Update ContentNegotiationManager for unknown path exts
This change refines the logic of "mapping" content negotiation strategies with regards to how to handle cases where no mapping is found. The request parameter strategy now treats request parameter values that do not match any mapped media type as 406 errors. The path extension strategy provides a new flag called "ignoreUnknownExtensions" (true by default) that when set to false also results in a 406. The same flag is also exposed through the ContentNegotiationManagerFactoryBean and the MVC Java config. Issue: SPR-10170
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
@@ -34,6 +35,7 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
public abstract class AbstractMappingContentNegotiationStrategy extends MappingMediaTypeFileExtensionResolver
|
||||
implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver {
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
* @throws IllegalArgumentException if a media type string cannot be parsed
|
||||
@@ -42,8 +44,9 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
super(mediaTypes);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) {
|
||||
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
|
||||
String key = getMediaTypeKey(webRequest);
|
||||
if (StringUtils.hasText(key)) {
|
||||
MediaType mediaType = lookupMediaType(key);
|
||||
@@ -76,7 +79,7 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
* Invoked when no matching media type is found in the lookup map.
|
||||
* Sub-classes can take further steps to determine the media type.
|
||||
*/
|
||||
protected MediaType handleNoMatch(NativeWebRequest request, String mappingKey) {
|
||||
protected MediaType handleNoMatch(NativeWebRequest request, String key) throws HttpMediaTypeNotAcceptableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -55,6 +55,8 @@ public class ContentNegotiationManagerFactoryBean
|
||||
|
||||
private Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
|
||||
|
||||
private boolean ignoreUnknownPathExtensions = true;
|
||||
|
||||
private Boolean useJaf;
|
||||
|
||||
private String parameterName = "format";
|
||||
@@ -116,6 +118,17 @@ public class ContentNegotiationManagerFactoryBean
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to ignore requests that have a file extension that does not match
|
||||
* any mapped media types. Setting this to {@code false} will result in a
|
||||
* {@code HttpMediaTypeNotAcceptableException} when there is no match.
|
||||
*
|
||||
* <p>By default this is set to {@code true}.
|
||||
*/
|
||||
public void setIgnoreUnknownPathExtensions(boolean ignoreUnknownPathExtensions) {
|
||||
this.ignoreUnknownPathExtensions = ignoreUnknownPathExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether to use the Java Activation Framework as a fallback option
|
||||
* to map from file extensions to media types. This is used only when
|
||||
@@ -191,6 +204,7 @@ public class ContentNegotiationManagerFactoryBean
|
||||
} else {
|
||||
strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes);
|
||||
}
|
||||
strategy.setIgnoreUnknownExtensions(this.ignoreUnknownPathExtensions);
|
||||
if (this.useJaf != null) {
|
||||
strategy.setUseJaf(this.useJaf);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.accept;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -59,6 +60,7 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the file extensions mapped to the given MediaType.
|
||||
* @return 0 or more extensions, never {@code null}
|
||||
@@ -74,6 +76,10 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
|
||||
return Collections.unmodifiableList(this.allFileExtensions);
|
||||
}
|
||||
|
||||
protected List<MediaType> getAllMediaTypes() {
|
||||
return new ArrayList<MediaType>(this.mediaTypes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MediaType mapped to the given extension.
|
||||
* @return a MediaType for the key or {@code null}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -22,6 +22,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
@@ -68,4 +69,8 @@ public class ParameterContentNegotiationStrategy extends AbstractMappingContentN
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MediaType handleNoMatch(NativeWebRequest request, String key) throws HttpMediaTypeNotAcceptableException {
|
||||
throw new HttpMediaTypeNotAcceptableException(getAllMediaTypes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
@@ -65,6 +66,8 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
|
||||
private boolean useJaf = JAF_PRESENT;
|
||||
|
||||
private boolean ignoreUnknownExtensions = true;
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
@@ -82,14 +85,30 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
super(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicate whether to use the Java Activation Framework to map from file extensions to media types.
|
||||
* <p>Default is {@code true}, i.e. the Java Activation Framework is used (if available).
|
||||
* Indicate whether to use the Java Activation Framework to map from file
|
||||
* extensions to media types.
|
||||
*
|
||||
* <p>Default is {@code true}, i.e. the Java Activation Framework is used
|
||||
* (if available).
|
||||
*/
|
||||
public void setUseJaf(boolean useJaf) {
|
||||
this.useJaf = useJaf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to ignore requests that have a file extension that does not match
|
||||
* any mapped media types. Setting this to {@code false} will result in a
|
||||
* {@code HttpMediaTypeNotAcceptableException}.
|
||||
*
|
||||
* <p>By default this is set to {@code true}.
|
||||
*/
|
||||
public void setIgnoreUnknownExtensions(boolean ignoreUnknownExtensions) {
|
||||
this.ignoreUnknownExtensions = ignoreUnknownExtensions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getMediaTypeKey(NativeWebRequest webRequest) {
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
@@ -108,13 +127,18 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) {
|
||||
protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension)
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
if (this.useJaf) {
|
||||
MediaType jafMediaType = JafMediaTypeFactory.getMediaType("file." + extension);
|
||||
if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) {
|
||||
return jafMediaType;
|
||||
}
|
||||
}
|
||||
if (!this.ignoreUnknownExtensions) {
|
||||
throw new HttpMediaTypeNotAcceptableException(getAllMediaTypes());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -22,6 +22,7 @@ import javax.servlet.ServletContext;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,9 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio
|
||||
* and if that doesn't help, delegate to the parent implementation.
|
||||
*/
|
||||
@Override
|
||||
protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) {
|
||||
protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension)
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
MediaType mediaType = null;
|
||||
if (this.servletContext != null) {
|
||||
String mimeType = this.servletContext.getMimeType("file." + extension);
|
||||
|
||||
Reference in New Issue
Block a user