This is an automated email from the ASF dual-hosted git repository. markt-asf pushed a commit to branch stricter-rfc2231 in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git
commit e3506cade2c1eed0f3f63f42a575ea166fedd75b Author: Mark Thomas <[email protected]> AuthorDate: Mon May 11 14:25:16 2026 +0100 Implement stricter checks for fields using RFC 2231 / RFC 5987 Values where invalid characters appear in the extended value will now be ignored. --- .../commons/fileupload2/core/ParameterParser.java | 3 ++ .../commons/fileupload2/core/RFC2231Utils.java | 32 ++++++++++++++++++++-- .../fileupload2/core/RFC2231UtilityTestCase.java | 13 +++++++++ src/changes/changes.xml | 1 + 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java index 513b9376..0daf413a 100644 --- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java +++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/ParameterParser.java @@ -176,6 +176,9 @@ public class ParameterParser { if (paramValue != null) { try { paramValue = RFC2231Utils.hasEncodedValue(paramName) ? RFC2231Utils.decodeText(paramValue) : MimeUtils.decodeText(paramValue); + } catch (final IllegalArgumentException iae) { + // Treat invalid values as if they were not provided + paramValue = null; } catch (final UnsupportedEncodingException ignored) { // let's keep the original value in this case } diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java index 11c8c749..d3bc9625 100644 --- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java +++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/RFC2231Utils.java @@ -52,14 +52,38 @@ final class RFC2231Utils { */ private static final byte[] HEX_DECODE = new byte[MASK_128]; + private static final boolean[] ATTR_CHAR = new boolean[128]; + // create a ASCII decoded array of Hexadecimal values static { for (var i = 0; i < HEX_DIGITS.length; i++) { HEX_DECODE[HEX_DIGITS[i]] = (byte) i; HEX_DECODE[Character.toLowerCase(HEX_DIGITS[i])] = (byte) i; } + + for (var i = 0; i < 128; i++) { + if (i < 32 || i == ' ' || i == '\"' || i == '%' || i == '\'' || i == '(' || i == ')' || i == '*' || + i == ',' || i == '/' || i == ':' || i == ';' || i == '<' || i == '=' || i == '>' || i == '?' || + i == '@' || i == '[' || i == '\\' || i == ']' || i == '{' || i == '}' || i == 127) { + // Not valid attr-char + ATTR_CHAR[i] = false; + } else { + ATTR_CHAR[i] = true; + } + } } + + static boolean isAttrChar(char c) { + // Fast for valid values. Slow for some invalid ones. + try { + return ATTR_CHAR[c]; + } catch (ArrayIndexOutOfBoundsException e) { + return false; + } + } + + /** * Decodes a string of text obtained from a HTTP header as per RFC 2231 * @@ -71,9 +95,10 @@ final class RFC2231Utils { * * @param encodedText Text to be decoded has a format of {@code <charset>'<language>'<encoded_value>} and ASCII only * @return Decoded text based on charset encoding + * @throws IllegalArgumentException The encoded text contained characters not permitted by RFC 2231 * @throws UnsupportedEncodingException The requested character set wasn't found. */ - static String decodeText(final String encodedText) throws UnsupportedEncodingException { + static String decodeText(final String encodedText) throws IllegalArgumentException, UnsupportedEncodingException { final var langDelimitStart = encodedText.indexOf('\''); if (langDelimitStart == -1) { // missing charset @@ -89,6 +114,7 @@ final class RFC2231Utils { return new String(bytes, getJavaCharset(mimeCharset)); } + /** * Converts {@code text} to their corresponding Hex value. * @@ -107,8 +133,10 @@ final class RFC2231Utils { final var b1 = HEX_DECODE[text.charAt(i++) & MASK]; final var b2 = HEX_DECODE[text.charAt(i++) & MASK]; out.write(b1 << shift | b2); - } else { + } else if (isAttrChar(c)) { out.write((byte) c); + } else { + throw new IllegalArgumentException(); } } return out.toByteArray(); diff --git a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java index a2ec817d..e937bd28 100644 --- a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java +++ b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/RFC2231UtilityTestCase.java @@ -82,4 +82,17 @@ public final class RFC2231UtilityTestCase { final var nameWithoutAsterisk = "paramname"; assertEquals("paramname", RFC2231Utils.stripDelimiter(nameWithoutAsterisk)); } + + + @Test + void testDecodeNonTokenChracters() throws Exception { + assertThrows(IllegalArgumentException.class, () -> RFC2231Utils.decodeText("ISO-8859-1''Not*allowed")); + } + + + @Test + void testDecodeUTF8Chracters() throws Exception { + assertThrows(IllegalArgumentException.class, () -> RFC2231Utils.decodeText("UTF-8''\\u8a2e")); + } + } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 68947466..5856784f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -45,6 +45,7 @@ The <action> type attribute can be add,update,fix,remove. <!-- FIX --> <action type="fix" dev="ggregory" due-to="Henri Biestro, Gary Gregory">Fix migration documentation to mention Java 11.</action> <action issue="FILEUPLOAD-362" type="fix" dev="ggregory" due-to="Kusal Kithul-Godage, Gary Gregory">Unable to parse requests for file uploads with special characters in filename on Windows.</action> + <action type="fix" dev="markt" due-to="Mark Thomas">Implement stricter checks for fields using RFC 2231 / RFC 5987 and ignore values where invalid characters appear in the extended value.</action> <!-- ADD --> <!-- UPDATE --> <action type="update" dev="ggregory" due-to="Gary Gregory">Bump org.apache.commons:commons-parent from 96 to 99.</action>
