This is an automated email from the ASF dual-hosted git repository. garydgregory pushed a commit to branch 1.x in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git
commit f3496034643e6cad1aaa4012e91d08c4ef7b43d1 Author: Gary Gregory <[email protected]> AuthorDate: Sat Jun 20 21:27:06 2026 +0000 RFC2231Utils decodeText - Incorrect handling of percent encoded text (#472). --- src/changes/changes.xml | 3 +- .../apache/commons/fileupload/RFC2231Utility.java | 19 ++++++---- .../commons/fileupload/RFC2231UtilityTestCase.java | 41 ++++++++++++---------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cb668793..11a30d1f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -50,7 +50,8 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" dev="ggregory" due-to="Gary Gregory">If DiskFileItem.delete() can't delete the file, it marks it for deletion on JVM exit.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">DiskFileItem.delete() and finalize() always ties to delete its backing file.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Javadoc that you shouldn't rely on the garbage collection to cause the JVM to call FileItem.delete() through finalization; see JEP 421: Deprecate Finalization for Removal.</action> - <action type="fix" dev="markt" due-to="Mark Thomas">Implement stricter checks for fields using RFC 2231 / RFC 5987. Invalid extended values will be ignored.</action> + <action type="fix" dev="markt" due-to="Mark Thomas">Implement stricter checks for fields using RFC 2231 / RFC 5987. Invalid extended values will be ignored.</action> + <action type="fix" dev="ggregory" due-to="Chenjp, Gary Gregory">RFC2231Utils decodeText - Incorrect handling of percent encoded text (#472).</action> <!-- ADD --> <!-- UPDATE --> <action type="update" dev="ggregory" due-to="Gary Gregory">Bump org.apache.commons:commons-parent from 84 to 102.</action> diff --git a/src/main/java/org/apache/commons/fileupload/RFC2231Utility.java b/src/main/java/org/apache/commons/fileupload/RFC2231Utility.java index dbe35323..10e7a095 100644 --- a/src/main/java/org/apache/commons/fileupload/RFC2231Utility.java +++ b/src/main/java/org/apache/commons/fileupload/RFC2231Utility.java @@ -92,11 +92,6 @@ final class RFC2231Utility { } - static boolean isAttrChar(final char c) { - return c < ASCII_CODE_POINT_COUNT && ATTR_CHAR[c]; - } - - /** * Decodes a string of text obtained from a HTTP header as per RFC 2231 * <p> @@ -146,8 +141,13 @@ final class RFC2231Utility { if (i > text.length() - 2) { break; // unterminated sequence } - final byte b1 = HEX_DECODE[text.charAt(i++) & MASK]; - final byte b2 = HEX_DECODE[text.charAt(i++) & MASK]; + final char c1 = text.charAt(i++); + final char c2 = text.charAt(i++); + if (c1 >= ASCII_CODE_POINT_COUNT || c2 >= ASCII_CODE_POINT_COUNT) { + throw new IllegalArgumentException(); + } + final byte b1 = HEX_DECODE[c1 & MASK]; + final byte b2 = HEX_DECODE[c2 & MASK]; if (b1 < 0 || b2 < 0) { throw new IllegalArgumentException(); } @@ -161,6 +161,7 @@ final class RFC2231Utility { return out.toByteArray(); } + private static String getJavaCharset(final String mimeCharset) { // good enough for standard values return mimeCharset; @@ -179,6 +180,10 @@ final class RFC2231Utility { return false; } + static boolean isAttrChar(final char c) { + return c < ASCII_CODE_POINT_COUNT && ATTR_CHAR[c]; + } + /** * If {@code paramName} has Asterisk (*) at the end, it will be stripped off, else the passed value will be returned. * diff --git a/src/test/java/org/apache/commons/fileupload/RFC2231UtilityTestCase.java b/src/test/java/org/apache/commons/fileupload/RFC2231UtilityTestCase.java index 9fbd73c4..7733dd85 100644 --- a/src/test/java/org/apache/commons/fileupload/RFC2231UtilityTestCase.java +++ b/src/test/java/org/apache/commons/fileupload/RFC2231UtilityTestCase.java @@ -58,6 +58,29 @@ public final class RFC2231UtilityTestCase { assertEncoded("abc", "abc"); } + @Test + void testDecodeInvalidHex() throws Exception { + assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("ISO-8859-1''hello%HHworld")); + } + + @Test + void testDecodeInvalidPercentEncoded() throws Exception { + assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("ISO-8859-1''hello%3\u8a35")); + } + + + @Test + void testDecodeNonTokenCharacters() throws Exception { + assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("ISO-8859-1''Not*allowed")); + } + + + @Test + void testDecodeUTF8Characters() throws Exception { + assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("UTF-8''\\u8a2e")); + } + + @Test public void testHasEncodedValue() { final String nameWithAsteriskAtEnd = "paramname*"; @@ -84,22 +107,4 @@ public final class RFC2231UtilityTestCase { final String nameWithoutAsterisk = "paramname"; assertEquals("paramname", RFC2231Utility.stripDelimiter(nameWithoutAsterisk)); } - - - @Test - void testDecodeNonTokenCharacters() throws Exception { - assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("ISO-8859-1''Not*allowed")); - } - - - @Test - void testDecodeUTF8Characters() throws Exception { - assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("UTF-8''\\u8a2e")); - } - - - @Test - void testDecodeInvalidHex() throws Exception { - assertThrows(IllegalArgumentException.class, () -> RFC2231Utility.decodeText("ISO-8859-1''hello%HHworld")); - } }
