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 03aee012273..d3605a570e8 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java @@ -21,7 +21,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; -import java.util.BitSet; import java.util.HexFormat; import java.util.List; import java.util.Locale; @@ -59,23 +58,9 @@ public final class ContentDisposition { private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT = "Invalid header field parameter format (as defined in RFC 5987)"; - private static final BitSet PRINTABLE = new BitSet(256); - private static final HexFormat HEX_FORMAT = HexFormat.of().withUpperCase(); - static { - // RFC 2045, Section 6.7, and RFC 2047, Section 4.2 - for (int i=33; i<= 126; i++) { - PRINTABLE.set(i); - } - PRINTABLE.set(34, false); // " - PRINTABLE.set(61, false); // = - PRINTABLE.set(63, false); // ? - PRINTABLE.set(95, false); // _ - } - - private final @Nullable String type; private final @Nullable String name; @@ -195,7 +180,7 @@ public String toString() { } else { sb.append("; filename=\""); - sb.append(encodeQuotedPrintableFilename(this.filename, this.charset)).append('\"'); + sb.append(toIso88591(encodeQuotedPairs(this.filename))).append('\"'); sb.append("; filename*="); sb.append(encodeRfc5987Filename(this.filename, this.charset)); } @@ -446,44 +431,8 @@ else if (b == '=' && index < value.length - 2) { return StreamUtils.copyToString(baos, charset); } - /** - * Encode the given header field param as described in RFC 2047. - * @param filename the filename - * @param charset the charset for the filename - * @return the encoded header field param - * @see RFC 2047 - */ - private static String encodeQuotedPrintableFilename(String filename, Charset charset) { - Assert.notNull(filename, "'filename' must not be null"); - Assert.notNull(charset, "'charset' must not be null"); - - byte[] source = filename.getBytes(charset); - StringBuilder sb = new StringBuilder(source.length << 1); - sb.append("=?"); - sb.append(charset.name()); - sb.append("?Q?"); - for (byte b : source) { - if (b == 32) { // RFC 2047, section 4.2, rule (2) - sb.append('_'); - } - else if (isPrintable(b)) { - sb.append((char) b); - } - else { - sb.append('='); - HEX_FORMAT.toHexDigits(sb, b); - } - } - sb.append("?="); - return sb.toString(); - } - - private static boolean isPrintable(byte c) { - int b = c; - if (b < 0) { - b = 256 + b; - } - return PRINTABLE.get(b); + private static String toIso88591(String input) { + return new String(input.getBytes(StandardCharsets.ISO_8859_1)); } private static String encodeQuotedPairs(String filename) { 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 87666b74961..9ce8f87c1da 100644 --- a/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java +++ b/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java @@ -221,7 +221,7 @@ void formatWithEncodedFilename() { .filename("中文.txt", StandardCharsets.UTF_8) .build().toString()) .isEqualTo("form-data; name=\"name\"; " + - "filename=\"=?UTF-8?Q?=E4=B8=AD=E6=96=87.txt?=\"; " + + "filename=\"??.txt\"; " + "filename*=UTF-8''%E4%B8%AD%E6%96%87.txt"); } @@ -272,7 +272,7 @@ void formatWithFilenameWithQuotes() { void formatWithUtf8FilenameWithQuotes() { String filename = "\"中文.txt"; assertThat(ContentDisposition.formData().filename(filename, StandardCharsets.UTF_8).build().toString()) - .isEqualTo("form-data; filename=\"=?UTF-8?Q?=22=E4=B8=AD=E6=96=87.txt?=\"; filename*=UTF-8''%22%E4%B8%AD%E6%96%87.txt"); + .isEqualTo("form-data; filename=\"\\\"??.txt\"; filename*=UTF-8''%22%E4%B8%AD%E6%96%87.txt"); } @Test @@ -303,14 +303,14 @@ void parseFormattedWithQuestionMark() { .build(); String result = cd.toString(); assertThat(result).isEqualTo("attachment; " + - "filename=\"=?UTF-8?Q?filename_with_=3F=E9=97=AE=E5=8F=B7.txt?=\"; " + + "filename=\"filename with ???.txt\"; " + "filename*=UTF-8''filename%20with%20%3F%E9%97%AE%E5%8F%B7.txt"); String[] parts = result.split("; "); String quotedPrintableFilename = parts[0] + "; " + parts[1]; assertThat(ContentDisposition.parse(quotedPrintableFilename).getFilename()) - .isEqualTo(filename); + .isEqualTo("filename with ???.txt"); String rfc5987Filename = parts[0] + "; " + parts[2]; assertThat(ContentDisposition.parse(rfc5987Filename).getFilename())