39
39
import org .springframework .util .StringUtils ;
40
40
import org .springframework .web .HttpMediaTypeNotAcceptableException ;
41
41
import org .springframework .web .accept .ContentNegotiationManager ;
42
+ import org .springframework .web .accept .ContentNegotiationStrategy ;
43
+ import org .springframework .web .accept .PathExtensionContentNegotiationStrategy ;
42
44
import org .springframework .web .context .request .NativeWebRequest ;
43
45
import org .springframework .web .context .request .ServletWebRequest ;
44
46
import org .springframework .web .method .support .HandlerMethodReturnValueHandler ;
@@ -73,8 +75,14 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
73
75
"json" , "xml" , "atom" , "rss" ,
74
76
"png" , "jpe" , "jpeg" , "jpg" , "gif" , "wbmp" , "bmp" ));
75
77
78
+ private static final Set <String > WHITELISTED_MEDIA_BASE_TYPES = new HashSet <String >(
79
+ Arrays .asList ("audio" , "image" , "video" ));
80
+
81
+
76
82
private final ContentNegotiationManager contentNegotiationManager ;
77
83
84
+ private final PathExtensionContentNegotiationStrategy pathStrategy ;
85
+
78
86
private final ResponseBodyAdviceChain adviceChain ;
79
87
80
88
private final Set <String > safeExtensions = new HashSet <String >();
@@ -94,11 +102,21 @@ protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>>
94
102
95
103
super (messageConverters );
96
104
this .contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager ());
105
+ this .pathStrategy = initPathStrategy (this .contentNegotiationManager );
97
106
this .adviceChain = new ResponseBodyAdviceChain (responseBodyAdvice );
98
107
this .safeExtensions .addAll (this .contentNegotiationManager .getAllFileExtensions ());
99
108
this .safeExtensions .addAll (WHITELISTED_EXTENSIONS );
100
109
}
101
110
111
+ private static PathExtensionContentNegotiationStrategy initPathStrategy (ContentNegotiationManager manager ) {
112
+ for (ContentNegotiationStrategy strategy : manager .getStrategies ()) {
113
+ if (strategy instanceof PathExtensionContentNegotiationStrategy ) {
114
+ return (PathExtensionContentNegotiationStrategy ) strategy ;
115
+ }
116
+ }
117
+ return new PathExtensionContentNegotiationStrategy ();
118
+ }
119
+
102
120
103
121
protected ResponseBodyAdviceChain getAdviceChain () {
104
122
return this .adviceChain ;
@@ -322,7 +340,31 @@ private boolean safeExtension(HttpServletRequest request, String extension) {
322
340
return true ;
323
341
}
324
342
}
325
- return false ;
343
+ return safeMediaTypesForExtension (extension );
344
+ }
345
+
346
+ private boolean safeMediaTypesForExtension (String extension ) {
347
+ List <MediaType > mediaTypes = null ;
348
+ try {
349
+ mediaTypes = this .pathStrategy .resolveMediaTypeKey (null , extension );
350
+ }
351
+ catch (HttpMediaTypeNotAcceptableException e ) {
352
+ // Ignore
353
+ }
354
+ if (CollectionUtils .isEmpty (mediaTypes )) {
355
+ return false ;
356
+ }
357
+ for (MediaType mediaType : mediaTypes ) {
358
+ if (!safeMediaType (mediaType )) {
359
+ return false ;
360
+ }
361
+ }
362
+ return true ;
363
+ }
364
+
365
+ private boolean safeMediaType (MediaType mediaType ) {
366
+ return (WHITELISTED_MEDIA_BASE_TYPES .contains (mediaType .getType ()) ||
367
+ mediaType .getSubtype ().endsWith ("+xml" ));
326
368
}
327
369
328
370
}
0 commit comments