Skip to content

Commit f7a014d

Browse files
committed
Improve MIME type subtype suffix handling
Prior to this commit, the subtype suffix of a MIME type (see RFC 6839) was not properly taken into account when checking compatibility between MIME types. For example, `"application/*"` was not considered as compatible with `"application/vnd.io.spring+json"`. This commit adds a new `MimeType#getSubtypeSuffix()` method to easily extract the subtype suffix information. This method is then reused in the `isCompatibleWith` implementation to better handle these cases. Fixes gh-25350
1 parent 93f201a commit f7a014d

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

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

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,19 @@ public String getSubtype() {
284284
return this.subtype;
285285
}
286286

287+
/**
288+
* Return the subtype suffix as defined in RFC 6839.
289+
* @since 5.3
290+
*/
291+
@Nullable
292+
public String getSubtypeSuffix() {
293+
int suffixIndex = this.subtype.lastIndexOf('+');
294+
if (suffixIndex != -1 && this.subtype.length() > suffixIndex) {
295+
return this.subtype.substring(suffixIndex + 1);
296+
}
297+
return null;
298+
}
299+
287300
/**
288301
* Return the character set, as indicated by a {@code charset} parameter, if any.
289302
* @return the character set, or {@code null} if not available
@@ -377,22 +390,20 @@ else if (getType().equals(other.getType())) {
377390
if (getSubtype().equals(other.getSubtype())) {
378391
return true;
379392
}
380-
// Wildcard with suffix? e.g. application/*+xml
381393
if (isWildcardSubtype() || other.isWildcardSubtype()) {
382-
int thisPlusIdx = getSubtype().lastIndexOf('+');
383-
int otherPlusIdx = other.getSubtype().lastIndexOf('+');
384-
if (thisPlusIdx == -1 && otherPlusIdx == -1) {
394+
String thisSuffix = getSubtypeSuffix();
395+
String otherSuffix = other.getSubtypeSuffix();
396+
if (getSubtype().equals(WILDCARD_TYPE)
397+
|| other.getSubtype().equals(WILDCARD_TYPE)) {
385398
return true;
386399
}
387-
else if (thisPlusIdx != -1 && otherPlusIdx != -1) {
388-
String thisSubtypeNoSuffix = getSubtype().substring(0, thisPlusIdx);
389-
String otherSubtypeNoSuffix = other.getSubtype().substring(0, otherPlusIdx);
390-
String thisSubtypeSuffix = getSubtype().substring(thisPlusIdx + 1);
391-
String otherSubtypeSuffix = other.getSubtype().substring(otherPlusIdx + 1);
392-
if (thisSubtypeSuffix.equals(otherSubtypeSuffix) &&
393-
(WILDCARD_TYPE.equals(thisSubtypeNoSuffix) || WILDCARD_TYPE.equals(otherSubtypeNoSuffix))) {
394-
return true;
395-
}
400+
else if (isWildcardSubtype() && thisSuffix != null) {
401+
return thisSuffix.equals(other.getSubtype())
402+
|| thisSuffix.equals(otherSuffix);
403+
}
404+
else if (other.isWildcardSubtype() && otherSuffix != null) {
405+
return this.getSubtype().equals(otherSuffix)
406+
|| otherSuffix.equals(thisSuffix);
396407
}
397408
}
398409
}

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -320,6 +320,25 @@ void parseMimeTypesWithQuotedParameters() {
320320
testWithQuotedParameters("foo/bar;param=\"\\,\\\"");
321321
}
322322

323+
@Test
324+
void parseSubtypeSuffix() {
325+
MimeType type = new MimeType("application", "vdn.something+json");
326+
assertThat(type.getSubtypeSuffix()).isEqualTo("json");
327+
type = new MimeType("application", "vdn.something");
328+
assertThat(type.getSubtypeSuffix()).isNull();
329+
type = new MimeType("application", "vdn.something+");
330+
assertThat(type.getSubtypeSuffix()).isEqualTo("");
331+
type = new MimeType("application", "vdn.some+thing+json");
332+
assertThat(type.getSubtypeSuffix()).isEqualTo("json");
333+
}
334+
335+
@Test // gh-25350
336+
void wildcardSubtypeCompatibleWithSuffix() {
337+
MimeType applicationStar = new MimeType("application", "*");
338+
MimeType applicationVndJson = new MimeType("application", "vnd.something+json");
339+
assertThat(applicationStar.isCompatibleWith(applicationVndJson)).isTrue();
340+
}
341+
323342
private void testWithQuotedParameters(String... mimeTypes) {
324343
String s = String.join(",", mimeTypes);
325344
List<MimeType> actual = MimeTypeUtils.parseMimeTypes(s);

0 commit comments

Comments
 (0)