Skip to content

Commit 7bbd4c6

Browse files
committed
Merge pull request #2010 from dimitrisli/SPR-17459
2 parents 46a5fb7 + ba3fef3 commit 7bbd4c6

File tree

3 files changed

+65
-14
lines changed

3 files changed

+65
-14
lines changed

spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.List;
2929
import java.util.Map;
3030
import java.util.Random;
31+
import java.util.stream.Collectors;
3132

3233
import org.springframework.lang.Nullable;
3334
import org.springframework.util.MimeType.SpecificityComparator;
@@ -37,6 +38,7 @@
3738
*
3839
* @author Arjen Poutsma
3940
* @author Rossen Stoyanchev
41+
* @author Dimitrios Liapis
4042
* @since 4.0
4143
*/
4244
public abstract class MimeTypeUtils {
@@ -248,21 +250,54 @@ else if (ch == '"') {
248250
}
249251

250252
/**
251-
* Parse the given, comma-separated string into a list of {@code MimeType} objects.
253+
* Parse the comma-separated string into a list of {@code MimeType} objects.
252254
* @param mimeTypes the string to parse
253255
* @return the list of mime types
254-
* @throws IllegalArgumentException if the string cannot be parsed
256+
* @throws InvalidMimeTypeException if the string cannot be parsed
255257
*/
256258
public static List<MimeType> parseMimeTypes(String mimeTypes) {
257259
if (!StringUtils.hasLength(mimeTypes)) {
258260
return Collections.emptyList();
259261
}
260-
String[] tokens = StringUtils.tokenizeToStringArray(mimeTypes, ",");
261-
List<MimeType> result = new ArrayList<>(tokens.length);
262-
for (String token : tokens) {
263-
result.add(parseMimeType(token));
262+
return tokenize(mimeTypes).stream()
263+
.map(MimeTypeUtils::parseMimeType).collect(Collectors.toList());
264+
}
265+
266+
/**
267+
* Tokenize the given comma-separated string of {@code MimeType} objects
268+
* into a {@code List<String>}. Unlike simple tokenization by ",", this
269+
* method takes into account quoted parameters.
270+
* @param mimeTypes the string to tokenize
271+
* @return the list of tokens
272+
* @since 5.1.3
273+
*/
274+
public static List<String> tokenize(String mimeTypes) {
275+
if (!StringUtils.hasLength(mimeTypes)) {
276+
return Collections.emptyList();
277+
}
278+
List<String> tokens = new ArrayList<>();
279+
boolean inQuotes = false;
280+
int startIndex = 0;
281+
int i = 0;
282+
while (i < mimeTypes.length()) {
283+
switch (mimeTypes.charAt(i)) {
284+
case '"':
285+
inQuotes = !inQuotes;
286+
break;
287+
case ',':
288+
if (!inQuotes) {
289+
tokens.add(mimeTypes.substring(startIndex, i));
290+
startIndex = i + 1;
291+
}
292+
break;
293+
case '\\':
294+
i++;
295+
break;
296+
}
297+
i++;
264298
}
265-
return result;
299+
tokens.add(mimeTypes.substring(startIndex));
300+
return tokens;
266301
}
267302

268303
/**

spring-core/src/test/java/org/springframework/util/MimeTypeTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* @author Arjen Poutsma
3737
* @author Juergen Hoeller
3838
* @author Sam Brannen
39+
* @author Dimitrios Liapis
3940
*/
4041
public class MimeTypeTests {
4142

@@ -276,6 +277,25 @@ public void parseMimeTypes() {
276277
assertEquals("Invalid amount of mime types", 0, mimeTypes.size());
277278
}
278279

280+
@Test // SPR-17459
281+
public void parseMimeTypesWithQuotedParameters() {
282+
testWithQuotedParameters("foo/bar;param=\",\"");
283+
testWithQuotedParameters("foo/bar;param=\"s,a,\"");
284+
testWithQuotedParameters("foo/bar;param=\"s,\"", "text/x-c");
285+
testWithQuotedParameters("foo/bar;param=\"a\\\"b,c\"");
286+
testWithQuotedParameters("foo/bar;param=\"\\\\\"");
287+
testWithQuotedParameters("foo/bar;param=\"\\,\\\"");
288+
}
289+
290+
private void testWithQuotedParameters(String... mimeTypes) {
291+
String s = String.join(",", mimeTypes);
292+
List<MimeType> actual = MimeTypeUtils.parseMimeTypes(s);
293+
assertEquals(mimeTypes.length, actual.size());
294+
for (int i=0; i < mimeTypes.length; i++) {
295+
assertEquals(mimeTypes[i], actual.get(i).toString());
296+
}
297+
}
298+
279299
@Test
280300
public void compareTo() {
281301
MimeType audioBasic = new MimeType("audio", "basic");

spring-web/src/main/java/org/springframework/http/MediaType.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ public static MediaType parseMediaType(String mediaType) {
542542
}
543543

544544
/**
545-
* Parse the given comma-separated string into a list of {@code MediaType} objects.
545+
* Parse the comma-separated string into a list of {@code MediaType} objects.
546546
* <p>This method can be used to parse an Accept or Content-Type header.
547547
* @param mediaTypes the string to parse
548548
* @return the list of media types
@@ -552,12 +552,8 @@ public static List<MediaType> parseMediaTypes(@Nullable String mediaTypes) {
552552
if (!StringUtils.hasLength(mediaTypes)) {
553553
return Collections.emptyList();
554554
}
555-
String[] tokens = StringUtils.tokenizeToStringArray(mediaTypes, ",");
556-
List<MediaType> result = new ArrayList<>(tokens.length);
557-
for (String token : tokens) {
558-
result.add(parseMediaType(token));
559-
}
560-
return result;
555+
return MimeTypeUtils.tokenize(mediaTypes).stream()
556+
.map(MediaType::parseMediaType).collect(Collectors.toList());
561557
}
562558

563559
/**

0 commit comments

Comments
 (0)