1
1
/*
2
- * Copyright 2002-2019 the original author or authors.
2
+ * Copyright 2002-2020 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
81
81
* </tr>
82
82
* </table>
83
83
*
84
- * <p>As of 5.0 you can set the exact strategies to use via
84
+ * <p>Alternatively you can avoid use of the above convenience builder
85
+ * methods and set the exact strategies to use via
85
86
* {@link #setStrategies(List)}.
86
87
*
87
- * <p><strong>Note:</strong> if you must use URL-based content type resolution,
88
- * the use of a query parameter is simpler and preferable to the use of a path
89
- * extension since the latter can cause issues with URI variables, path
90
- * parameters, and URI decoding. Consider setting {@link #setFavorPathExtension}
91
- * to {@literal false} or otherwise set the strategies to use explicitly via
92
- * {@link #setStrategies(List)}.
88
+ * <p><strong>Note:</strong> As of 5.2.4,
89
+ * {@link #setFavorPathExtension(boolean) favorPathExtension} and
90
+ * {@link #setIgnoreUnknownPathExtensions(boolean) ignoreUnknownPathExtensions}
91
+ * are deprecated in order to discourage use of path extensions for content
92
+ * negotiation as well as for request mapping (with similar deprecations in
93
+ * {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
94
+ * RequestMappingHandlerMapping}). For further context, please read issue
95
+ * <a href="https://github.com/spring-projects/spring-framework/issues/24179">#24719</a>.
93
96
*
94
97
* @author Rossen Stoyanchev
95
98
* @author Brian Clozel
@@ -145,52 +148,61 @@ public void setStrategies(@Nullable List<ContentNegotiationStrategy> strategies)
145
148
* <p>By default this is set to {@code true} in which case a request
146
149
* for {@code /hotels.pdf} will be interpreted as a request for
147
150
* {@code "application/pdf"} regardless of the 'Accept' header.
151
+ * @deprecated as of 5.2.4. See class-level note on the deprecation of path
152
+ * extension config options.
148
153
*/
154
+ @ Deprecated
149
155
public void setFavorPathExtension (boolean favorPathExtension ) {
150
156
this .favorPathExtension = favorPathExtension ;
151
157
}
152
158
153
159
/**
154
- * Add a mapping from a key, extracted from a path extension or a query
155
- * parameter, to a MediaType. This is required in order for the parameter
156
- * strategy to work. Any extensions explicitly registered here are also
157
- * whitelisted for the purpose of Reflected File Download attack detection
158
- * (see Spring Framework reference documentation for more details on RFD
159
- * attack protection).
160
- * <p>The path extension strategy will also try to use
160
+ * Add a mapping from a key to a MediaType where the key are normalized to
161
+ * lowercase and may have been extracted from a path extension, a filename
162
+ * extension, or passed as a query parameter.
163
+ * <p>The {@link #setFavorParameter(boolean) parameter strategy} requires
164
+ * such mappings in order to work while the {@link #setFavorPathExtension(boolean)
165
+ * path extension strategy} can fall back on lookups via
161
166
* {@link ServletContext#getMimeType} and
162
- * {@link org.springframework.http.MediaTypeFactory} to resolve path extensions.
167
+ * {@link org.springframework.http.MediaTypeFactory}.
168
+ * <p><strong>Note:</strong> Mappings registered here may be accessed via
169
+ * {@link ContentNegotiationManager#getMediaTypeMappings()} and may be used
170
+ * not only in the parameter and path extension strategies. For example,
171
+ * with the Spring MVC config, e.g. {@code @EnableWebMvc} or
172
+ * {@code <mvc:annotation-driven>}, the media type mappings are also plugged
173
+ * in to:
174
+ * <ul>
175
+ * <li>Determine the media type of static resources served with
176
+ * {@code ResourceHttpRequestHandler}.
177
+ * <li>Determine the media type of views rendered with
178
+ * {@code ContentNegotiatingViewResolver}.
179
+ * <li>Whitelist extensions for RFD attack detection (check the Spring
180
+ * Framework reference docs for details).
181
+ * </ul>
163
182
* @param mediaTypes media type mappings
164
183
* @see #addMediaType(String, MediaType)
165
184
* @see #addMediaTypes(Map)
166
185
*/
167
186
public void setMediaTypes (Properties mediaTypes ) {
168
187
if (!CollectionUtils .isEmpty (mediaTypes )) {
169
- mediaTypes .forEach ((key , value ) -> {
170
- String extension = ((String ) key ).toLowerCase (Locale .ENGLISH );
171
- MediaType mediaType = MediaType .valueOf ((String ) value );
172
- this .mediaTypes .put (extension , mediaType );
173
- });
188
+ mediaTypes .forEach ((key , value ) ->
189
+ addMediaType ((String ) key , MediaType .valueOf ((String ) value )));
174
190
}
175
191
}
176
192
177
193
/**
178
- * An alternative to {@link #setMediaTypes} for use in Java code.
179
- * @see #setMediaTypes
180
- * @see #addMediaTypes
194
+ * An alternative to {@link #setMediaTypes} for programmatic registrations.
181
195
*/
182
- public void addMediaType (String fileExtension , MediaType mediaType ) {
183
- this .mediaTypes .put (fileExtension , mediaType );
196
+ public void addMediaType (String key , MediaType mediaType ) {
197
+ this .mediaTypes .put (key . toLowerCase ( Locale . ENGLISH ) , mediaType );
184
198
}
185
199
186
200
/**
187
- * An alternative to {@link #setMediaTypes} for use in Java code.
188
- * @see #setMediaTypes
189
- * @see #addMediaType
201
+ * An alternative to {@link #setMediaTypes} for programmatic registrations.
190
202
*/
191
203
public void addMediaTypes (@ Nullable Map <String , MediaType > mediaTypes ) {
192
204
if (mediaTypes != null ) {
193
- this . mediaTypes .putAll ( mediaTypes );
205
+ mediaTypes .forEach ( this :: addMediaType );
194
206
}
195
207
}
196
208
@@ -199,7 +211,10 @@ public void addMediaTypes(@Nullable Map<String, MediaType> mediaTypes) {
199
211
* to any media type. Setting this to {@code false} will result in an
200
212
* {@code HttpMediaTypeNotAcceptableException} if there is no match.
201
213
* <p>By default this is set to {@code true}.
214
+ * @deprecated as of 5.2.4. See class-level note on the deprecation of path
215
+ * extension config options.
202
216
*/
217
+ @ Deprecated
203
218
public void setIgnoreUnknownPathExtensions (boolean ignore ) {
204
219
this .ignoreUnknownPathExtensions = ignore ;
205
220
}
@@ -303,9 +318,10 @@ public void afterPropertiesSet() {
303
318
}
304
319
305
320
/**
306
- * Actually build the {@link ContentNegotiationManager}.
321
+ * Create and initialize a {@link ContentNegotiationManager} instance .
307
322
* @since 5.0
308
323
*/
324
+ @ SuppressWarnings ("deprecation" )
309
325
public ContentNegotiationManager build () {
310
326
List <ContentNegotiationStrategy > strategies = new ArrayList <>();
311
327
@@ -327,7 +343,6 @@ public ContentNegotiationManager build() {
327
343
}
328
344
strategies .add (strategy );
329
345
}
330
-
331
346
if (this .favorParameter ) {
332
347
ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy (this .mediaTypes );
333
348
strategy .setParameterName (this .parameterName );
@@ -339,17 +354,24 @@ public ContentNegotiationManager build() {
339
354
}
340
355
strategies .add (strategy );
341
356
}
342
-
343
357
if (!this .ignoreAcceptHeader ) {
344
358
strategies .add (new HeaderContentNegotiationStrategy ());
345
359
}
346
-
347
360
if (this .defaultNegotiationStrategy != null ) {
348
361
strategies .add (this .defaultNegotiationStrategy );
349
362
}
350
363
}
351
364
352
365
this .contentNegotiationManager = new ContentNegotiationManager (strategies );
366
+
367
+ // Ensure media type mappings are available via ContentNegotiationManager#getMediaTypeMappings()
368
+ // independent of path extension or parameter strategies.
369
+
370
+ if (!CollectionUtils .isEmpty (this .mediaTypes ) && !this .favorPathExtension && !this .favorParameter ) {
371
+ this .contentNegotiationManager .addFileExtensionResolvers (
372
+ new MappingMediaTypeFileExtensionResolver (this .mediaTypes ));
373
+ }
374
+
353
375
return this .contentNegotiationManager ;
354
376
}
355
377
0 commit comments