42
42
*/
43
43
public final class ContentDisposition {
44
44
45
+ private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT =
46
+ "Invalid header field parameter format (as defined in RFC 5987)" ;
47
+
45
48
@ Nullable
46
49
private final String type ;
47
50
@@ -205,7 +208,7 @@ public String toString() {
205
208
}
206
209
else {
207
210
sb .append ("; filename*=" );
208
- sb .append (encodeHeaderFieldParam (this .filename , this .charset ));
211
+ sb .append (encodeFilename (this .filename , this .charset ));
209
212
}
210
213
}
211
214
if (this .size != null ) {
@@ -271,15 +274,23 @@ public static ContentDisposition parse(String contentDisposition) {
271
274
String attribute = part .substring (0 , eqIndex );
272
275
String value = (part .startsWith ("\" " , eqIndex + 1 ) && part .endsWith ("\" " ) ?
273
276
part .substring (eqIndex + 2 , part .length () - 1 ) :
274
- part .substring (eqIndex + 1 , part . length () ));
277
+ part .substring (eqIndex + 1 ));
275
278
if (attribute .equals ("name" ) ) {
276
279
name = value ;
277
280
}
278
281
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
+ }
283
294
}
284
295
else if (attribute .equals ("filename" ) && (filename == null )) {
285
296
filename = value ;
@@ -357,24 +368,17 @@ else if (!escaped && ch == '"') {
357
368
}
358
369
359
370
/**
360
- * Decode the given header field param as describe in RFC 5987.
371
+ * Decode the given header field param as described in RFC 5987.
361
372
* <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
363
375
* @return the encoded header field param
364
376
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
365
377
*/
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 );
378
382
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
379
383
int index = 0 ;
380
384
while (index < value .length ) {
@@ -383,13 +387,18 @@ private static String decodeHeaderFieldParam(String input) {
383
387
bos .write ((char ) b );
384
388
index ++;
385
389
}
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
+ }
389
398
index +=3 ;
390
399
}
391
400
else {
392
- throw new IllegalArgumentException ("Invalid header field parameter format (as defined in RFC 5987)" );
401
+ throw new IllegalArgumentException (INVALID_HEADER_FIELD_PARAMETER_FORMAT );
393
402
}
394
403
}
395
404
return new String (bos .toByteArray (), charset );
@@ -409,7 +418,7 @@ private static boolean isRFC5987AttrChar(byte c) {
409
418
* @return the encoded header field param
410
419
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
411
420
*/
412
- private static String encodeHeaderFieldParam (String input , Charset charset ) {
421
+ private static String encodeFilename (String input , Charset charset ) {
413
422
Assert .notNull (input , "Input String should not be null" );
414
423
Assert .notNull (charset , "Charset should not be null" );
415
424
if (StandardCharsets .US_ASCII .equals (charset )) {
0 commit comments