diff --git a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java index 115aea08d5aa..0a245314b06f 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java @@ -42,6 +42,9 @@ */ public final class ContentDisposition { + private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT = + "Invalid header field parameter format (as defined in RFC 5987)"; + @Nullable private final String type; @@ -357,7 +360,7 @@ else if (!escaped && ch == '"') { } /** - * Decode the given header field param as describe in RFC 5987. + * Decode the given header field param as described in RFC 5987. *
Only the US-ASCII, UTF-8 and ISO-8859-1 charsets are supported. * @param input the header field param * @return the encoded header field param @@ -383,13 +386,18 @@ private static String decodeHeaderFieldParam(String input) { bos.write((char) b); index++; } - else if (b == '%') { - char[] array = { (char)value[index + 1], (char)value[index + 2]}; - bos.write(Integer.parseInt(String.valueOf(array), 16)); + else if (b == '%' && index < value.length - 2) { + char[] array = new char[]{(char) value[index + 1], (char) value[index + 2]}; + try { + bos.write(Integer.parseInt(String.valueOf(array), 16)); + } + catch (NumberFormatException ex) { + throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT, ex); + } index+=3; } else { - throw new IllegalArgumentException("Invalid header field parameter format (as defined in RFC 5987)"); + throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT); } } return new String(bos.toByteArray(), charset); diff --git a/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java b/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java index 4654aeb1189b..a8f000eba854 100644 --- a/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java +++ b/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java @@ -36,7 +36,6 @@ */ public class ContentDispositionTests { - @Test public void parseTest() { ContentDisposition disposition = ContentDisposition @@ -198,4 +197,22 @@ public void decodeHeaderFieldParamInvalidCharset() { ReflectionUtils.invokeMethod(decode, null, "UTF-16''test")); } + @Test + public void decodeHeaderFieldParamShortInvalidEncodedFilename() { + Method decode = ReflectionUtils.findMethod(ContentDisposition.class, + "decodeHeaderFieldParam", String.class); + ReflectionUtils.makeAccessible(decode); + assertThatIllegalArgumentException().isThrownBy(() -> + ReflectionUtils.invokeMethod(decode, null, "UTF-8''%A")); + } + + @Test + public void decodeHeaderFieldParamLongerInvalidEncodedFilename() { + Method decode = ReflectionUtils.findMethod(ContentDisposition.class, + "decodeHeaderFieldParam", String.class); + ReflectionUtils.makeAccessible(decode); + assertThatIllegalArgumentException().isThrownBy(() -> + ReflectionUtils.invokeMethod(decode, null, "UTF-8''%A.txt")); + } + }