Skip to content

Commit 956ffe6

Browse files
committed
ContentDisposition refactoring
See gh-24220
1 parent 3cf806a commit 956ffe6

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

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

+24-22
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public String toString() {
222222
if (this.filename != null) {
223223
if (this.charset == null || StandardCharsets.US_ASCII.equals(this.charset)) {
224224
sb.append("; filename=\"");
225-
sb.append(this.filename).append('\"');
225+
sb.append(escapeQuotationsInFilename(this.filename)).append('\"');
226226
}
227227
else {
228228
sb.append("; filename*=");
@@ -428,6 +428,23 @@ private static boolean isRFC5987AttrChar(byte c) {
428428
c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~';
429429
}
430430

431+
private static String escapeQuotationsInFilename(String filename) {
432+
if (filename.indexOf('"') == -1 && filename.indexOf('\\') == -1) {
433+
return filename;
434+
}
435+
boolean escaped = false;
436+
StringBuilder sb = new StringBuilder();
437+
for (char c : filename.toCharArray()) {
438+
sb.append((c == '"' && !escaped) ? "\\\"" : c);
439+
escaped = (!escaped && c == '\\');
440+
}
441+
// Remove backslash at the end..
442+
if (escaped) {
443+
sb.deleteCharAt(sb.length() - 1);
444+
}
445+
return sb.toString();
446+
}
447+
431448
/**
432449
* Encode the given header field param as describe in RFC 5987.
433450
* @param input the header field param
@@ -437,13 +454,10 @@ private static boolean isRFC5987AttrChar(byte c) {
437454
* @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a>
438455
*/
439456
private static String encodeFilename(String input, Charset charset) {
440-
Assert.notNull(input, "Input String should not be null");
441-
Assert.notNull(charset, "Charset should not be null");
442-
if (StandardCharsets.US_ASCII.equals(charset)) {
443-
return input;
444-
}
445-
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset),
446-
"Charset should be UTF-8 or ISO-8859-1");
457+
Assert.notNull(input, "`input` is required");
458+
Assert.notNull(charset, "`charset` is required");
459+
Assert.isTrue(!StandardCharsets.US_ASCII.equals(charset), "ASCII does not require encoding");
460+
Assert.isTrue(UTF_8.equals(charset) || ISO_8859_1.equals(charset), "Only UTF-8 and ISO-8859-1 supported.");
447461
byte[] source = input.getBytes(charset);
448462
int len = source.length;
449463
StringBuilder sb = new StringBuilder(len << 1);
@@ -578,25 +592,13 @@ public Builder name(String name) {
578592
@Override
579593
public Builder filename(String filename) {
580594
Assert.hasText(filename, "No filename");
581-
this.filename = escapeQuotationMarks(filename);
595+
this.filename = filename;
582596
return this;
583597
}
584598

585-
private static String escapeQuotationMarks(String filename) {
586-
if (filename.indexOf('"') == -1) {
587-
return filename;
588-
}
589-
boolean escaped = false;
590-
StringBuilder sb = new StringBuilder();
591-
for (char c : filename.toCharArray()) {
592-
sb.append((c == '"' && !escaped) ? "\\\"" : c);
593-
escaped = (!escaped && c == '\\');
594-
}
595-
return sb.toString();
596-
}
597-
598599
@Override
599600
public Builder filename(String filename, Charset charset) {
601+
Assert.hasText(filename, "No filename");
600602
this.filename = filename;
601603
this.charset = charset;
602604
return this;

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,15 @@ public void formatWithEncodedFilenameUsingUsAscii() {
222222
@Test // gh-24220
223223
public void formatWithFilenameWithQuotes() {
224224

225-
BiConsumer<String, String> tester = (input, output) ->
225+
BiConsumer<String, String> tester = (input, output) -> {
226+
226227
assertThat(builder("form-data").filename(input).build().toString())
227228
.isEqualTo("form-data; filename=\"" + output + "\"");
228229

230+
assertThat(builder("form-data").filename(input, StandardCharsets.US_ASCII).build().toString())
231+
.isEqualTo("form-data; filename=\"" + output + "\"");
232+
};
233+
229234
String filename = "\"foo.txt";
230235
tester.accept(filename, "\\" + filename);
231236

@@ -243,6 +248,10 @@ public void formatWithFilenameWithQuotes() {
243248

244249
tester.accept("\"\"foo.txt", "\\\"\\\"foo.txt");
245250
tester.accept("\"\"\"foo.txt", "\\\"\\\"\\\"foo.txt");
251+
252+
tester.accept("foo.txt\\", "foo.txt");
253+
tester.accept("foo.txt\\\\", "foo.txt\\\\");
254+
tester.accept("foo.txt\\\\\\", "foo.txt\\\\");
246255
}
247256

248257
@Test

0 commit comments

Comments
 (0)