43
43
import org .springframework .util .StringUtils ;
44
44
import org .springframework .web .HttpMediaTypeNotAcceptableException ;
45
45
import org .springframework .web .accept .ContentNegotiationManager ;
46
+ import org .springframework .web .accept .ContentNegotiationStrategy ;
47
+ import org .springframework .web .accept .PathExtensionContentNegotiationStrategy ;
46
48
import org .springframework .web .context .request .NativeWebRequest ;
47
49
import org .springframework .web .context .request .ServletWebRequest ;
48
50
import org .springframework .web .method .support .HandlerMethodReturnValueHandler ;
@@ -77,12 +79,18 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
77
79
"json" , "xml" , "atom" , "rss" ,
78
80
"png" , "jpe" , "jpeg" , "jpg" , "gif" , "wbmp" , "bmp" ));
79
81
82
+ private static final Set <String > WHITELISTED_MEDIA_BASE_TYPES = new HashSet <String >(
83
+ Arrays .asList ("audio" , "image" , "video" ));
84
+
80
85
81
86
private final ContentNegotiationManager contentNegotiationManager ;
82
87
88
+ private final PathExtensionContentNegotiationStrategy pathStrategy ;
89
+
83
90
private final Set <String > safeExtensions = new HashSet <String >();
84
91
85
92
93
+
86
94
/**
87
95
* Constructor with list of converters only.
88
96
*/
@@ -108,10 +116,20 @@ protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>>
108
116
109
117
super (converters , requestResponseBodyAdvice );
110
118
this .contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager ());
119
+ this .pathStrategy = initPathStrategy (this .contentNegotiationManager );
111
120
this .safeExtensions .addAll (this .contentNegotiationManager .getAllFileExtensions ());
112
121
this .safeExtensions .addAll (WHITELISTED_EXTENSIONS );
113
122
}
114
123
124
+ private static PathExtensionContentNegotiationStrategy initPathStrategy (ContentNegotiationManager manager ) {
125
+ for (ContentNegotiationStrategy strategy : manager .getStrategies ()) {
126
+ if (strategy instanceof PathExtensionContentNegotiationStrategy ) {
127
+ return (PathExtensionContentNegotiationStrategy ) strategy ;
128
+ }
129
+ }
130
+ return new PathExtensionContentNegotiationStrategy ();
131
+ }
132
+
115
133
116
134
/**
117
135
* Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
@@ -386,7 +404,31 @@ private boolean safeExtension(HttpServletRequest request, String extension) {
386
404
return true ;
387
405
}
388
406
}
389
- return false ;
407
+ return safeMediaTypesForExtension (extension );
408
+ }
409
+
410
+ private boolean safeMediaTypesForExtension (String extension ) {
411
+ List <MediaType > mediaTypes = null ;
412
+ try {
413
+ mediaTypes = this .pathStrategy .resolveMediaTypeKey (null , extension );
414
+ }
415
+ catch (HttpMediaTypeNotAcceptableException e ) {
416
+ // Ignore
417
+ }
418
+ if (CollectionUtils .isEmpty (mediaTypes )) {
419
+ return false ;
420
+ }
421
+ for (MediaType mediaType : mediaTypes ) {
422
+ if (!safeMediaType (mediaType )) {
423
+ return false ;
424
+ }
425
+ }
426
+ return true ;
427
+ }
428
+
429
+ private boolean safeMediaType (MediaType mediaType ) {
430
+ return (WHITELISTED_MEDIA_BASE_TYPES .contains (mediaType .getType ()) ||
431
+ mediaType .getSubtype ().endsWith ("+xml" ));
390
432
}
391
433
392
434
}
0 commit comments