You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by jo...@apache.org on 2020/05/25 19:29:00 UTC

[commons-fileupload] 02/04: Detect asterisk only if is at end & added tests

This is an automated email from the ASF dual-hosted git repository.

jochen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git

commit 1a8a103eefa5616503e9947804c6a20b12669e42
Author: Merbin J Anselm <me...@sap.com>
AuthorDate: Tue Dec 10 12:00:25 2019 +0530

    Detect asterisk only if is at end & added tests
---
 .../commons/fileupload2/ParameterParser.java       |  9 ++----
 .../fileupload2/util/mime/RFC2231Utility.java      | 28 ++++++++++++++++
 .../commons/fileupload2/ParameterParserTest.java   | 22 +++++++++++++
 .../util/mime/RFC2231UtilityTestCase.java          | 37 +++++++++++++++++++---
 4 files changed, 85 insertions(+), 11 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/ParameterParser.java b/src/main/java/org/apache/commons/fileupload2/ParameterParser.java
index 2735259..ef24a89 100644
--- a/src/main/java/org/apache/commons/fileupload2/ParameterParser.java
+++ b/src/main/java/org/apache/commons/fileupload2/ParameterParser.java
@@ -306,12 +306,10 @@ public class ParameterParser {
 
         String paramName = null;
         String paramValue = null;
-        boolean hasExtendedParams = false;
         while (hasChar()) {
             paramName = parseToken(new char[] {
                     '=', separator });
             paramValue = null;
-            hasExtendedParams = (paramName != null) ? paramName.contains("*") : false; //TODO: Check only if delimiter is at end
             if (hasChar() && (charArray[pos] == '=')) {
                 pos++; // skip '='
                 paramValue = parseQuotedToken(new char[] {
@@ -319,7 +317,7 @@ public class ParameterParser {
 
                 if (paramValue != null) {
                     try {
-                        paramValue = hasExtendedParams ? RFC2231Utility.decodeText(paramValue)
+                        paramValue = RFC2231Utility.hasEncodedValue(paramName) ? RFC2231Utility.decodeText(paramValue)
                                 : MimeUtility.decodeText(paramValue);
                     } catch (UnsupportedEncodingException e) {
                         // let's keep the original value in this case
@@ -330,13 +328,10 @@ public class ParameterParser {
                 pos++; // skip separator
             }
             if ((paramName != null) && (paramName.length() > 0)) {
-                if (hasExtendedParams) {
-                    paramName = paramName.replace("*", ""); //strip of the * from the name //TODO: Replace the last character alone
-                }
+                paramName = RFC2231Utility.stripDelimiter(paramName);
                 if (this.lowerCaseNames) {
                     paramName = paramName.toLowerCase(Locale.ENGLISH);
                 }
-
                 params.put(paramName, paramValue);
             }
         }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java b/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java
index 37dce05..955d185 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java
@@ -44,6 +44,34 @@ public final class RFC2231Utility {
     }
 
     /**
+     * Checks if Asterisk (*) at the end of parameter name to indicate,
+     * if it has charset and language information to decode the value
+     * @param paramName
+     * @return {@code true}, if encoded as per RFC 2231, {@code false} otherwise
+     */
+    public static boolean hasEncodedValue(String paramName) {
+        if (paramName != null) {
+            return paramName.lastIndexOf("*") == (paramName.length() - 1);
+        }
+        return false;
+    }
+
+    /**
+     * If {@code paramName} has Asterisk (*) at the end, it will be stripped off, 
+     * else the passed value will be returned
+     * @param paramName
+     * @return stripped {@code paramName} of Asterisk (*), if RFC2231 encoded
+     */
+    public static String stripDelimiter(String paramName) {
+        if (hasEncodedValue(paramName)) {
+            StringBuilder paramBuilder = new StringBuilder(paramName);
+            paramBuilder.deleteCharAt(paramName.lastIndexOf("*"));
+            return paramBuilder.toString();
+        }
+        return paramName;
+    }
+
+    /**
      * Decode a string of text obtained from a HTTP header as per RFC 2231
      * 
      * <p/>
diff --git a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
index 96988b3..70838f3 100644
--- a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
@@ -126,9 +126,31 @@ public class ParameterParserTest {
     @Test
     public void testFileUpload274() {
         ParameterParser parser = new ParameterParser();
+
+        // Should parse a UTF-8 charset
         String s = "Content-Disposition: form-data; name=\"file\"; filename*=UTF-8\'\'%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF\r\n";
         Map<String, String> params = parser.parse(s, new char[] { ',', ';' });
         assertEquals("\u3053\u3093\u306B\u3061\u306F", params.get("filename")); //filename = "こんにちは" in japanese
+
+        // Should parse ISO-8859-1 charset
+        s = "Content-Disposition: form-data; name=\"file\"; filename*=UTF-8\'\'%70%C3%A2%74%C3%A9\r\n";
+        params = parser.parse(s, new char[] { ',', ';' });
+        assertEquals("\u0070\u00e2\u0074\u00e9", params.get("filename")); //filename = "pâté" in french
+
+        // Should not decode if '*' is not at the end of param-name
+        s = "Content-Disposition: form-data; name=\"file\"; file*name=UTF-8\'\'%61%62%63\r\n";
+        params = parser.parse(s, new char[] { ',', ';' });
+        assertEquals("UTF-8\'\'%61%62%63", params.get("file*name"));
+
+        // Should not decode if param-value does not follow <charset>'<lang>'<encoded>
+        s = "Content-Disposition: form-data; name=\"file\"; filename*=a\'bc\r\n";
+        params = parser.parse(s, new char[] { ',', ';' });
+        assertEquals("a\'bc", params.get("filename"));
+
+        // Should not decode if param-name doesn't have '*' at end
+        s = "Content-Disposition: form-data; name=\"file\"; filename=a\'b\'c\r\n";
+        params = parser.parse(s, new char[] { ',', ';' });
+        assertEquals("a\'b\'c", params.get("filename"));
     }
 
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java
index 9100728..315713c 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java
@@ -17,7 +17,9 @@
 package org.apache.commons.fileupload2.util.mime;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.UnsupportedEncodingException;
 
@@ -31,6 +33,33 @@ import org.junit.jupiter.api.Test;
 public final class RFC2231UtilityTestCase {
 
     @Test
+    public void testHasEncodedValue() {
+        String nameWithAsteriskAtEnd = "paramname*";
+        assertTrue(RFC2231Utility.hasEncodedValue(nameWithAsteriskAtEnd));
+
+        String nameWithAsteriskNotAtEnd = "param*name";
+        assertFalse(RFC2231Utility.hasEncodedValue(nameWithAsteriskNotAtEnd));
+
+        String nameWithoutAsterisk = "paramname";
+        assertFalse(RFC2231Utility.hasEncodedValue(nameWithoutAsterisk));
+    }
+
+    @Test
+    public void testStripDelimiter() {
+        String nameWithAsteriskAtEnd = "paramname*";
+        assertEquals("paramname", RFC2231Utility.stripDelimiter(nameWithAsteriskAtEnd));
+
+        String nameWithAsteriskNotAtEnd = "param*name";
+        assertEquals("param*name", RFC2231Utility.stripDelimiter(nameWithAsteriskNotAtEnd));
+
+        String nameWithTwoAsterisks = "param*name*";
+        assertEquals("param*name", RFC2231Utility.stripDelimiter(nameWithTwoAsterisks));
+
+        String nameWithoutAsterisk = "paramname";
+        assertEquals("paramname", RFC2231Utility.stripDelimiter(nameWithoutAsterisk));
+    }
+
+    @Test
     public void noNeedToDecode() throws Exception {
         assertEncoded("abc", "abc");
     }
@@ -45,14 +74,14 @@ public final class RFC2231UtilityTestCase {
         assertEncoded("\u00A3 rate", "iso-8859-1'en'%A3%20rate"); //"£ rate"
     }
 
-    private static void assertEncoded(String expected, String encoded) throws Exception {
-        assertEquals(expected, RFC2231Utility.decodeText(encoded));
-    }
-
     @Test
     public void decodeInvalidEncoding() throws Exception {
         assertThrows(UnsupportedEncodingException.class, () -> {
             RFC2231Utility.decodeText("abc'en'hello");
         });
     }
+
+    private static void assertEncoded(String expected, String encoded) throws Exception {
+        assertEquals(expected, RFC2231Utility.decodeText(encoded));
+    }
 }