/*
* Copyright 2002-2021 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.util;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.RequestPath;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
Utility class to parse the path of an HttpServletRequest
to a RequestPath
and cache it in a request attribute for further access. This can then be used for URL path matching with PathPattern
s. Also includes helper methods to return either a previously resolved
String lookupPath or a previously parsed
RequestPath
depending on which is cached in request attributes.
Author: Rossen Stoyanchev Since: 5.3
/**
* Utility class to parse the path of an {@link HttpServletRequest} to a
* {@link RequestPath} and cache it in a request attribute for further access.
* This can then be used for URL path matching with
* {@link org.springframework.web.util.pattern.PathPattern PathPattern}s.
*
* <p>Also includes helper methods to return either a previously
* {@link UrlPathHelper#resolveAndCacheLookupPath resolved} String lookupPath
* or a previously {@link #parseAndCache parsed} {@code RequestPath} depending
* on which is cached in request attributes.
*
* @author Rossen Stoyanchev
* @since 5.3
*/
public abstract class ServletRequestPathUtils {
Name of Servlet request attribute that holds the parsed RequestPath
. /** Name of Servlet request attribute that holds the parsed {@link RequestPath}. */
public static final String PATH_ATTRIBUTE = ServletRequestPathUtils.class.getName() + ".PATH";
Parse the requestURI
of the request and its contextPath
to create a RequestPath
and cache it in the request attribute PATH_ATTRIBUTE
. This method ignores the
servletPath
and the pathInfo
. Therefore in case of a Servlet mapping by prefix, the RequestPath.pathWithinApplication()
will always include the Servlet prefix.
/**
* Parse the {@link HttpServletRequest#getRequestURI() requestURI} of the
* request and its {@code contextPath} to create a {@link RequestPath} and
* cache it in the request attribute {@link #PATH_ATTRIBUTE}.
*
* <p>This method ignores the {@link HttpServletRequest#getServletPath()
* servletPath} and the {@link HttpServletRequest#getPathInfo() pathInfo}.
* Therefore in case of a Servlet mapping by prefix, the
* {@link RequestPath#pathWithinApplication()} will always include the
* Servlet prefix.
*/
public static RequestPath parseAndCache(HttpServletRequest request) {
String requestUri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
requestUri = (requestUri != null ? requestUri : request.getRequestURI());
RequestPath requestPath = RequestPath.parse(requestUri, request.getContextPath());
request.setAttribute(PATH_ATTRIBUTE, requestPath);
return requestPath;
}
Return a previously
parsed and cached RequestPath
. Throws: - IllegalArgumentException – if not found
/**
* Return a {@link #parseAndCache previously} parsed and cached {@code RequestPath}.
* @throws IllegalArgumentException if not found
*/
public static RequestPath getParsedRequestPath(ServletRequest request) {
RequestPath path = (RequestPath) request.getAttribute(PATH_ATTRIBUTE);
Assert.notNull(path, "Expected parsed RequestPath in request attribute \"" + PATH_ATTRIBUTE + "\".");
return path;
}
Set the cached, parsed RequestPath
to the given value. Params: - requestPath – the value to set to, or if
null
the cache value is cleared. - request – the current request
Since: 5.3.3
/**
* Set the cached, parsed {@code RequestPath} to the given value.
* @param requestPath the value to set to, or if {@code null} the cache
* value is cleared.
* @param request the current request
* @since 5.3.3
*/
public static void setParsedRequestPath(@Nullable RequestPath requestPath, ServletRequest request) {
if (requestPath != null) {
request.setAttribute(PATH_ATTRIBUTE, requestPath);
}
else {
request.removeAttribute(PATH_ATTRIBUTE);
}
}
Check for a previously
parsed and cached RequestPath
. /**
* Check for a {@link #parseAndCache previously} parsed and cached {@code RequestPath}.
*/
public static boolean hasParsedRequestPath(ServletRequest request) {
return (request.getAttribute(PATH_ATTRIBUTE) != null);
}
/**
* Remove the request attribute {@link #PATH_ATTRIBUTE} that holds a
* {@link #parseAndCache previously} parsed and cached {@code RequestPath}.
*/
public static void clearParsedRequestPath(ServletRequest request) {
request.removeAttribute(PATH_ATTRIBUTE);
}
// Methods to select either parsed RequestPath or resolved String lookupPath
Return the pre-resolved
String lookupPath or the
pre-parsed
RequestPath
. In Spring MVC, when at least one HandlerMapping
has parsed PathPatterns
enabled, the DispatcherServlet
eagerly parses and caches the RequestPath
and the same can be also done earlier with
ServletRequestPathFilter
. In other cases where HandlerMapping
s use String pattern matching with PathMatcher
, the String lookupPath is resolved separately by each HandlerMapping
.
Params: - request – the current request
Throws: - IllegalArgumentException – if neither is available
Returns: a String lookupPath or a RequestPath
/**
* Return the {@link UrlPathHelper#resolveAndCacheLookupPath pre-resolved}
* String lookupPath or the {@link #parseAndCache(HttpServletRequest)
* pre-parsed} {@code RequestPath}.
* <p>In Spring MVC, when at least one {@code HandlerMapping} has parsed
* {@code PathPatterns} enabled, the {@code DispatcherServlet} eagerly parses
* and caches the {@code RequestPath} and the same can be also done earlier with
* {@link org.springframework.web.filter.ServletRequestPathFilter
* ServletRequestPathFilter}. In other cases where {@code HandlerMapping}s
* use String pattern matching with {@code PathMatcher}, the String
* lookupPath is resolved separately by each {@code HandlerMapping}.
* @param request the current request
* @return a String lookupPath or a {@code RequestPath}
* @throws IllegalArgumentException if neither is available
*/
public static Object getCachedPath(ServletRequest request) {
// The RequestPath is pre-parsed if any HandlerMapping uses PathPatterns.
// The lookupPath is re-resolved or cleared per HandlerMapping.
// So check for lookupPath first.
String lookupPath = (String) request.getAttribute(UrlPathHelper.PATH_ATTRIBUTE);
if (lookupPath != null) {
return lookupPath;
}
RequestPath requestPath = (RequestPath) request.getAttribute(PATH_ATTRIBUTE);
if (requestPath != null) {
return requestPath.pathWithinApplication();
}
throw new IllegalArgumentException(
"Neither a pre-parsed RequestPath nor a pre-resolved String lookupPath is available.");
}
Variant of getCachedPath(ServletRequest)
that returns the path for request mapping as a String. If the cached path is a
pre-parsed
RequestPath
then the returned String path value is encoded and with path parameters removed.
If the cached path is a
pre-resolved
String lookupPath, then the returned String path value depends on how UrlPathHelper
that resolved is configured.
Params: - request – the current request
Returns: the full request mapping path as a String
/**
* Variant of {@link #getCachedPath(ServletRequest)} that returns the path
* for request mapping as a String.
* <p>If the cached path is a {@link #parseAndCache(HttpServletRequest)
* pre-parsed} {@code RequestPath} then the returned String path value is
* encoded and with path parameters removed.
* <p>If the cached path is a {@link UrlPathHelper#resolveAndCacheLookupPath
* pre-resolved} String lookupPath, then the returned String path value
* depends on how {@link UrlPathHelper} that resolved is configured.
* @param request the current request
* @return the full request mapping path as a String
*/
public static String getCachedPathValue(ServletRequest request) {
Object path = getCachedPath(request);
if (path instanceof PathContainer) {
String value = ((PathContainer) path).value();
path = UrlPathHelper.defaultInstance.removeSemicolonContent(value);
}
return (String) path;
}
Check for a previously
resolved
String lookupPath or a previously parsed
RequestPath
. Params: - request – the current request
Returns: whether a pre-resolved or pre-parsed path is available
/**
* Check for a previously {@link UrlPathHelper#resolveAndCacheLookupPath
* resolved} String lookupPath or a previously {@link #parseAndCache parsed}
* {@code RequestPath}.
* @param request the current request
* @return whether a pre-resolved or pre-parsed path is available
*/
public static boolean hasCachedPath(ServletRequest request) {
return (request.getAttribute(PATH_ATTRIBUTE) != null ||
request.getAttribute(UrlPathHelper.PATH_ATTRIBUTE) != null);
}
}