MimeType parsing properly handles quoted semicolons
Issue: SPR-14986
(cherry picked from commit 7714eec
)
This commit is contained in:
parent
dd3c370bca
commit
84d8135cbb
|
@ -165,8 +165,8 @@ public class MimeType implements Comparable<MimeType>, Serializable {
|
||||||
* @throws IllegalArgumentException if any of the parameters contains illegal characters
|
* @throws IllegalArgumentException if any of the parameters contains illegal characters
|
||||||
*/
|
*/
|
||||||
public MimeType(String type, String subtype, Map<String, String> parameters) {
|
public MimeType(String type, String subtype, Map<String, String> parameters) {
|
||||||
Assert.hasLength(type, "type must not be empty");
|
Assert.hasLength(type, "'type' must not be empty");
|
||||||
Assert.hasLength(subtype, "subtype must not be empty");
|
Assert.hasLength(subtype, "'subtype' must not be empty");
|
||||||
checkToken(type);
|
checkToken(type);
|
||||||
checkToken(subtype);
|
checkToken(subtype);
|
||||||
this.type = type.toLowerCase(Locale.ENGLISH);
|
this.type = type.toLowerCase(Locale.ENGLISH);
|
||||||
|
@ -202,8 +202,8 @@ public class MimeType implements Comparable<MimeType>, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkParameters(String attribute, String value) {
|
protected void checkParameters(String attribute, String value) {
|
||||||
Assert.hasLength(attribute, "parameter attribute must not be empty");
|
Assert.hasLength(attribute, "'attribute' must not be empty");
|
||||||
Assert.hasLength(value, "parameter value must not be empty");
|
Assert.hasLength(value, "'value' must not be empty");
|
||||||
checkToken(attribute);
|
checkToken(attribute);
|
||||||
if (PARAM_CHARSET.equals(attribute)) {
|
if (PARAM_CHARSET.equals(attribute)) {
|
||||||
value = unquote(value);
|
value = unquote(value);
|
||||||
|
@ -277,8 +277,8 @@ public class MimeType implements Comparable<MimeType>, Serializable {
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
public Charset getCharset() {
|
public Charset getCharset() {
|
||||||
String charSet = getParameter(PARAM_CHARSET);
|
String charset = getParameter(PARAM_CHARSET);
|
||||||
return (charSet != null ? Charset.forName(unquote(charSet)) : null);
|
return (charset != null ? Charset.forName(unquote(charset)) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -49,6 +49,10 @@ public abstract class MimeTypeUtils {
|
||||||
|
|
||||||
private static Charset US_ASCII = Charset.forName("US-ASCII");
|
private static Charset US_ASCII = Charset.forName("US-ASCII");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparator used by {@link #sortBySpecificity(List)}.
|
||||||
|
*/
|
||||||
|
public static final Comparator<MimeType> SPECIFICITY_COMPARATOR = new SpecificityComparator<MimeType>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public constant mime type that includes all media ranges (i.e. "*/*").
|
* Public constant mime type that includes all media ranges (i.e. "*/*").
|
||||||
|
@ -219,12 +223,13 @@ public abstract class MimeTypeUtils {
|
||||||
if (!StringUtils.hasLength(mimeType)) {
|
if (!StringUtils.hasLength(mimeType)) {
|
||||||
throw new InvalidMimeTypeException(mimeType, "'mimeType' must not be empty");
|
throw new InvalidMimeTypeException(mimeType, "'mimeType' must not be empty");
|
||||||
}
|
}
|
||||||
String[] parts = StringUtils.tokenizeToStringArray(mimeType, ";");
|
|
||||||
if (parts.length == 0) {
|
int index = mimeType.indexOf(';');
|
||||||
|
String fullType = (index >= 0 ? mimeType.substring(0, index) : mimeType).trim();
|
||||||
|
if (fullType.length() == 0) {
|
||||||
throw new InvalidMimeTypeException(mimeType, "'mimeType' must not be empty");
|
throw new InvalidMimeTypeException(mimeType, "'mimeType' must not be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
String fullType = parts[0].trim();
|
|
||||||
// java.net.HttpURLConnection returns a *; q=.2 Accept header
|
// java.net.HttpURLConnection returns a *; q=.2 Accept header
|
||||||
if (MimeType.WILDCARD_TYPE.equals(fullType)) {
|
if (MimeType.WILDCARD_TYPE.equals(fullType)) {
|
||||||
fullType = "*/*";
|
fullType = "*/*";
|
||||||
|
@ -243,18 +248,36 @@ public abstract class MimeTypeUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> parameters = null;
|
Map<String, String> parameters = null;
|
||||||
if (parts.length > 1) {
|
do {
|
||||||
parameters = new LinkedHashMap<String, String>(parts.length - 1);
|
int nextIndex = index + 1;
|
||||||
for (int i = 1; i < parts.length; i++) {
|
boolean quoted = false;
|
||||||
String parameter = parts[i];
|
while (nextIndex < mimeType.length()) {
|
||||||
|
char ch = mimeType.charAt(nextIndex);
|
||||||
|
if (ch == ';') {
|
||||||
|
if (!quoted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ch == '"') {
|
||||||
|
quoted = !quoted;
|
||||||
|
}
|
||||||
|
nextIndex++;
|
||||||
|
}
|
||||||
|
String parameter = mimeType.substring(index + 1, nextIndex).trim();
|
||||||
|
if (parameter.length() > 0) {
|
||||||
|
if (parameters == null) {
|
||||||
|
parameters = new LinkedHashMap<String, String>(4);
|
||||||
|
}
|
||||||
int eqIndex = parameter.indexOf('=');
|
int eqIndex = parameter.indexOf('=');
|
||||||
if (eqIndex != -1) {
|
if (eqIndex >= 0) {
|
||||||
String attribute = parameter.substring(0, eqIndex);
|
String attribute = parameter.substring(0, eqIndex);
|
||||||
String value = parameter.substring(eqIndex + 1, parameter.length());
|
String value = parameter.substring(eqIndex + 1, parameter.length());
|
||||||
parameters.put(attribute, value);
|
parameters.put(attribute, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
index = nextIndex;
|
||||||
}
|
}
|
||||||
|
while (index < mimeType.length());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new MimeType(type, subtype, parameters);
|
return new MimeType(type, subtype, parameters);
|
||||||
|
@ -353,11 +376,4 @@ public abstract class MimeTypeUtils {
|
||||||
return new String(generateMultipartBoundary(), US_ASCII);
|
return new String(generateMultipartBoundary(), US_ASCII);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comparator used by {@link #sortBySpecificity(List)}.
|
|
||||||
*/
|
|
||||||
public static final Comparator<MimeType> SPECIFICITY_COMPARATOR = new SpecificityComparator<MimeType>();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,16 @@ public class MimeTypeTests {
|
||||||
assertEquals("Invalid charset", Charset.forName("UTF-8"), mimeType.getCharset());
|
assertEquals("Invalid charset", Charset.forName("UTF-8"), mimeType.getCharset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseQuotedSeparator() {
|
||||||
|
String s = "application/xop+xml;charset=utf-8;type=\"application/soap+xml;action=\\\"http://x.y.z\\\"\"";
|
||||||
|
MimeType mimeType = MimeType.valueOf(s);
|
||||||
|
assertEquals("Invalid type", "application", mimeType.getType());
|
||||||
|
assertEquals("Invalid subtype", "xop+xml", mimeType.getSubtype());
|
||||||
|
assertEquals("Invalid charset", Charset.forName("UTF-8"), mimeType.getCharset());
|
||||||
|
assertEquals("\"application/soap+xml;action=\\\"http://x.y.z\\\"\"", mimeType.getParameter("type"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withConversionService() {
|
public void withConversionService() {
|
||||||
ConversionService conversionService = new DefaultConversionService();
|
ConversionService conversionService = new DefaultConversionService();
|
||||||
|
|
Loading…
Reference in New Issue