Expand range of whitelisted extensions by media type
This commit expands the range of whitelisted extensions by checking if an extension can be resolved to image/*, audo/*, video/*, as well as any content type that ends with +xml. Issue: SPR-13643
This commit is contained in:
@@ -60,7 +60,17 @@ public abstract class AbstractMappingContentNegotiationStrategy
|
|||||||
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
|
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
|
||||||
throws HttpMediaTypeNotAcceptableException {
|
throws HttpMediaTypeNotAcceptableException {
|
||||||
|
|
||||||
String key = getMediaTypeKey(webRequest);
|
return resolveMediaTypeKey(webRequest, getMediaTypeKey(webRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An alternative to {@link #resolveMediaTypes(NativeWebRequest)} that accepts
|
||||||
|
* an already extracted key.
|
||||||
|
* @since 3.2.16
|
||||||
|
*/
|
||||||
|
public List<MediaType> resolveMediaTypeKey(NativeWebRequest webRequest, String key)
|
||||||
|
throws HttpMediaTypeNotAcceptableException {
|
||||||
|
|
||||||
if (StringUtils.hasText(key)) {
|
if (StringUtils.hasText(key)) {
|
||||||
MediaType mediaType = lookupMediaType(key);
|
MediaType mediaType = lookupMediaType(key);
|
||||||
if (mediaType != null) {
|
if (mediaType != null) {
|
||||||
|
|||||||
@@ -88,6 +88,14 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the configured content negotiation strategies.
|
||||||
|
* @since 3.2.16
|
||||||
|
*/
|
||||||
|
public List<ContentNegotiationStrategy> getStrategies() {
|
||||||
|
return this.strategies;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register more {@code MediaTypeFileExtensionResolver} instances in addition
|
* Register more {@code MediaTypeFileExtensionResolver} instances in addition
|
||||||
* to those detected at construction.
|
* to those detected at construction.
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||||
import org.springframework.web.accept.ContentNegotiationManager;
|
import org.springframework.web.accept.ContentNegotiationManager;
|
||||||
|
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||||
|
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||||
@@ -77,12 +79,18 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||||||
"json", "xml", "atom", "rss",
|
"json", "xml", "atom", "rss",
|
||||||
"png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));
|
"png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));
|
||||||
|
|
||||||
|
private static final Set<String> WHITELISTED_MEDIA_BASE_TYPES = new HashSet<String>(
|
||||||
|
Arrays.asList("audio", "image", "video"));
|
||||||
|
|
||||||
|
|
||||||
private final ContentNegotiationManager contentNegotiationManager;
|
private final ContentNegotiationManager contentNegotiationManager;
|
||||||
|
|
||||||
|
private final PathExtensionContentNegotiationStrategy pathStrategy;
|
||||||
|
|
||||||
private final Set<String> safeExtensions = new HashSet<String>();
|
private final Set<String> safeExtensions = new HashSet<String>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor with list of converters only.
|
* Constructor with list of converters only.
|
||||||
*/
|
*/
|
||||||
@@ -108,10 +116,20 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||||||
|
|
||||||
super(converters, requestResponseBodyAdvice);
|
super(converters, requestResponseBodyAdvice);
|
||||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||||
|
this.pathStrategy = initPathStrategy(this.contentNegotiationManager);
|
||||||
this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
|
this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
|
||||||
this.safeExtensions.addAll(WHITELISTED_EXTENSIONS);
|
this.safeExtensions.addAll(WHITELISTED_EXTENSIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static PathExtensionContentNegotiationStrategy initPathStrategy(ContentNegotiationManager manager) {
|
||||||
|
for (ContentNegotiationStrategy strategy : manager.getStrategies()) {
|
||||||
|
if (strategy instanceof PathExtensionContentNegotiationStrategy) {
|
||||||
|
return (PathExtensionContentNegotiationStrategy) strategy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new PathExtensionContentNegotiationStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
|
* Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
|
||||||
@@ -386,7 +404,31 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return safeMediaTypesForExtension(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean safeMediaTypesForExtension(String extension) {
|
||||||
|
List<MediaType> mediaTypes = null;
|
||||||
|
try {
|
||||||
|
mediaTypes = this.pathStrategy.resolveMediaTypeKey(null, extension);
|
||||||
|
}
|
||||||
|
catch (HttpMediaTypeNotAcceptableException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(mediaTypes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (MediaType mediaType : mediaTypes) {
|
||||||
|
if (!safeMediaType(mediaType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean safeMediaType(MediaType mediaType) {
|
||||||
|
return (WHITELISTED_MEDIA_BASE_TYPES.contains(mediaType.getType()) ||
|
||||||
|
mediaType.getSubtype().endsWith("+xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user