Skip to content

Commit

Permalink
Change MediaType.parse to allow and skip over linear whitespace on …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
cgdecker authored and Google Java Core Libraries committed Aug 7, 2023
1 parent c6d35cf commit 2786f83
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 16 deletions.
21 changes: 18 additions & 3 deletions android/guava-tests/test/com/google/common/net/MediaTypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.google.common.net;

import static com.google.common.base.Charsets.UTF_16;
import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.net.MediaType.ANY_APPLICATION_TYPE;
import static com.google.common.net.MediaType.ANY_AUDIO_TYPE;
import static com.google.common.net.MediaType.ANY_IMAGE_TYPE;
Expand All @@ -31,6 +29,8 @@
import static java.lang.reflect.Modifier.isFinal;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
import static java.nio.charset.StandardCharsets.UTF_16;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;

import com.google.common.annotations.GwtCompatible;
Expand Down Expand Up @@ -512,6 +512,14 @@ public void testParse_badInput() {
}
}

// https://github.com/google/guava/issues/6663
public void testParse_spaceInParameterSeparator() {
assertThat(MediaType.parse("text/plain; charset =utf-8").charset()).hasValue(UTF_8);
assertThat(MediaType.parse("text/plain; charset= utf-8").charset()).hasValue(UTF_8);
assertThat(MediaType.parse("text/plain; charset = utf-8").charset()).hasValue(UTF_8);
assertThat(MediaType.parse("text/plain;charset =utf-8").charset()).hasValue(UTF_8);
}

public void testGetCharset() {
assertThat(MediaType.parse("text/plain").charset()).isAbsent();
assertThat(MediaType.parse("text/plain; charset=utf-8").charset()).hasValue(UTF_8);
Expand Down Expand Up @@ -556,6 +564,9 @@ public void testEquals() {
MediaType.create("TEXT", "PLAIN"),
MediaType.parse("text/plain"),
MediaType.parse("TEXT/PLAIN"),
MediaType.parse("text /plain"),
MediaType.parse("TEXT/ plain"),
MediaType.parse("text / plain"),
MediaType.create("text", "plain").withParameter("a", "1").withoutParameters())
.addEqualityGroup(
MediaType.create("text", "plain").withCharset(UTF_8),
Expand All @@ -571,7 +582,11 @@ public void testEquals() {
MediaType.parse("text/plain; charset=\"utf-8\""),
MediaType.parse("text/plain; charset=\"\\u\\tf-\\8\""),
MediaType.parse("text/plain; charset=UTF-8"),
MediaType.parse("text/plain ; charset=utf-8"))
MediaType.parse("text/plain ; charset=utf-8"),
MediaType.parse("text/plain; charset =UTF-8"),
MediaType.parse("text/plain; charset= UTF-8"),
MediaType.parse("text/plain; charset = UTF-8"),
MediaType.parse("text/plain; charset=\tUTF-8"))
.addEqualityGroup(MediaType.parse("text/plain; charset=utf-8; charset=utf-8"))
.addEqualityGroup(
MediaType.create("text", "plain").withParameter("a", "value"),
Expand Down
14 changes: 9 additions & 5 deletions android/guava/src/com/google/common/net/MediaType.java
Original file line number Diff line number Diff line change
Expand Up @@ -1052,15 +1052,13 @@ public static MediaType parse(String input) {
Tokenizer tokenizer = new Tokenizer(input);
try {
String type = tokenizer.consumeToken(TOKEN_MATCHER);
tokenizer.consumeCharacter('/');
consumeSeparator(tokenizer, '/');
String subtype = tokenizer.consumeToken(TOKEN_MATCHER);
ImmutableListMultimap.Builder<String, String> parameters = ImmutableListMultimap.builder();
while (tokenizer.hasMore()) {
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
tokenizer.consumeCharacter(';');
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
consumeSeparator(tokenizer, ';');
String attribute = tokenizer.consumeToken(TOKEN_MATCHER);
tokenizer.consumeCharacter('=');
consumeSeparator(tokenizer, '=');
String value;
if ('"' == tokenizer.previewChar()) {
tokenizer.consumeCharacter('"');
Expand All @@ -1086,6 +1084,12 @@ public static MediaType parse(String input) {
}
}

private static void consumeSeparator(Tokenizer tokenizer, char c) {
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
tokenizer.consumeCharacter(c);
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
}

private static final class Tokenizer {
final String input;
int position = 0;
Expand Down
21 changes: 18 additions & 3 deletions guava-tests/test/com/google/common/net/MediaTypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.google.common.net;

import static com.google.common.base.Charsets.UTF_16;
import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.net.MediaType.ANY_APPLICATION_TYPE;
import static com.google.common.net.MediaType.ANY_AUDIO_TYPE;
import static com.google.common.net.MediaType.ANY_IMAGE_TYPE;
Expand All @@ -31,6 +29,8 @@
import static java.lang.reflect.Modifier.isFinal;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
import static java.nio.charset.StandardCharsets.UTF_16;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;

import com.google.common.annotations.GwtCompatible;
Expand Down Expand Up @@ -512,6 +512,14 @@ public void testParse_badInput() {
}
}

// https://github.com/google/guava/issues/6663
public void testParse_spaceInParameterSeparator() {
assertThat(MediaType.parse("text/plain; charset =utf-8").charset()).hasValue(UTF_8);
assertThat(MediaType.parse("text/plain; charset= utf-8").charset()).hasValue(UTF_8);
assertThat(MediaType.parse("text/plain; charset = utf-8").charset()).hasValue(UTF_8);
assertThat(MediaType.parse("text/plain;charset =utf-8").charset()).hasValue(UTF_8);
}

public void testGetCharset() {
assertThat(MediaType.parse("text/plain").charset()).isAbsent();
assertThat(MediaType.parse("text/plain; charset=utf-8").charset()).hasValue(UTF_8);
Expand Down Expand Up @@ -556,6 +564,9 @@ public void testEquals() {
MediaType.create("TEXT", "PLAIN"),
MediaType.parse("text/plain"),
MediaType.parse("TEXT/PLAIN"),
MediaType.parse("text /plain"),
MediaType.parse("TEXT/ plain"),
MediaType.parse("text / plain"),
MediaType.create("text", "plain").withParameter("a", "1").withoutParameters())
.addEqualityGroup(
MediaType.create("text", "plain").withCharset(UTF_8),
Expand All @@ -571,7 +582,11 @@ public void testEquals() {
MediaType.parse("text/plain; charset=\"utf-8\""),
MediaType.parse("text/plain; charset=\"\\u\\tf-\\8\""),
MediaType.parse("text/plain; charset=UTF-8"),
MediaType.parse("text/plain ; charset=utf-8"))
MediaType.parse("text/plain ; charset=utf-8"),
MediaType.parse("text/plain; charset =UTF-8"),
MediaType.parse("text/plain; charset= UTF-8"),
MediaType.parse("text/plain; charset = UTF-8"),
MediaType.parse("text/plain; charset=\tUTF-8"))
.addEqualityGroup(MediaType.parse("text/plain; charset=utf-8; charset=utf-8"))
.addEqualityGroup(
MediaType.create("text", "plain").withParameter("a", "value"),
Expand Down
14 changes: 9 additions & 5 deletions guava/src/com/google/common/net/MediaType.java
Original file line number Diff line number Diff line change
Expand Up @@ -1052,15 +1052,13 @@ public static MediaType parse(String input) {
Tokenizer tokenizer = new Tokenizer(input);
try {
String type = tokenizer.consumeToken(TOKEN_MATCHER);
tokenizer.consumeCharacter('/');
consumeSeparator(tokenizer, '/');
String subtype = tokenizer.consumeToken(TOKEN_MATCHER);
ImmutableListMultimap.Builder<String, String> parameters = ImmutableListMultimap.builder();
while (tokenizer.hasMore()) {
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
tokenizer.consumeCharacter(';');
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
consumeSeparator(tokenizer, ';');
String attribute = tokenizer.consumeToken(TOKEN_MATCHER);
tokenizer.consumeCharacter('=');
consumeSeparator(tokenizer, '=');
String value;
if ('"' == tokenizer.previewChar()) {
tokenizer.consumeCharacter('"');
Expand All @@ -1086,6 +1084,12 @@ public static MediaType parse(String input) {
}
}

private static void consumeSeparator(Tokenizer tokenizer, char c) {
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
tokenizer.consumeCharacter(c);
tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
}

private static final class Tokenizer {
final String input;
int position = 0;
Expand Down

0 comments on commit 2786f83

Please sign in to comment.