Skip to content

Commit 2786f83

Browse files
cgdeckerGoogle Java Core Libraries
authored and
Google Java Core Libraries
committedAug 7, 2023
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

File tree

4 files changed

+54
-16
lines changed

4 files changed

+54
-16
lines changed
 

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

+18-3
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

+9-5
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

+18-3
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

+9-5
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)
Please sign in to comment.