Skip to content

Commit 74d3268

Browse files
committed
Polish contribution
This commit polishes an external contribution, ensuring that not just spaces are encoded as underscores, and that underscores are encoded as non-printable. See gh-30252
1 parent 5a4a46a commit 74d3268

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

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

+24-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.time.format.DateTimeParseException;
2424
import java.util.ArrayList;
2525
import java.util.Base64;
26+
import java.util.BitSet;
2627
import java.util.List;
2728
import java.util.regex.Matcher;
2829
import java.util.regex.Pattern;
@@ -58,6 +59,19 @@ public final class ContentDisposition {
5859
private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT =
5960
"Invalid header field parameter format (as defined in RFC 5987)";
6061

62+
private static final BitSet PRINTABLE = new BitSet(256);
63+
64+
65+
static {
66+
// RFC 2045, Section 6.7, and RFC 2047, Section 4.2
67+
for (int i=33; i<= 126; i++) {
68+
PRINTABLE.set(i);
69+
}
70+
PRINTABLE.set(61, false); // =
71+
PRINTABLE.set(63, false); // ?
72+
PRINTABLE.set(95, false); // _
73+
}
74+
6175

6276
@Nullable
6377
private final String type;
@@ -545,7 +559,7 @@ private static String decodeQuotedPrintableFilename(String filename, Charset cha
545559
int index = 0;
546560
while (index < value.length) {
547561
byte b = value[index];
548-
if (b == '_') {
562+
if (b == '_') { // RFC 2047, section 4.2, rule (2)
549563
baos.write(' ');
550564
index++;
551565
}
@@ -583,7 +597,10 @@ private static String encodeQuotedPrintableFilename(String filename, Charset cha
583597
sb.append(charset.name());
584598
sb.append("?Q?");
585599
for (byte b : source) {
586-
if (isPrintable(b)) {
600+
if (b == 32) { // RFC 2047, section 4.2, rule (2)
601+
sb.append('_');
602+
}
603+
else if (isPrintable(b)) {
587604
sb.append((char) b);
588605
}
589606
else {
@@ -599,7 +616,11 @@ private static String encodeQuotedPrintableFilename(String filename, Charset cha
599616
}
600617

601618
private static boolean isPrintable(byte c) {
602-
return (c >= '!' && c <= '<') || (c >= '@' && c <= '~') || c == '>';
619+
int b = c;
620+
if (b < 0) {
621+
b = 256 + b;
622+
}
623+
return PRINTABLE.get(b);
603624
}
604625

605626
private static String encodeQuotedPairs(String filename) {

Diff for: spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,12 @@ void parseFormattedWithQuestionMark() {
331331
ContentDisposition cd = ContentDisposition.attachment()
332332
.filename(filename, StandardCharsets.UTF_8)
333333
.build();
334-
String[] parts = cd.toString().split("; ");
334+
String result = cd.toString();
335+
assertThat(result).isEqualTo("attachment; " +
336+
"filename=\"=?UTF-8?Q?filename_with_=3F=E9=97=AE=E5=8F=B7.txt?=\"; " +
337+
"filename*=UTF-8''filename%20with%20%3F%E9%97%AE%E5%8F%B7.txt");
338+
339+
String[] parts = result.split("; ");
335340

336341
String quotedPrintableFilename = parts[0] + "; " + parts[1];
337342
assertThat(ContentDisposition.parse(quotedPrintableFilename).getFilename())
@@ -341,4 +346,5 @@ void parseFormattedWithQuestionMark() {
341346
assertThat(ContentDisposition.parse(rfc5987Filename).getFilename())
342347
.isEqualTo(filename);
343348
}
349+
344350
}

0 commit comments

Comments
 (0)