Skip to content

Commit 32a585d

Browse files
committed
Merge pull request #23485
2 parents 670cbb9 + d927d31 commit 32a585d

File tree

2 files changed

+155
-136
lines changed

2 files changed

+155
-136
lines changed

spring-web/src/main/java/org/springframework/http/ContentDisposition.java

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
*/
4343
public final class ContentDisposition {
4444

45+
private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT =
46+
"Invalid header field parameter format (as defined in RFC 5987)";
47+
4548
@Nullable
4649
private final String type;
4750

@@ -205,7 +208,7 @@ public String toString() {
205208
}
206209
else {
207210
sb.append("; filename*=");
208-
sb.append(encodeHeaderFieldParam(this.filename, this.charset));
211+
sb.append(encodeFilename(this.filename, this.charset));
209212
}
210213
}
211214
if (this.size != null) {
@@ -271,15 +274,23 @@ public static ContentDisposition parse(String contentDisposition) {
271274
String attribute = part.substring(0, eqIndex);
272275
String value = (part.startsWith("\"", eqIndex + 1) && part.endsWith("\"") ?
273276
part.substring(eqIndex + 2, part.length() - 1) :
274-
part.substring(eqIndex + 1, part.length()));
277+
part.substring(eqIndex + 1));
275278
if (attribute.equals("name") ) {
276279
name = value;
277280
}
278281
else if (attribute.equals("filename*") ) {
279-
filename = decodeHeaderFieldParam(value);
280-
charset = Charset.forName(value.substring(0, value.indexOf('\'')));
281-
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset),
282-
"Charset should be UTF-8 or ISO-8859-1");
282+
int idx1 = value.indexOf('\'');
283+
int idx2 = value.indexOf('\'', idx1 + 1);
284+
if (idx1 != -1 && idx2 != -1) {
285+
charset = Charset.forName(value.substring(0, idx1));
286+
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset),
287+
"Charset should be UTF-8 or ISO-8859-1");
288+
filename = decodeFilename(value.substring(idx2 + 1), charset);
289+
}
290+
else {
291+
// US ASCII
292+
filename = decodeFilename(value, StandardCharsets.US_ASCII);
293+
}
283294
}
284295
else if (attribute.equals("filename") && (filename == null)) {
285296
filename = value;
@@ -357,24 +368,17 @@ else if (!escaped && ch == '"') {
357368
}
358369

359370
/**
360-
* Decode the given header field param as describe in RFC 5987.
371+
* Decode the given header field param as described in RFC 5987.
361372
* <p>Only the US-ASCII, UTF-8 and ISO-8859-1 charsets are supported.
362-
* @param input the header field param
373+
* @param filename the filename
374+
* @param charset the charset for the filename
363375
* @return the encoded header field param
364376
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
365377
*/
366-
private static String decodeHeaderFieldParam(String input) {
367-
Assert.notNull(input, "Input String should not be null");
368-
int firstQuoteIndex = input.indexOf('\'');
369-
int secondQuoteIndex = input.indexOf('\'', firstQuoteIndex + 1);
370-
// US_ASCII
371-
if (firstQuoteIndex == -1 || secondQuoteIndex == -1) {
372-
return input;
373-
}
374-
Charset charset = Charset.forName(input.substring(0, firstQuoteIndex));
375-
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset),
376-
"Charset should be UTF-8 or ISO-8859-1");
377-
byte[] value = input.substring(secondQuoteIndex + 1, input.length()).getBytes(charset);
378+
private static String decodeFilename(String filename, Charset charset) {
379+
Assert.notNull(filename, "'input' String` should not be null");
380+
Assert.notNull(charset, "'charset' should not be null");
381+
byte[] value = filename.getBytes(charset);
378382
ByteArrayOutputStream bos = new ByteArrayOutputStream();
379383
int index = 0;
380384
while (index < value.length) {
@@ -383,13 +387,18 @@ private static String decodeHeaderFieldParam(String input) {
383387
bos.write((char) b);
384388
index++;
385389
}
386-
else if (b == '%') {
387-
char[] array = { (char)value[index + 1], (char)value[index + 2]};
388-
bos.write(Integer.parseInt(String.valueOf(array), 16));
390+
else if (b == '%' && index < value.length - 2) {
391+
char[] array = new char[]{(char) value[index + 1], (char) value[index + 2]};
392+
try {
393+
bos.write(Integer.parseInt(String.valueOf(array), 16));
394+
}
395+
catch (NumberFormatException ex) {
396+
throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT, ex);
397+
}
389398
index+=3;
390399
}
391400
else {
392-
throw new IllegalArgumentException("Invalid header field parameter format (as defined in RFC 5987)");
401+
throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT);
393402
}
394403
}
395404
return new String(bos.toByteArray(), charset);
@@ -409,7 +418,7 @@ private static boolean isRFC5987AttrChar(byte c) {
409418
* @return the encoded header field param
410419
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
411420
*/
412-
private static String encodeHeaderFieldParam(String input, Charset charset) {
421+
private static String encodeFilename(String input, Charset charset) {
413422
Assert.notNull(input, "Input String should not be null");
414423
Assert.notNull(charset, "Charset should not be null");
415424
if (StandardCharsets.US_ASCII.equals(charset)) {

0 commit comments

Comments
 (0)