mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Ensure parsing/tostring symmetry in ContentDisposition
Prior to this commit, building a "Content-Disposition" header to a String and then parsing it back would not always result in the original header. This commit ensures that ContentDisposition guarantees this and honors the "equals" contract. Fixes gh-37064
This commit is contained in:
@@ -172,17 +172,17 @@ public final class ContentDisposition {
|
||||
sb.append(this.type);
|
||||
}
|
||||
if (this.name != null) {
|
||||
sb.append("; name=\"").append(this.name).append('\"');
|
||||
sb.append("; name=\"");
|
||||
appendName(sb, this.name).append('\"');
|
||||
}
|
||||
if (this.filename != null) {
|
||||
if (this.charset == null || StandardCharsets.US_ASCII.equals(this.charset)) {
|
||||
sb.append("; filename=\"")
|
||||
.append(encodeQuotedPairs(this.filename))
|
||||
.append('\"');
|
||||
sb.append("; filename=\"");
|
||||
appendName(sb, this.filename).append('\"');
|
||||
}
|
||||
else {
|
||||
sb.append("; filename=\"")
|
||||
.append(transliterateToAscii(encodeQuotedPairs(this.filename)))
|
||||
.append(transliterateToAscii(appendName(new StringBuilder(), this.filename).toString()))
|
||||
.append("\"; filename*=")
|
||||
.append(encodeRfc5987Filename(this.filename, this.charset));
|
||||
}
|
||||
@@ -253,7 +253,7 @@ public final class ContentDisposition {
|
||||
part.substring(eqIndex + 2, part.length() - 1) :
|
||||
part.substring(eqIndex + 1));
|
||||
if (attribute.equals("name") ) {
|
||||
name = value;
|
||||
name = (value.indexOf('\\') != -1 ? decodeQuotedPairs(value) : value);
|
||||
}
|
||||
else if (attribute.equals("filename*") ) {
|
||||
int idx1 = value.indexOf('\'');
|
||||
@@ -503,19 +503,20 @@ public final class ContentDisposition {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String encodeQuotedPairs(String filename) {
|
||||
if (filename.indexOf('"') == -1 && filename.indexOf('\\') == -1) {
|
||||
return filename;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < filename.length() ; i++) {
|
||||
char c = filename.charAt(i);
|
||||
if (c == '"' || c == '\\') {
|
||||
sb.append('\\');
|
||||
private static StringBuilder appendName(StringBuilder buffer, String name) {
|
||||
for (int i = 0; i < name.length() ; i++) {
|
||||
char c = name.charAt(i);
|
||||
// strip control characters
|
||||
if (c <= 0x1F || c == 0x7F) {
|
||||
continue;
|
||||
}
|
||||
sb.append(c);
|
||||
// encode quoted pairs
|
||||
if (c == '"' || c == '\\') {
|
||||
buffer.append('\\');
|
||||
}
|
||||
buffer.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static String decodeQuotedPairs(String filename) {
|
||||
|
||||
@@ -181,6 +181,15 @@ class ContentDispositionTests {
|
||||
assertThat(cd.getFilename()).isEqualTo("foo\\bar \"baz\" qux \\\" quux.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseBackslashInName() {
|
||||
String s = "form-data; name=\"foo\\\"bar\"; filename=\"foo.txt\"";
|
||||
ContentDisposition cd = ContentDisposition.parse(s);
|
||||
assertThat(cd.getName()).isEqualTo("foo\"bar");
|
||||
assertThat(cd.getFilename()).isEqualTo("foo.txt");
|
||||
assertThat(cd.toString()).isEqualTo(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseBackslashInLastPosition() {
|
||||
ContentDisposition cd = ContentDisposition.parse("form-data; name=\"foo\"; filename=\"bar\\\"");
|
||||
|
||||
Reference in New Issue
Block a user