mirror of
https://github.com/google/guava.git
synced 2026-10-29 09:06:01 +08:00
Reject control characters in MediaType parameter values.
Fixes https://github.com/google/guava/pull/8743 RELNOTES=n/a PiperOrigin-RevId: 1000906952
This commit is contained in:
1 parent
dea4984457
commit
5e82f2f528
4 files changed
+64
-8
No files matched your search
@@ -275,6 +275,18 @@ public class MediaTypeTest extends TestCase {
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "…"));
|
||||
}
|
||||
|
||||
public void testWithParameter_controlCharacterInParameterValue() {
|
||||
MediaType mediaType = MediaType.parse("text/plain");
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\r\nb"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\nb"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\rb"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\u0000b"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\u007fb"));
|
||||
assertThat(mediaType.withParameter("a", "a\tb"))
|
||||
.isEqualTo(MediaType.parse("text/plain; a=\"a\tb\""));
|
||||
assertThat(mediaType.withParameter("a", "a\tb").toString()).isEqualTo("text/plain; a=\"a\tb\"");
|
||||
}
|
||||
|
||||
public void testWithParameter_emptyParameter() {
|
||||
MediaType mediaType = MediaType.parse("text/plain");
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("", "a"));
|
||||
@@ -377,6 +389,15 @@ public class MediaTypeTest extends TestCase {
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=1; b"));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=1; b="));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\u2025"));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\r\nc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\nc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\rc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\\\rc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\\\nc\""));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\u0000c\""));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\\\u0000c\""));
|
||||
}
|
||||
|
||||
// https://github.com/google/guava/issues/6663
|
||||
|
||||
@@ -85,7 +85,11 @@ public final class MediaType {
|
||||
.and(CharMatcher.isNot(' '))
|
||||
.and(CharMatcher.noneOf("()<>@,;:\\\"/[]?="));
|
||||
|
||||
private static final CharMatcher QUOTED_TEXT_MATCHER = ascii().and(CharMatcher.noneOf("\"\\\r"));
|
||||
private static final CharMatcher PARAMETER_VALUE_MATCHER =
|
||||
ascii().and(javaIsoControl().negate()).or(CharMatcher.is('\t'));
|
||||
|
||||
private static final CharMatcher QUOTED_TEXT_MATCHER =
|
||||
PARAMETER_VALUE_MATCHER.and(CharMatcher.noneOf("\"\\"));
|
||||
|
||||
/*
|
||||
* This matches the same characters as linear-white-space from RFC 822, but we make no effort to
|
||||
@@ -1241,7 +1245,10 @@ public final class MediaType {
|
||||
|
||||
private static String normalizeParameterValue(String attribute, String value) {
|
||||
checkNotNull(value); // for GWT
|
||||
checkArgument(ascii().matchesAllOf(value), "parameter values must be ASCII: %s", value);
|
||||
checkArgument(
|
||||
PARAMETER_VALUE_MATCHER.matchesAllOf(value),
|
||||
"parameter values must contain only ASCII and no control characters: %s",
|
||||
value);
|
||||
return attribute.equals(CHARSET_ATTRIBUTE) ? Ascii.toLowerCase(value) : value;
|
||||
}
|
||||
|
||||
@@ -1270,7 +1277,7 @@ public final class MediaType {
|
||||
while (tokenizer.previewChar() != '"') {
|
||||
if (tokenizer.previewChar() == '\\') {
|
||||
tokenizer.consumeCharacter('\\');
|
||||
valueBuilder.append(tokenizer.consumeCharacter(ascii()));
|
||||
valueBuilder.append(tokenizer.consumeCharacter(PARAMETER_VALUE_MATCHER));
|
||||
} else {
|
||||
valueBuilder.append(tokenizer.consumeToken(QUOTED_TEXT_MATCHER));
|
||||
}
|
||||
@@ -1406,7 +1413,7 @@ public final class MediaType {
|
||||
StringBuilder escaped = new StringBuilder(value.length() + 16).append('"');
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (ch == '\r' || ch == '\\' || ch == '"') {
|
||||
if (ch == '\\' || ch == '"') {
|
||||
escaped.append('\\');
|
||||
}
|
||||
escaped.append(ch);
|
||||
|
||||
@@ -275,6 +275,18 @@ public class MediaTypeTest extends TestCase {
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "…"));
|
||||
}
|
||||
|
||||
public void testWithParameter_controlCharacterInParameterValue() {
|
||||
MediaType mediaType = MediaType.parse("text/plain");
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\r\nb"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\nb"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\rb"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\u0000b"));
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("a", "a\u007fb"));
|
||||
assertThat(mediaType.withParameter("a", "a\tb"))
|
||||
.isEqualTo(MediaType.parse("text/plain; a=\"a\tb\""));
|
||||
assertThat(mediaType.withParameter("a", "a\tb").toString()).isEqualTo("text/plain; a=\"a\tb\"");
|
||||
}
|
||||
|
||||
public void testWithParameter_emptyParameter() {
|
||||
MediaType mediaType = MediaType.parse("text/plain");
|
||||
assertThrows(IllegalArgumentException.class, () -> mediaType.withParameter("", "a"));
|
||||
@@ -377,6 +389,15 @@ public class MediaTypeTest extends TestCase {
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=1; b"));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=1; b="));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\u2025"));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\r\nc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\nc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\rc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\\\rc\""));
|
||||
assertThrows(IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\\\nc\""));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\u0000c\""));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> MediaType.parse("text/plain; a=\"b\\\u0000c\""));
|
||||
}
|
||||
|
||||
// https://github.com/google/guava/issues/6663
|
||||
|
||||
@@ -85,7 +85,11 @@ public final class MediaType {
|
||||
.and(CharMatcher.isNot(' '))
|
||||
.and(CharMatcher.noneOf("()<>@,;:\\\"/[]?="));
|
||||
|
||||
private static final CharMatcher QUOTED_TEXT_MATCHER = ascii().and(CharMatcher.noneOf("\"\\\r"));
|
||||
private static final CharMatcher PARAMETER_VALUE_MATCHER =
|
||||
ascii().and(javaIsoControl().negate()).or(CharMatcher.is('\t'));
|
||||
|
||||
private static final CharMatcher QUOTED_TEXT_MATCHER =
|
||||
PARAMETER_VALUE_MATCHER.and(CharMatcher.noneOf("\"\\"));
|
||||
|
||||
/*
|
||||
* This matches the same characters as linear-white-space from RFC 822, but we make no effort to
|
||||
@@ -1241,7 +1245,10 @@ public final class MediaType {
|
||||
|
||||
private static String normalizeParameterValue(String attribute, String value) {
|
||||
checkNotNull(value); // for GWT
|
||||
checkArgument(ascii().matchesAllOf(value), "parameter values must be ASCII: %s", value);
|
||||
checkArgument(
|
||||
PARAMETER_VALUE_MATCHER.matchesAllOf(value),
|
||||
"parameter values must contain only ASCII and no control characters: %s",
|
||||
value);
|
||||
return attribute.equals(CHARSET_ATTRIBUTE) ? Ascii.toLowerCase(value) : value;
|
||||
}
|
||||
|
||||
@@ -1270,7 +1277,7 @@ public final class MediaType {
|
||||
while (tokenizer.previewChar() != '"') {
|
||||
if (tokenizer.previewChar() == '\\') {
|
||||
tokenizer.consumeCharacter('\\');
|
||||
valueBuilder.append(tokenizer.consumeCharacter(ascii()));
|
||||
valueBuilder.append(tokenizer.consumeCharacter(PARAMETER_VALUE_MATCHER));
|
||||
} else {
|
||||
valueBuilder.append(tokenizer.consumeToken(QUOTED_TEXT_MATCHER));
|
||||
}
|
||||
@@ -1406,7 +1413,7 @@ public final class MediaType {
|
||||
StringBuilder escaped = new StringBuilder(value.length() + 16).append('"');
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (ch == '\r' || ch == '\\' || ch == '"') {
|
||||
if (ch == '\\' || ch == '"') {
|
||||
escaped.append('\\');
|
||||
}
|
||||
escaped.append(ch);
|
||||
|
||||
Reference in new issue
Block a user