Consistent support for multiple Accept headers
Issue: SPR-14506
This commit is contained in:
@@ -429,19 +429,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* <p>Returns an empty list when the acceptable media types are unspecified.
|
||||
*/
|
||||
public List<MediaType> getAccept() {
|
||||
String value = getFirst(ACCEPT);
|
||||
List<MediaType> result = (value != null ? MediaType.parseMediaTypes(value) : Collections.<MediaType>emptyList());
|
||||
|
||||
// Some containers parse 'Accept' into multiple values
|
||||
if (result.size() == 1) {
|
||||
List<String> acceptHeader = get(ACCEPT);
|
||||
if (acceptHeader.size() > 1) {
|
||||
value = StringUtils.collectionToCommaDelimitedString(acceptHeader);
|
||||
result = MediaType.parseMediaTypes(value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return MediaType.parseMediaTypes(get(ACCEPT));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,7 +440,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code Access-Control-Allow-Credentials} response header.
|
||||
* Return the value of the {@code Access-Control-Allow-Credentials} response header.
|
||||
*/
|
||||
public boolean getAccessControlAllowCredentials() {
|
||||
return Boolean.parseBoolean(getFirst(ACCESS_CONTROL_ALLOW_CREDENTIALS));
|
||||
@@ -466,7 +454,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code Access-Control-Allow-Headers} response header.
|
||||
* Return the value of the {@code Access-Control-Allow-Headers} response header.
|
||||
*/
|
||||
public List<String> getAccessControlAllowHeaders() {
|
||||
return getValuesAsList(ACCESS_CONTROL_ALLOW_HEADERS);
|
||||
@@ -519,7 +507,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code Access-Control-Expose-Headers} response header.
|
||||
* Return the value of the {@code Access-Control-Expose-Headers} response header.
|
||||
*/
|
||||
public List<String> getAccessControlExposeHeaders() {
|
||||
return getValuesAsList(ACCESS_CONTROL_EXPOSE_HEADERS);
|
||||
@@ -533,7 +521,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code Access-Control-Max-Age} response header.
|
||||
* Return the value of the {@code Access-Control-Max-Age} response header.
|
||||
* <p>Returns -1 when the max age is unknown.
|
||||
*/
|
||||
public long getAccessControlMaxAge() {
|
||||
@@ -549,7 +537,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code Access-Control-Request-Headers} request header.
|
||||
* Return the value of the {@code Access-Control-Request-Headers} request header.
|
||||
*/
|
||||
public List<String> getAccessControlRequestHeaders() {
|
||||
return getValuesAsList(ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.InvalidMimeTypeException;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
@@ -397,6 +398,8 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* Parse the given String value into a {@code MediaType} object,
|
||||
* with this method name following the 'valueOf' naming convention
|
||||
* (as supported by {@link org.springframework.core.convert.ConversionService}.
|
||||
* @param value the string to parse
|
||||
* @throws InvalidMediaTypeException if the media type value cannot be parsed
|
||||
* @see #parseMediaType(String)
|
||||
*/
|
||||
public static MediaType valueOf(String value) {
|
||||
@@ -407,7 +410,7 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* Parse the given String into a single {@code MediaType}.
|
||||
* @param mediaType the string to parse
|
||||
* @return the media type
|
||||
* @throws InvalidMediaTypeException if the string cannot be parsed
|
||||
* @throws InvalidMediaTypeException if the media type value cannot be parsed
|
||||
*/
|
||||
public static MediaType parseMediaType(String mediaType) {
|
||||
MimeType type;
|
||||
@@ -425,13 +428,12 @@ public class MediaType extends MimeType implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given, comma-separated string into a list of {@code MediaType} objects.
|
||||
* Parse the given comma-separated string into a list of {@code MediaType} objects.
|
||||
* <p>This method can be used to parse an Accept or Content-Type header.
|
||||
* @param mediaTypes the string to parse
|
||||
* @return the list of media types
|
||||
* @throws IllegalArgumentException if the string cannot be parsed
|
||||
* @throws InvalidMediaTypeException if the media type value cannot be parsed
|
||||
*/
|
||||
public static List<MediaType> parseMediaTypes(String mediaTypes) {
|
||||
if (!StringUtils.hasLength(mediaTypes)) {
|
||||
@@ -445,6 +447,31 @@ public class MediaType extends MimeType implements Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given list of (potentially) comma-separated strings into a
|
||||
* list of {@code MediaType} objects.
|
||||
* <p>This method can be used to parse an Accept or Content-Type header.
|
||||
* @param mediaTypes the string to parse
|
||||
* @return the list of media types
|
||||
* @throws InvalidMediaTypeException if the media type value cannot be parsed
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static List<MediaType> parseMediaTypes(List<String> mediaTypes) {
|
||||
if (CollectionUtils.isEmpty(mediaTypes)) {
|
||||
return Collections.<MediaType>emptyList();
|
||||
}
|
||||
else if (mediaTypes.size() == 1) {
|
||||
return parseMediaTypes(mediaTypes.get(0));
|
||||
}
|
||||
else {
|
||||
List<MediaType> result = new ArrayList<>(8);
|
||||
for (String mediaType : mediaTypes) {
|
||||
result.addAll(parseMediaTypes(mediaType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-create the given mime types as media types.
|
||||
* @since 5.0
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.springframework.web.accept;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
* A {@code ContentNegotiationStrategy} that checks the 'Accept' request header.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.2
|
||||
*/
|
||||
public class HeaderContentNegotiationStrategy implements ContentNegotiationStrategy {
|
||||
@@ -42,18 +43,20 @@ public class HeaderContentNegotiationStrategy implements ContentNegotiationStrat
|
||||
public List<MediaType> resolveMediaTypes(NativeWebRequest request)
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
String header = request.getHeader(HttpHeaders.ACCEPT);
|
||||
if (!StringUtils.hasText(header)) {
|
||||
return Collections.emptyList();
|
||||
String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);
|
||||
if (headerValueArray == null) {
|
||||
return Collections.<MediaType>emptyList();
|
||||
}
|
||||
|
||||
List<String> headerValues = Arrays.asList(headerValueArray);
|
||||
try {
|
||||
List<MediaType> mediaTypes = MediaType.parseMediaTypes(header);
|
||||
List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerValues);
|
||||
MediaType.sortBySpecificityAndQuality(mediaTypes);
|
||||
return mediaTypes;
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new HttpMediaTypeNotAcceptableException(
|
||||
"Could not parse 'Accept' header [" + header + "]: " + ex.getMessage());
|
||||
"Could not parse 'Accept' header " + headerValues + ": " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user