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
This commit is contained in:
parent
5a4a46af78
commit
74d3268656
|
@ -23,6 +23,7 @@ import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -58,6 +59,19 @@ public final class ContentDisposition {
|
||||||
private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT =
|
private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT =
|
||||||
"Invalid header field parameter format (as defined in RFC 5987)";
|
"Invalid header field parameter format (as defined in RFC 5987)";
|
||||||
|
|
||||||
|
private static final BitSet PRINTABLE = new BitSet(256);
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
// RFC 2045, Section 6.7, and RFC 2047, Section 4.2
|
||||||
|
for (int i=33; i<= 126; i++) {
|
||||||
|
PRINTABLE.set(i);
|
||||||
|
}
|
||||||
|
PRINTABLE.set(61, false); // =
|
||||||
|
PRINTABLE.set(63, false); // ?
|
||||||
|
PRINTABLE.set(95, false); // _
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String type;
|
private final String type;
|
||||||
|
@ -545,7 +559,7 @@ public final class ContentDisposition {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (index < value.length) {
|
while (index < value.length) {
|
||||||
byte b = value[index];
|
byte b = value[index];
|
||||||
if (b == '_') {
|
if (b == '_') { // RFC 2047, section 4.2, rule (2)
|
||||||
baos.write(' ');
|
baos.write(' ');
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -583,7 +597,10 @@ public final class ContentDisposition {
|
||||||
sb.append(charset.name());
|
sb.append(charset.name());
|
||||||
sb.append("?Q?");
|
sb.append("?Q?");
|
||||||
for (byte b : source) {
|
for (byte b : source) {
|
||||||
if (isPrintable(b)) {
|
if (b == 32) { // RFC 2047, section 4.2, rule (2)
|
||||||
|
sb.append('_');
|
||||||
|
}
|
||||||
|
else if (isPrintable(b)) {
|
||||||
sb.append((char) b);
|
sb.append((char) b);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -599,7 +616,11 @@ public final class ContentDisposition {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPrintable(byte c) {
|
private static boolean isPrintable(byte c) {
|
||||||
return (c >= '!' && c <= '<') || (c >= '@' && c <= '~') || c == '>';
|
int b = c;
|
||||||
|
if (b < 0) {
|
||||||
|
b = 256 + b;
|
||||||
|
}
|
||||||
|
return PRINTABLE.get(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String encodeQuotedPairs(String filename) {
|
private static String encodeQuotedPairs(String filename) {
|
||||||
|
|
|
@ -331,7 +331,12 @@ class ContentDispositionTests {
|
||||||
ContentDisposition cd = ContentDisposition.attachment()
|
ContentDisposition cd = ContentDisposition.attachment()
|
||||||
.filename(filename, StandardCharsets.UTF_8)
|
.filename(filename, StandardCharsets.UTF_8)
|
||||||
.build();
|
.build();
|
||||||
String[] parts = cd.toString().split("; ");
|
String result = cd.toString();
|
||||||
|
assertThat(result).isEqualTo("attachment; " +
|
||||||
|
"filename=\"=?UTF-8?Q?filename_with_=3F=E9=97=AE=E5=8F=B7.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];
|
String quotedPrintableFilename = parts[0] + "; " + parts[1];
|
||||||
assertThat(ContentDisposition.parse(quotedPrintableFilename).getFilename())
|
assertThat(ContentDisposition.parse(quotedPrintableFilename).getFilename())
|
||||||
|
@ -341,4 +346,5 @@ class ContentDispositionTests {
|
||||||
assertThat(ContentDisposition.parse(rfc5987Filename).getFilename())
|
assertThat(ContentDisposition.parse(rfc5987Filename).getFilename())
|
||||||
.isEqualTo(filename);
|
.isEqualTo(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue