diff --git a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java index 46a6711e5db..4b1c998547d 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont if (request == null) { return null; } + // Ignore LOOKUP_PATH attribute, use our own "fixed" UrlPathHelper with decoding off String path = this.urlPathHelper.getLookupPathForRequest(request); String extension = UriUtils.extractFileExtension(path); return (StringUtils.hasText(extension) ? extension.toLowerCase(Locale.ENGLISH) : null); diff --git a/spring-web/src/main/java/org/springframework/web/cors/UrlBasedCorsConfigurationSource.java b/spring-web/src/main/java/org/springframework/web/cors/UrlBasedCorsConfigurationSource.java index 60755e7e200..b74018961f4 100644 --- a/spring-web/src/main/java/org/springframework/web/cors/UrlBasedCorsConfigurationSource.java +++ b/spring-web/src/main/java/org/springframework/web/cors/UrlBasedCorsConfigurationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,9 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource private UrlPathHelper urlPathHelper = new UrlPathHelper(); + @Nullable + private String lookupPathAttributeName; + /** * Set the PathMatcher implementation to use for matching URL paths @@ -72,6 +75,17 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource this.urlPathHelper.setUrlDecode(urlDecode); } + /** + * Optionally configure the name of the attribute that caches the lookupPath. + * This is used to make the call to + * {@link UrlPathHelper#getLookupPathForRequest(HttpServletRequest, String)} + * @param lookupPathAttributeName the request attribute to check + * @since 5.2 + */ + public void setLookupPathAttributeName(@Nullable String lookupPathAttributeName) { + this.lookupPathAttributeName = lookupPathAttributeName; + } + /** * Shortcut to same property on underlying {@link #setUrlPathHelper UrlPathHelper}. * @see org.springframework.web.util.UrlPathHelper#setRemoveSemicolonContent(boolean) @@ -117,7 +131,7 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource @Override @Nullable public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { - String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); + String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, this.lookupPathAttributeName); for (Map.Entry entry : this.corsConfigurations.entrySet()) { if (this.pathMatcher.match(entry.getKey(), lookupPath)) { return entry.getValue(); diff --git a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java index 1494c133fe8..b371aca7953 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java +++ b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -175,6 +175,26 @@ public class UrlPathHelper { } } + /** + * Variant of {@link #getLookupPathForRequest(HttpServletRequest)} that + * automates checking for a previously computed lookupPath saved as a + * request attribute. The attribute is only used for lookup purposes. + * @param request current HTTP request + * @param lookupPathAttributeName the request attribute to check + * @return the lookup path + * @since 5.2 + * @see org.springframework.web.servlet.HandlerMapping#LOOKUP_PATH + */ + public String getLookupPathForRequest(HttpServletRequest request, @Nullable String lookupPathAttributeName) { + if (lookupPathAttributeName != null) { + String result = (String) request.getAttribute(lookupPathAttributeName); + if (result != null) { + return result; + } + } + return getLookupPathForRequest(request); + } + /** * Return the path within the servlet mapping for the given request, * i.e. the part of the request's URL beyond the part that called the servlet, diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java index c10eb239999..18377f0cd97 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java @@ -62,6 +62,15 @@ public interface HandlerMapping { */ String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler"; + /** + * Name of the {@link HttpServletRequest} attribute that contains the path + * used to look up the matching handler, which depending on the configured + * {@link org.springframework.web.util.UrlPathHelper} could be the full path + * or without the context path, decoded or not, etc. + * @since 5.2 + */ + String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath"; + /** * Name of the {@link HttpServletRequest} attribute that contains the path * within the handler mapping, in case of a pattern match, or the full diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java index bea11de0467..bdb0600650b 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java @@ -212,6 +212,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport source.setCorsConfigurations(corsConfigurations); source.setPathMatcher(this.pathMatcher); source.setUrlPathHelper(this.urlPathHelper); + source.setLookupPathAttributeName(LOOKUP_PATH); this.corsConfigurationSource = source; } else { @@ -463,7 +464,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); - String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); + String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java index cf4f430ca69..f34f457c7a7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java @@ -355,6 +355,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); + request.setAttribute(LOOKUP_PATH, lookupPath); this.mappingRegistry.acquireReadLock(); try { HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java index 746d0a34978..7b10d0881bb 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java @@ -120,6 +120,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i @Nullable protected Object getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); + request.setAttribute(LOOKUP_PATH, lookupPath); Object handler = lookupHandler(lookupPath, request); if (handler == null) { // We need to care for the default handler directly, since we need to @@ -291,7 +292,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i @Override @Nullable public RequestMatchResult match(HttpServletRequest request, String pattern) { - String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); + String lookupPath = getUrlPathHelper().getLookupPathForRequest(request, LOOKUP_PATH); if (getPathMatcher().match(pattern, lookupPath)) { return new RequestMatchResult(pattern, lookupPath, getPathMatcher()); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/UrlFilenameViewController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/UrlFilenameViewController.java index b000dbbe21c..9782e5a92e8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/UrlFilenameViewController.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/UrlFilenameViewController.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -110,7 +110,7 @@ public class UrlFilenameViewController extends AbstractUrlViewController { protected String extractOperableUrl(HttpServletRequest request) { String urlPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); if (!StringUtils.hasText(urlPath)) { - urlPath = getUrlPathHelper().getLookupPathForRequest(request); + urlPath = getUrlPathHelper().getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH); } return urlPath; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/WebContentInterceptor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/WebContentInterceptor.java index 9350956fb79..90b94aec992 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/WebContentInterceptor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/WebContentInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.util.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.util.PathMatcher; import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.support.WebContentGenerator; import org.springframework.web.util.UrlPathHelper; @@ -169,7 +170,7 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle checkRequest(request); - String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); + String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH); CacheControl cacheControl = lookupCacheControl(lookupPath); Integer cacheSeconds = lookupCacheSeconds(lookupPath); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java index ca3691b8085..00d2eff8f42 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java @@ -31,6 +31,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import org.springframework.util.StringUtils; +import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.util.UrlPathHelper; /** @@ -212,7 +213,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition matches = getMatchingPatterns(lookupPath); return !matches.isEmpty() ? new PatternsRequestCondition(new LinkedHashSet<>(matches), this) : null; } @@ -287,7 +288,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition patternComparator = this.pathMatcher.getPatternComparator(lookupPath); Iterator iterator = this.patterns.iterator(); Iterator iteratorOther = other.patterns.iterator(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java index 1e9a421a9d6..3e1a772a8ef 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -340,7 +340,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi return null; } Set patterns = matchingInfo.getPatternsCondition().getPatterns(); - String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); + String lookupPath = getUrlPathHelper().getLookupPathForRequest(request, LOOKUP_PATH); return new RequestMatchResult(patterns.iterator().next(), lookupPath, getPathMatcher()); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java index f3110cba7dc..6806938854d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import org.springframework.util.StringUtils; +import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.util.UrlPathHelper; @@ -180,7 +181,7 @@ public class ResourceUrlProvider implements ApplicationListener