This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 1.x in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git
commit 2c5e872b42e1a956b8e6eb8d962001c774eb225d Author: Merbin J Anselm <merbin.j.ans...@sap.com> AuthorDate: Tue Dec 10 12:00:25 2019 +0530 Detect asterisk only if is at end & added tests --- .../apache/commons/fileupload/ParameterParser.java | 9 ++--- .../fileupload/util/mime/RFC2231Utility.java | 28 +++++++++++++++ .../commons/fileupload/ParameterParserTest.java | 22 ++++++++++++ .../util/mime/RFC2231UtilityTestCase.java | 40 +++++++++++++++++++--- 4 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/apache/commons/fileupload/ParameterParser.java b/src/main/java/org/apache/commons/fileupload/ParameterParser.java index 1a0ca851..96ed2e87 100644 --- a/src/main/java/org/apache/commons/fileupload/ParameterParser.java +++ b/src/main/java/org/apache/commons/fileupload/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 (final 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/fileupload/util/mime/RFC2231Utility.java b/src/main/java/org/apache/commons/fileupload/util/mime/RFC2231Utility.java index f625494b..af77227d 100644 --- a/src/main/java/org/apache/commons/fileupload/util/mime/RFC2231Utility.java +++ b/src/main/java/org/apache/commons/fileupload/util/mime/RFC2231Utility.java @@ -43,6 +43,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 * diff --git a/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java b/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java index a97cac9b..efefdf0f 100644 --- a/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java +++ b/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java @@ -125,9 +125,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/fileupload/util/mime/RFC2231UtilityTestCase.java b/src/test/java/org/apache/commons/fileupload/util/mime/RFC2231UtilityTestCase.java index 6502be76..a9c09f52 100644 --- a/src/test/java/org/apache/commons/fileupload/util/mime/RFC2231UtilityTestCase.java +++ b/src/test/java/org/apache/commons/fileupload/util/mime/RFC2231UtilityTestCase.java @@ -18,7 +18,10 @@ package org.apache.commons.fileupload.util.mime; import java.io.UnsupportedEncodingException; -import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import org.junit.Test; /** @@ -28,6 +31,33 @@ import org.junit.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"); @@ -43,12 +73,12 @@ public final class RFC2231UtilityTestCase { assertEncoded("\u00A3 rate", "iso-8859-1'en'%A3%20rate"); //"£ rate" } - private static void assertEncoded(String expected, String encoded) throws Exception { - Assert.assertEquals(expected, RFC2231Utility.decodeText(encoded)); - } - @Test(expected = UnsupportedEncodingException.class) public void decodeInvalidEncoding() throws Exception { RFC2231Utility.decodeText("abc'en'hello"); } + + private static void assertEncoded(String expected, String encoded) throws Exception { + assertEquals(expected, RFC2231Utility.decodeText(encoded)); + } }