|
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.
|
|
24 | 24 | import java.util.Collections;
|
25 | 25 | import java.util.HashMap;
|
26 | 26 | import java.util.List;
|
| 27 | +import java.util.Locale; |
27 | 28 | import java.util.Map;
|
28 | 29 | import java.util.stream.Collectors;
|
29 | 30 |
|
|
43 | 44 | import org.springframework.http.HttpMethod;
|
44 | 45 | import org.springframework.http.HttpRange;
|
45 | 46 | import org.springframework.http.MediaType;
|
| 47 | +import org.springframework.http.MediaTypeFactory; |
46 | 48 | import org.springframework.http.converter.ResourceHttpMessageConverter;
|
47 | 49 | import org.springframework.http.converter.ResourceRegionHttpMessageConverter;
|
48 | 50 | import org.springframework.http.server.ServletServerHttpRequest;
|
|
56 | 58 | import org.springframework.util.StringValueResolver;
|
57 | 59 | import org.springframework.web.HttpRequestHandler;
|
58 | 60 | import org.springframework.web.accept.ContentNegotiationManager;
|
59 |
| -import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; |
60 |
| -import org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy; |
61 | 61 | import org.springframework.web.context.request.ServletWebRequest;
|
62 | 62 | import org.springframework.web.cors.CorsConfiguration;
|
63 | 63 | import org.springframework.web.cors.CorsConfigurationSource;
|
@@ -129,8 +129,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
129 | 129 | @Nullable
|
130 | 130 | private ContentNegotiationManager contentNegotiationManager;
|
131 | 131 |
|
132 |
| - @Nullable |
133 |
| - private PathExtensionContentNegotiationStrategy contentNegotiationStrategy; |
| 132 | + private final Map<String, MediaType> mediaTypes = new HashMap<>(4); |
134 | 133 |
|
135 | 134 | @Nullable
|
136 | 135 | private CorsConfiguration corsConfiguration;
|
@@ -262,20 +261,50 @@ public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter(
|
262 | 261 | * media types for resources being served. If the manager contains a path
|
263 | 262 | * extension strategy it will be checked for registered file extension.
|
264 | 263 | * @since 4.3
|
| 264 | + * @deprecated as of 5.2.4 in favor of using {@link #setMediaTypes(Map)} |
| 265 | + * with mappings possibly obtained from |
| 266 | + * {@link ContentNegotiationManager#getMediaTypeMappings()}. |
265 | 267 | */
|
| 268 | + @Deprecated |
266 | 269 | public void setContentNegotiationManager(@Nullable ContentNegotiationManager contentNegotiationManager) {
|
267 | 270 | this.contentNegotiationManager = contentNegotiationManager;
|
268 | 271 | }
|
269 | 272 |
|
270 | 273 | /**
|
271 | 274 | * Return the configured content negotiation manager.
|
272 | 275 | * @since 4.3
|
| 276 | + * @deprecated as of 5.2.4. |
273 | 277 | */
|
274 | 278 | @Nullable
|
| 279 | + @Deprecated |
275 | 280 | public ContentNegotiationManager getContentNegotiationManager() {
|
276 | 281 | return this.contentNegotiationManager;
|
277 | 282 | }
|
278 | 283 |
|
| 284 | + /** |
| 285 | + * Add mappings between file extensions, extracted from the filename of a |
| 286 | + * static {@link Resource}, and corresponding media type to set on the |
| 287 | + * response. |
| 288 | + * <p>Use of this method is typically not necessary since mappings are |
| 289 | + * otherwise determined via |
| 290 | + * {@link javax.servlet.ServletContext#getMimeType(String)} or via |
| 291 | + * {@link MediaTypeFactory#getMediaType(Resource)}. |
| 292 | + * @param mediaTypes media type mappings |
| 293 | + * @since 5.2.4 |
| 294 | + */ |
| 295 | + public void setMediaTypes(Map<String, MediaType> mediaTypes) { |
| 296 | + mediaTypes.forEach((ext, mediaType) -> |
| 297 | + this.mediaTypes.put(ext.toLowerCase(Locale.ENGLISH), mediaType)); |
| 298 | + } |
| 299 | + |
| 300 | + /** |
| 301 | + * Return the {@link #setMediaTypes(Map) configured} media types. |
| 302 | + * @since 5.2.4 |
| 303 | + */ |
| 304 | + public Map<String, MediaType> getMediaTypes() { |
| 305 | + return this.mediaTypes; |
| 306 | + } |
| 307 | + |
279 | 308 | /**
|
280 | 309 | * Specify the CORS configuration for resources served by this handler.
|
281 | 310 | * <p>By default this is not set in which allows cross-origin requests.
|
@@ -344,7 +373,17 @@ public void afterPropertiesSet() throws Exception {
|
344 | 373 | this.resourceRegionHttpMessageConverter = new ResourceRegionHttpMessageConverter();
|
345 | 374 | }
|
346 | 375 |
|
347 |
| - this.contentNegotiationStrategy = initContentNegotiationStrategy(); |
| 376 | + ContentNegotiationManager manager = getContentNegotiationManager(); |
| 377 | + if (manager != null) { |
| 378 | + setMediaTypes(manager.getMediaTypeMappings()); |
| 379 | + } |
| 380 | + |
| 381 | + @SuppressWarnings("deprecation") |
| 382 | + org.springframework.web.accept.PathExtensionContentNegotiationStrategy strategy = |
| 383 | + initContentNegotiationStrategy(); |
| 384 | + if (strategy != null) { |
| 385 | + setMediaTypes(strategy.getMediaTypes()); |
| 386 | + } |
348 | 387 | }
|
349 | 388 |
|
350 | 389 | private void resolveResourceLocations() {
|
@@ -412,26 +451,20 @@ protected void initAllowedLocations() {
|
412 | 451 | }
|
413 | 452 |
|
414 | 453 | /**
|
415 |
| - * Initialize the content negotiation strategy depending on the {@code ContentNegotiationManager} |
416 |
| - * setup and the availability of a {@code ServletContext}. |
417 |
| - * @see ServletPathExtensionContentNegotiationStrategy |
418 |
| - * @see PathExtensionContentNegotiationStrategy |
| 454 | + * Initialize the strategy to use to determine the media type for a resource. |
| 455 | + * @deprecated as of 5.2.4 this method returns {@code null}, and if a |
| 456 | + * sub-class returns an actual instance,the instance is used only as a |
| 457 | + * source of media type mappings, if it contains any. Please, use |
| 458 | + * {@link #setMediaTypes(Map)} instead, or if you need to change behavior, |
| 459 | + * you can override {@link #getMediaType(HttpServletRequest, Resource)}. |
419 | 460 | */
|
420 |
| - protected PathExtensionContentNegotiationStrategy initContentNegotiationStrategy() { |
421 |
| - Map<String, MediaType> mediaTypes = null; |
422 |
| - if (getContentNegotiationManager() != null) { |
423 |
| - PathExtensionContentNegotiationStrategy strategy = |
424 |
| - getContentNegotiationManager().getStrategy(PathExtensionContentNegotiationStrategy.class); |
425 |
| - if (strategy != null) { |
426 |
| - mediaTypes = new HashMap<>(strategy.getMediaTypes()); |
427 |
| - } |
428 |
| - } |
429 |
| - return (getServletContext() != null ? |
430 |
| - new ServletPathExtensionContentNegotiationStrategy(getServletContext(), mediaTypes) : |
431 |
| - new PathExtensionContentNegotiationStrategy(mediaTypes)); |
| 461 | + @Nullable |
| 462 | + @Deprecated |
| 463 | + @SuppressWarnings("deprecation") |
| 464 | + protected org.springframework.web.accept.PathExtensionContentNegotiationStrategy initContentNegotiationStrategy() { |
| 465 | + return null; |
432 | 466 | }
|
433 | 467 |
|
434 |
| - |
435 | 468 | /**
|
436 | 469 | * Processes a resource request.
|
437 | 470 | * <p>Checks for the existence of the requested resource in the configured list of locations.
|
@@ -659,17 +692,40 @@ protected boolean isInvalidPath(String path) {
|
659 | 692 |
|
660 | 693 | /**
|
661 | 694 | * Determine the media type for the given request and the resource matched
|
662 |
| - * to it. This implementation tries to determine the MediaType based on the |
663 |
| - * file extension of the Resource via |
664 |
| - * {@link ServletPathExtensionContentNegotiationStrategy#getMediaTypeForResource}. |
| 695 | + * to it. This implementation tries to determine the MediaType using one of |
| 696 | + * the following lookups based on the resource filename and its path |
| 697 | + * extension: |
| 698 | + * <ol> |
| 699 | + * <li>{@link javax.servlet.ServletContext#getMimeType(String)} |
| 700 | + * <li>{@link #getMediaTypes()} |
| 701 | + * <li>{@link MediaTypeFactory#getMediaType(String)} |
| 702 | + * </ol> |
665 | 703 | * @param request the current request
|
666 | 704 | * @param resource the resource to check
|
667 | 705 | * @return the corresponding media type, or {@code null} if none found
|
668 | 706 | */
|
669 | 707 | @Nullable
|
670 | 708 | protected MediaType getMediaType(HttpServletRequest request, Resource resource) {
|
671 |
| - return (this.contentNegotiationStrategy != null ? |
672 |
| - this.contentNegotiationStrategy.getMediaTypeForResource(resource) : null); |
| 709 | + MediaType result = null; |
| 710 | + String mimeType = request.getServletContext().getMimeType(resource.getFilename()); |
| 711 | + if (StringUtils.hasText(mimeType)) { |
| 712 | + result = MediaType.parseMediaType(mimeType); |
| 713 | + } |
| 714 | + if (result == null || MediaType.APPLICATION_OCTET_STREAM.equals(result)) { |
| 715 | + MediaType mediaType = null; |
| 716 | + String filename = resource.getFilename(); |
| 717 | + String ext = StringUtils.getFilenameExtension(filename); |
| 718 | + if (ext != null) { |
| 719 | + mediaType = this.mediaTypes.get(ext.toLowerCase(Locale.ENGLISH)); |
| 720 | + } |
| 721 | + if (mediaType == null) { |
| 722 | + mediaType = MediaTypeFactory.getMediaType(filename).orElse(null); |
| 723 | + } |
| 724 | + if (mediaType != null) { |
| 725 | + result = mediaType; |
| 726 | + } |
| 727 | + } |
| 728 | + return result; |
673 | 729 | }
|
674 | 730 |
|
675 | 731 | /**
|
|
0 commit comments