This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git
The following commit(s) were added to refs/heads/master by this push:
new e45f3831 Ignore invalid RFC 2231 extended value so it cannot erase a
valid filename (#479)
e45f3831 is described below
commit e45f38315cb0234fe10a63f8562d5ce2f9c0e7a9
Author: alhuda <[email protected]>
AuthorDate: Sat Jul 18 19:47:35 2026 +0530
Ignore invalid RFC 2231 extended value so it cannot erase a valid filename
(#479)
---
.../commons/fileupload2/core/ParameterParser.java | 7 +++---
.../fileupload2/core/ParameterParserTest.java | 28 ++++++++++++++++++++++
2 files changed, 32 insertions(+), 3 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 419c4689..59e54893 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
@@ -169,6 +169,7 @@ public class ParameterParser {
while (hasChar()) {
paramName = parseToken(new char[] { '=', separator });
paramValue = null;
+ var invalid = false;
if (hasChar() && charArray[pos] == '=') {
pos++; // skip '='
paramValue = parseQuotedToken(new char[] { separator });
@@ -177,8 +178,8 @@ public class ParameterParser {
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;
+ // Treat invalid values as if they were not provided,
so a malformed filename* cannot override a valid filename.
+ invalid = true;
} catch (final UnsupportedEncodingException ignored) {
// let's keep the original value in this case
}
@@ -187,7 +188,7 @@ public class ParameterParser {
if (hasChar() && charArray[pos] == separator) {
pos++; // skip separator
}
- if (paramName != null && !paramName.isEmpty()) {
+ if (!invalid && paramName != null && !paramName.isEmpty()) {
paramName = RFC2231Utils.stripDelimiter(paramName);
if (this.lowerCaseNames) {
paramName = paramName.toLowerCase(Locale.ROOT);
diff --git
a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/ParameterParserTest.java
b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/ParameterParserTest.java
index df3d6c1a..123a10a1 100644
---
a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/ParameterParserTest.java
+++
b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/ParameterParserTest.java
@@ -99,6 +99,34 @@ class ParameterParserTest {
assertEquals("a'b'c", params.get("filename"));
}
+ /**
+ * An invalid RFC 2231 / RFC 5987 extended value must be ignored rather
than overwrite a valid plain value for the same parameter.
+ */
+ @Test
+ void testInvalidExtendedValueIgnored() {
+ final var parser = new ParameterParser();
+
+ // A truncated %nn escape in filename* must not erase the valid
filename.
+ var s = "Content-Disposition: form-data; name=\"file\";
filename=\"safe.txt\"; filename*=UTF-8''bad%2\r\n";
+ var params = parser.parse(s, new char[] { ',', ';' });
+ assertEquals("safe.txt", params.get("filename"));
+
+ // Order independent: an invalid filename* before the valid filename
is also ignored.
+ s = "Content-Disposition: form-data; name=\"file\";
filename*=UTF-8''bad%2; filename=\"safe.txt\"\r\n";
+ params = parser.parse(s, new char[] { ',', ';' });
+ assertEquals("safe.txt", params.get("filename"));
+
+ // An invalid filename* on its own is not reported as a (null) value.
+ s = "Content-Disposition: form-data; name=\"file\";
filename*=UTF-8''bad%2\r\n";
+ params = parser.parse(s, new char[] { ',', ';' });
+ assertNull(params.get("filename"));
+
+ // A valid filename* still decodes normally.
+ s = "Content-Disposition: form-data; name=\"file\";
filename=\"safe.txt\"; filename*=UTF-8''real.exe\r\n";
+ params = parser.parse(s, new char[] { ',', ';' });
+ assertEquals("real.exe", params.get("filename"));
+ }
+
@Test
void testParsing() {
var s = "test; test1 = stuff ; test2 = \"stuff; stuff\";
test3=\"stuff";