Skip to content

Commit 2786f83

Browse files
cgdeckerGoogle Java Core Libraries
authored andcommitted
Change MediaType.parse to allow and skip over linear whitespace on either side of the = separator in a parameter (attribute=value) as well as on either side of the / between the type and subtype (because nothing in the specification suggests that it be treated differently than the ; or the =).
[RFC 822](https://datatracker.ietf.org/doc/html/rfc822), which specifies the notation used to describe the syntax of a media type in [RFC 2045](https://datatracker.ietf.org/doc/html/rfc2045#section-5.1), seems to [indicate](https://datatracker.ietf.org/doc/html/rfc822#section-3.1.4) that spaces should be allowed here (and in fact if it didn't, nothing in the specification would allow them around the `;` either). Fixes #6663. RELNOTES=`net`: Made `MediaType.parse` allow and skip over whitespace around the `/` and `=` separator tokens in addition to the `;` separator for which it was already being allowed. PiperOrigin-RevId: 554496121
1 parent c6d35cf commit 2786f83

4 files changed

Lines changed: 54 additions & 16 deletions

File tree

android/guava-tests/test/com/google/common/net/MediaTypeTest.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package com.google.common.net;
1818

19-
import static com.google.common.base.Charsets.UTF_16;
20-
import static com.google.common.base.Charsets.UTF_8;
2119
import static com.google.common.net.MediaType.ANY_APPLICATION_TYPE;
2220
import static com.google.common.net.MediaType.ANY_AUDIO_TYPE;
2321
import static com.google.common.net.MediaType.ANY_IMAGE_TYPE;
@@ -31,6 +29,8 @@
3129
import static java.lang.reflect.Modifier.isFinal;
3230
import static java.lang.reflect.Modifier.isPublic;
3331
import static java.lang.reflect.Modifier.isStatic;
32+
import static java.nio.charset.StandardCharsets.UTF_16;
33+
import static java.nio.charset.StandardCharsets.UTF_8;
3434
import static java.util.Arrays.asList;
3535

3636
import com.google.common.annotations.GwtCompatible;
@@ -512,6 +512,14 @@ public void testParse_badInput() {
512512
}
513513
}
514514

515+
// https://github.com/google/guava/issues/6663
516+
public void testParse_spaceInParameterSeparator() {
517+
assertThat(MediaType.parse("text/plain; charset =utf-8").charset()).hasValue(UTF_8);
518+
assertThat(MediaType.parse("text/plain; charset= utf-8").charset()).hasValue(UTF_8);
519+
assertThat(MediaType.parse("text/plain; charset = utf-8").charset()).hasValue(UTF_8);
520+
assertThat(MediaType.parse("text/plain;charset =utf-8").charset()).hasValue(UTF_8);
521+
}
522+
515523
public void testGetCharset() {
516524
assertThat(MediaType.parse("text/plain").charset()).isAbsent();
517525
assertThat(MediaType.parse("text/plain; charset=utf-8").charset()).hasValue(UTF_8);
@@ -556,6 +564,9 @@ public void testEquals() {
556564
MediaType.create("TEXT", "PLAIN"),
557565
MediaType.parse("text/plain"),
558566
MediaType.parse("TEXT/PLAIN"),
567+
MediaType.parse("text /plain"),
568+
MediaType.parse("TEXT/ plain"),
569+
MediaType.parse("text / plain"),
559570
MediaType.create("text", "plain").withParameter("a", "1").withoutParameters())
560571
.addEqualityGroup(
561572
MediaType.create("text", "plain").withCharset(UTF_8),
@@ -571,7 +582,11 @@ public void testEquals() {
571582
MediaType.parse("text/plain; charset=\"utf-8\""),
572583
MediaType.parse("text/plain; charset=\"\\u\\tf-\\8\""),
573584
MediaType.parse("text/plain; charset=UTF-8"),
574-
MediaType.parse("text/plain ; charset=utf-8"))
585+
MediaType.parse("text/plain ; charset=utf-8"),
586+
MediaType.parse("text/plain; charset =UTF-8"),
587+
MediaType.parse("text/plain; charset= UTF-8"),
588+
MediaType.parse("text/plain; charset = UTF-8"),
589+
MediaType.parse("text/plain; charset=\tUTF-8"))
575590
.addEqualityGroup(MediaType.parse("text/plain; charset=utf-8; charset=utf-8"))
576591
.addEqualityGroup(
577592
MediaType.create("text", "plain").withParameter("a", "value"),

android/guava/src/com/google/common/net/MediaType.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,15 +1052,13 @@ public static MediaType parse(String input) {
10521052
Tokenizer tokenizer = new Tokenizer(input);
10531053
try {
10541054
String type = tokenizer.consumeToken(TOKEN_MATCHER);
1055-
tokenizer.consumeCharacter('/');
1055+
consumeSeparator(tokenizer, '/');
10561056
String subtype = tokenizer.consumeToken(TOKEN_MATCHER);
10571057
ImmutableListMultimap.Builder<String, String> parameters = ImmutableListMultimap.builder();
10581058
while (tokenizer.hasMore()) {
1059-
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1060-
tokenizer.consumeCharacter(';');
1061-
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1059+
consumeSeparator(tokenizer, ';');
10621060
String attribute = tokenizer.consumeToken(TOKEN_MATCHER);
1063-
tokenizer.consumeCharacter('=');
1061+
consumeSeparator(tokenizer, '=');
10641062
String value;
10651063
if ('"' == tokenizer.previewChar()) {
10661064
tokenizer.consumeCharacter('"');
@@ -1086,6 +1084,12 @@ public static MediaType parse(String input) {
10861084
}
10871085
}
10881086

1087+
private static void consumeSeparator(Tokenizer tokenizer, char c) {
1088+
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1089+
tokenizer.consumeCharacter(c);
1090+
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1091+
}
1092+
10891093
private static final class Tokenizer {
10901094
final String input;
10911095
int position = 0;

guava-tests/test/com/google/common/net/MediaTypeTest.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package com.google.common.net;
1818

19-
import static com.google.common.base.Charsets.UTF_16;
20-
import static com.google.common.base.Charsets.UTF_8;
2119
import static com.google.common.net.MediaType.ANY_APPLICATION_TYPE;
2220
import static com.google.common.net.MediaType.ANY_AUDIO_TYPE;
2321
import static com.google.common.net.MediaType.ANY_IMAGE_TYPE;
@@ -31,6 +29,8 @@
3129
import static java.lang.reflect.Modifier.isFinal;
3230
import static java.lang.reflect.Modifier.isPublic;
3331
import static java.lang.reflect.Modifier.isStatic;
32+
import static java.nio.charset.StandardCharsets.UTF_16;
33+
import static java.nio.charset.StandardCharsets.UTF_8;
3434
import static java.util.Arrays.asList;
3535

3636
import com.google.common.annotations.GwtCompatible;
@@ -512,6 +512,14 @@ public void testParse_badInput() {
512512
}
513513
}
514514

515+
// https://github.com/google/guava/issues/6663
516+
public void testParse_spaceInParameterSeparator() {
517+
assertThat(MediaType.parse("text/plain; charset =utf-8").charset()).hasValue(UTF_8);
518+
assertThat(MediaType.parse("text/plain; charset= utf-8").charset()).hasValue(UTF_8);
519+
assertThat(MediaType.parse("text/plain; charset = utf-8").charset()).hasValue(UTF_8);
520+
assertThat(MediaType.parse("text/plain;charset =utf-8").charset()).hasValue(UTF_8);
521+
}
522+
515523
public void testGetCharset() {
516524
assertThat(MediaType.parse("text/plain").charset()).isAbsent();
517525
assertThat(MediaType.parse("text/plain; charset=utf-8").charset()).hasValue(UTF_8);
@@ -556,6 +564,9 @@ public void testEquals() {
556564
MediaType.create("TEXT", "PLAIN"),
557565
MediaType.parse("text/plain"),
558566
MediaType.parse("TEXT/PLAIN"),
567+
MediaType.parse("text /plain"),
568+
MediaType.parse("TEXT/ plain"),
569+
MediaType.parse("text / plain"),
559570
MediaType.create("text", "plain").withParameter("a", "1").withoutParameters())
560571
.addEqualityGroup(
561572
MediaType.create("text", "plain").withCharset(UTF_8),
@@ -571,7 +582,11 @@ public void testEquals() {
571582
MediaType.parse("text/plain; charset=\"utf-8\""),
572583
MediaType.parse("text/plain; charset=\"\\u\\tf-\\8\""),
573584
MediaType.parse("text/plain; charset=UTF-8"),
574-
MediaType.parse("text/plain ; charset=utf-8"))
585+
MediaType.parse("text/plain ; charset=utf-8"),
586+
MediaType.parse("text/plain; charset =UTF-8"),
587+
MediaType.parse("text/plain; charset= UTF-8"),
588+
MediaType.parse("text/plain; charset = UTF-8"),
589+
MediaType.parse("text/plain; charset=\tUTF-8"))
575590
.addEqualityGroup(MediaType.parse("text/plain; charset=utf-8; charset=utf-8"))
576591
.addEqualityGroup(
577592
MediaType.create("text", "plain").withParameter("a", "value"),

guava/src/com/google/common/net/MediaType.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,15 +1052,13 @@ public static MediaType parse(String input) {
10521052
Tokenizer tokenizer = new Tokenizer(input);
10531053
try {
10541054
String type = tokenizer.consumeToken(TOKEN_MATCHER);
1055-
tokenizer.consumeCharacter('/');
1055+
consumeSeparator(tokenizer, '/');
10561056
String subtype = tokenizer.consumeToken(TOKEN_MATCHER);
10571057
ImmutableListMultimap.Builder<String, String> parameters = ImmutableListMultimap.builder();
10581058
while (tokenizer.hasMore()) {
1059-
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1060-
tokenizer.consumeCharacter(';');
1061-
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1059+
consumeSeparator(tokenizer, ';');
10621060
String attribute = tokenizer.consumeToken(TOKEN_MATCHER);
1063-
tokenizer.consumeCharacter('=');
1061+
consumeSeparator(tokenizer, '=');
10641062
String value;
10651063
if ('"' == tokenizer.previewChar()) {
10661064
tokenizer.consumeCharacter('"');
@@ -1086,6 +1084,12 @@ public static MediaType parse(String input) {
10861084
}
10871085
}
10881086

1087+
private static void consumeSeparator(Tokenizer tokenizer, char c) {
1088+
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1089+
tokenizer.consumeCharacter(c);
1090+
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
1091+
}
1092+
10891093
private static final class Tokenizer {
10901094
final String input;
10911095
int position = 0;

0 commit comments

Comments
 (0)