From 5fd761ee3955ab376a13079651ad68f774b9d741 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 2 Feb 2018 13:44:07 +0100 Subject: [PATCH] MimeType.compareTo uses case-insensitive Charset (analogous to equals) Issue: SPR-16458 (cherry picked from commit cfe7ff1) --- .../org/springframework/util/MimeType.java | 68 ++++++++++++------- .../springframework/util/MimeTypeTests.java | 30 ++++---- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/MimeType.java b/spring-core/src/main/java/org/springframework/util/MimeType.java index 23ceb3e317..5e94debe3e 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeType.java +++ b/spring-core/src/main/java/org/springframework/util/MimeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -322,7 +322,7 @@ public class MimeType implements Comparable, Serializable { if (other == null) { return false; } - if (this.isWildcardType()) { + if (isWildcardType()) { // */* includes anything return true; } @@ -330,7 +330,7 @@ public class MimeType implements Comparable, Serializable { if (getSubtype().equals(other.getSubtype())) { return true; } - if (this.isWildcardSubtype()) { + if (isWildcardSubtype()) { // wildcard with suffix, e.g. application/*+xml int thisPlusIdx = getSubtype().indexOf('+'); if (thisPlusIdx == -1) { @@ -373,22 +373,18 @@ public class MimeType implements Comparable, Serializable { if (getSubtype().equals(other.getSubtype())) { return true; } - // wildcard with suffix? e.g. application/*+xml - if (this.isWildcardSubtype() || other.isWildcardSubtype()) { - + // Wildcard with suffix? e.g. application/*+xml + if (isWildcardSubtype() || other.isWildcardSubtype()) { int thisPlusIdx = getSubtype().indexOf('+'); int otherPlusIdx = other.getSubtype().indexOf('+'); - if (thisPlusIdx == -1 && otherPlusIdx == -1) { return true; } else if (thisPlusIdx != -1 && otherPlusIdx != -1) { String thisSubtypeNoSuffix = getSubtype().substring(0, thisPlusIdx); String otherSubtypeNoSuffix = other.getSubtype().substring(0, otherPlusIdx); - String thisSubtypeSuffix = getSubtype().substring(thisPlusIdx + 1); String otherSubtypeSuffix = other.getSubtype().substring(otherPlusIdx + 1); - if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && (WILDCARD_TYPE.equals(thisSubtypeNoSuffix) || WILDCARD_TYPE.equals(otherSubtypeNoSuffix))) { return true; @@ -429,7 +425,6 @@ public class MimeType implements Comparable, Serializable { if (!other.parameters.containsKey(key)) { return false; } - if (PARAM_CHARSET.equals(key)) { if (!ObjectUtils.nullSafeEquals(getCharset(), other.getCharset())) { return false; @@ -493,12 +488,14 @@ public class MimeType implements Comparable, Serializable { if (comp != 0) { return comp; } + TreeSet thisAttributes = new TreeSet(String.CASE_INSENSITIVE_ORDER); thisAttributes.addAll(getParameters().keySet()); TreeSet otherAttributes = new TreeSet(String.CASE_INSENSITIVE_ORDER); otherAttributes.addAll(other.getParameters().keySet()); Iterator thisAttributesIterator = thisAttributes.iterator(); Iterator otherAttributesIterator = otherAttributes.iterator(); + while (thisAttributesIterator.hasNext()) { String thisAttribute = thisAttributesIterator.next(); String otherAttribute = otherAttributesIterator.next(); @@ -506,16 +503,35 @@ public class MimeType implements Comparable, Serializable { if (comp != 0) { return comp; } - String thisValue = getParameters().get(thisAttribute); - String otherValue = other.getParameters().get(otherAttribute); - if (otherValue == null) { - otherValue = ""; + if (PARAM_CHARSET.equals(thisAttribute)) { + Charset thisCharset = getCharset(); + Charset otherCharset = other.getCharset(); + if (thisCharset != otherCharset) { + if (thisCharset == null) { + return -1; + } + if (otherCharset == null) { + return 1; + } + comp = thisCharset.compareTo(otherCharset); + if (comp != 0) { + return comp; + } + } } - comp = thisValue.compareTo(otherValue); - if (comp != 0) { - return comp; + else { + String thisValue = getParameters().get(thisAttribute); + String otherValue = other.getParameters().get(otherAttribute); + if (otherValue == null) { + otherValue = ""; + } + comp = thisValue.compareTo(otherValue); + if (comp != 0) { + return comp; + } } } + return 0; } @@ -541,26 +557,26 @@ public class MimeType implements Comparable, Serializable { @Override public int compare(T mimeType1, T mimeType2) { - if (mimeType1.isWildcardType() && !mimeType2.isWildcardType()) { // */* < audio/* + if (mimeType1.isWildcardType() && !mimeType2.isWildcardType()) { // */* < audio/* return 1; } - else if (mimeType2.isWildcardType() && !mimeType1.isWildcardType()) { // audio/* > */* + else if (mimeType2.isWildcardType() && !mimeType1.isWildcardType()) { // audio/* > */* return -1; } - else if (!mimeType1.getType().equals(mimeType2.getType())) { // audio/basic == text/html + else if (!mimeType1.getType().equals(mimeType2.getType())) { // audio/basic == text/html return 0; } - else { // mediaType1.getType().equals(mediaType2.getType()) - if (mimeType1.isWildcardSubtype() && !mimeType2.isWildcardSubtype()) { // audio/* < audio/basic + else { // mediaType1.getType().equals(mediaType2.getType()) + if (mimeType1.isWildcardSubtype() && !mimeType2.isWildcardSubtype()) { // audio/* < audio/basic return 1; } - else if (mimeType2.isWildcardSubtype() && !mimeType1.isWildcardSubtype()) { // audio/basic > audio/* + else if (mimeType2.isWildcardSubtype() && !mimeType1.isWildcardSubtype()) { // audio/basic > audio/* return -1; } - else if (!mimeType1.getSubtype().equals(mimeType2.getSubtype())) { // audio/basic == audio/wave + else if (!mimeType1.getSubtype().equals(mimeType2.getSubtype())) { // audio/basic == audio/wave return 0; } - else { // mediaType2.getSubtype().equals(mediaType2.getSubtype()) + else { // mediaType2.getSubtype().equals(mediaType2.getSubtype()) return compareParameters(mimeType1, mimeType2); } } @@ -569,7 +585,7 @@ public class MimeType implements Comparable, Serializable { protected int compareParameters(T mimeType1, T mimeType2) { int paramsSize1 = mimeType1.getParameters().size(); int paramsSize2 = mimeType2.getParameters().size(); - return (paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic + return (paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic } } diff --git a/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java b/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java index 43420d3698..c5bdb9d4cf 100644 --- a/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java +++ b/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ import org.junit.Test; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; -import static java.util.Collections.singletonMap; +import static java.util.Collections.*; import static org.junit.Assert.*; /** @@ -70,7 +70,7 @@ public class MimeTypeTests { } @Test - public void parseCharset() throws Exception { + public void parseCharset() { String s = "text/html; charset=iso-8859-1"; MimeType mimeType = MimeType.valueOf(s); assertEquals("Invalid type", "text", mimeType.getType()); @@ -106,7 +106,7 @@ public class MimeTypeTests { } @Test - public void includes() throws Exception { + public void includes() { MimeType textPlain = MimeTypeUtils.TEXT_PLAIN; assertTrue("Equal types is not inclusive", textPlain.includes(textPlain)); MimeType allText = new MimeType("text"); @@ -133,7 +133,7 @@ public class MimeTypeTests { } @Test - public void isCompatible() throws Exception { + public void isCompatible() { MimeType textPlain = MimeTypeUtils.TEXT_PLAIN; assertTrue("Equal types is not compatible", textPlain.isCompatibleWith(textPlain)); MimeType allText = new MimeType("text"); @@ -160,14 +160,14 @@ public class MimeTypeTests { } @Test - public void testToString() throws Exception { + public void testToString() { MimeType mimeType = new MimeType("text", "plain"); String result = mimeType.toString(); assertEquals("Invalid toString() returned", "text/plain", result); } @Test - public void parseMimeType() throws Exception { + public void parseMimeType() { String s = "audio/*"; MimeType mimeType = MimeTypeUtils.parseMimeType(s); assertEquals("Invalid type", "audio", mimeType.getType()); @@ -200,7 +200,7 @@ public class MimeTypeTests { } @Test(expected = InvalidMimeTypeException.class) - public void parseMimeTypeMissingTypeAndSubtype() throws Exception { + public void parseMimeTypeMissingTypeAndSubtype() { MimeTypeUtils.parseMimeType(" ;a=b"); } @@ -229,19 +229,13 @@ public class MimeTypeTests { MimeTypeUtils.parseMimeType("text/html; charset=foo-bar"); } - /** - * SPR-8917 - */ - @Test + @Test // SPR-8917 public void parseMimeTypeQuotedParameterValue() { MimeType mimeType = MimeTypeUtils.parseMimeType("audio/*;attr=\"v>alue\""); assertEquals("\"v>alue\"", mimeType.getParameter("attr")); } - /** - * SPR-8917 - */ - @Test + @Test // SPR-8917 public void parseMimeTypeSingleQuotedParameterValue() { MimeType mimeType = MimeTypeUtils.parseMimeType("audio/*;attr='v>alue'"); assertEquals("'v>alue'", mimeType.getParameter("attr")); @@ -253,7 +247,7 @@ public class MimeTypeTests { } @Test - public void parseMimeTypes() throws Exception { + public void parseMimeTypes() { String s = "text/plain, text/html, text/x-dvi, text/x-c"; List mimeTypes = MimeTypeUtils.parseMimeTypes(s); assertNotNull("No mime types returned", mimeTypes); @@ -325,6 +319,8 @@ public class MimeTypeTests { MimeType m2 = new MimeType("text", "plain", singletonMap("charset", "utf-8")); assertEquals(m1, m2); assertEquals(m2, m1); + assertEquals(0, m1.compareTo(m2)); + assertEquals(0, m2.compareTo(m1)); } }