org.springframework.web.util.UrlPathHelper Maven / Gradle / Ivy
/*
* Copyright 2002-2006 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
*
* http://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 java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.JdkVersion;
import org.springframework.util.StringUtils;
/**
* Helper class for URL path matching. Provides support for URL paths in
* RequestDispatcher includes and support for consistent URL decoding.
*
* Used by AbstractUrlHandlerMapping, AbstractUrlMethodNameResolver
* and RequestContext for path matching and/or URI determination.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @since 14.01.2004
* @see org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
* @see org.springframework.web.servlet.mvc.multiaction.AbstractUrlMethodNameResolver
* @see org.springframework.web.servlet.support.RequestContext
*/
public class UrlPathHelper {
/**
* @deprecated as of Spring 2.0, in favor of WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE
* @see org.springframework.web.util.WebUtils#INCLUDE_REQUEST_URI_ATTRIBUTE
*/
public static final String INCLUDE_URI_REQUEST_ATTRIBUTE = WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE;
/**
* @deprecated as of Spring 2.0, in favor of WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE
* @see org.springframework.web.util.WebUtils#INCLUDE_CONTEXT_PATH_ATTRIBUTE
*/
public static final String INCLUDE_CONTEXT_PATH_REQUEST_ATTRIBUTE = WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE;
/**
* @deprecated as of Spring 2.0, in favor of WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE
* @see org.springframework.web.util.WebUtils#INCLUDE_SERVLET_PATH_ATTRIBUTE
*/
public static final String INCLUDE_SERVLET_PATH_REQUEST_ATTRIBUTE = WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE;
private final Log logger = LogFactory.getLog(getClass());
private boolean alwaysUseFullPath = false;
private boolean urlDecode = false;
private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
/**
* Set if URL lookup should always use full path within current servlet
* context. Else, the path within the current servlet mapping is used
* if applicable (i.e. in the case of a ".../*" servlet mapping in web.xml).
* Default is "false".
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
this.alwaysUseFullPath = alwaysUseFullPath;
}
/**
* Set if context path and request URI should be URL-decoded.
* Both are returned undecoded by the Servlet API,
* in contrast to the servlet path.
*
Uses either the request encoding or the default encoding according
* to the Servlet spec (ISO-8859-1).
*
Note: Setting this to "true" requires JDK 1.4 if the encoding differs
* from the VM's platform default encoding, as JDK 1.3's URLDecoder class
* does not offer a way to specify the encoding.
* @see #getServletPath
* @see #getContextPath
* @see #getRequestUri
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
* @see javax.servlet.ServletRequest#getCharacterEncoding
* @see java.net.URLDecoder#decode(String, String)
* @see java.net.URLDecoder#decode(String)
*/
public void setUrlDecode(boolean urlDecode) {
this.urlDecode = urlDecode;
}
/**
* Set the default character encoding to use for URL decoding.
* Default is ISO-8859-1, according to the Servlet spec.
*
If the request specifies a character encoding itself, the request
* encoding will override this setting. This also allows for generically
* overriding the character encoding in a filter that invokes the
* ServletRequest.setCharacterEncoding method.
* @param defaultEncoding the character encoding to use
* @see #determineEncoding
* @see javax.servlet.ServletRequest#getCharacterEncoding
* @see javax.servlet.ServletRequest#setCharacterEncoding
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
*/
public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
}
/**
* Return the default character encoding to use for URL decoding.
*/
protected String getDefaultEncoding() {
return defaultEncoding;
}
/**
* Return the mapping lookup path for the given request, within the current
* servlet mapping if applicable, else within the web application.
*
Regards include request URL if called within a RequestDispatcher include.
* @param request current HTTP request
* @return the lookup path
* @see #getPathWithinApplication
* @see #getPathWithinServletMapping
*/
public String getLookupPathForRequest(HttpServletRequest request) {
// Always use full path within current servlet context?
if (this.alwaysUseFullPath) {
return getPathWithinApplication(request);
}
// Else, use path within current servlet mapping if applicable
String rest = getPathWithinServletMapping(request);
if (!"".equals(rest)) {
return rest;
}
else {
return getPathWithinApplication(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,
* or "" if the whole URL has been used to identify the servlet.
*
Regards include request URL if called within a RequestDispatcher include.
*
E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
*
E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
*
E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "".
* @param request current HTTP request
* @return the path within the servlet mapping, or ""
*/
public String getPathWithinServletMapping(HttpServletRequest request) {
String pathWithinApp = getPathWithinApplication(request);
String servletPath = getServletPath(request);
if (pathWithinApp.startsWith(servletPath)) {
// Normal case: URI contains servlet path.
return pathWithinApp.substring(servletPath.length());
}
else {
// Special case: URI is different from servlet path.
// Can happen e.g. with index page: URI="/", servletPath="/index.html"
// Use servlet path in this case, as it indicates the actual target path.
return servletPath;
}
}
/**
* Return the path within the web application for the given request.
*
Regards include request URL if called within a RequestDispatcher include.
* @param request current HTTP request
* @return the path within the web application
*/
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
// Normal case: URI contains context path.
String path = requestUri.substring(contextPath.length());
return (StringUtils.hasText(path) ? path : "/");
}
else {
// Special case: rather unusual.
return requestUri;
}
}
/**
* Return the request URI for the given request, detecting an include request
* URL if called within a RequestDispatcher include.
*
As the value returned by request.getRequestURI()
is not
* decoded by the servlet container, this method will decode it.
*
The URI that the web container resolves should be correct, but some
* containers like JBoss/Jetty incorrectly include ";" strings like ";jsessionid"
* in the URI. This method cuts off such incorrect appendices.
* @param request current HTTP request
* @return the request URI
*/
public String getRequestUri(HttpServletRequest request) {
String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
if (uri == null) {
uri = request.getRequestURI();
}
return decodeAndCleanUriString(request, uri);
}
/**
* Return the context path for the given request, detecting an include request
* URL if called within a RequestDispatcher include.
*
As the value returned by request.getContextPath()
is not
* decoded by the servlet container, this method will decode it.
* @param request current HTTP request
* @return the context path
*/
public String getContextPath(HttpServletRequest request) {
String contextPath = (String) request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE);
if (contextPath == null) {
contextPath = request.getContextPath();
}
return decodeRequestString(request, contextPath);
}
/**
* Return the servlet path for the given request, regarding an include request
* URL if called within a RequestDispatcher include.
*
As the value returned by request.getServletPath() is already decoded by
* the servlet container, this method will not attempt to decode it.
* @param request current HTTP request
* @return the servlet path
*/
public String getServletPath(HttpServletRequest request) {
String servletPath = (String) request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE);
if (servletPath == null) {
servletPath = request.getServletPath();
}
return servletPath;
}
/**
* Return the request URI for root of the given request. If this is a forwarded request,
* correctly resolves to the request URI of the original request. Relies on the Servlet
* 2.4 'forward' attributes. These attributes may be set by other components when
* running in a Servlet 2.3- environment.
*/
public String getOriginatingRequestUri(HttpServletRequest request) {
String uri = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE);
if (uri == null) {
uri = request.getRequestURI();
}
return decodeAndCleanUriString(request, uri);
}
/**
* Return the context path for the given request, detecting an include request
* URL if called within a RequestDispatcher include.
*
As the value returned by request.getContextPath()
is not
* decoded by the servlet container, this method will decode it.
* @param request current HTTP request
* @return the context path
*/
public String getOriginatingContextPath(HttpServletRequest request) {
String contextPath = (String) request.getAttribute(WebUtils.FORWARD_CONTEXT_PATH_ATTRIBUTE);
if (contextPath == null) {
contextPath = request.getContextPath();
}
return decodeRequestString(request, contextPath);
}
/**
* Return the request URI for root of the given request. If this is a forwarded request,
* correctly resolves to the request URI of the original request. Relies on the Servlet
* 2.4 'forward' attributes. These attributes may be set by other components when
* running in a Servlet 2.3- environment.
*/
public String getOriginatingQueryString(HttpServletRequest request) {
String queryString = (String) request.getAttribute(WebUtils.FORWARD_QUERY_STRING_ATTRIBUTE);
if (queryString == null) {
queryString = request.getQueryString();
}
return queryString;
}
/**
* Decode the supplied URI string and strips any extraneous portion after a ';'.
*/
private String decodeAndCleanUriString(HttpServletRequest request, String uri) {
uri = decodeRequestString(request, uri);
int semicolonIndex = uri.indexOf(';');
return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
}
/**
* Decode the given source string with a URLDecoder. The encoding will be taken
* from the request, falling back to the default "ISO-8859-1".
*
Default implementation uses URLDecoder.decode(input, enc)
* on JDK 1.4+, falling back to URLDecoder.decode(input)
* (which uses the platform default encoding) on JDK 1.3.
* @param request current HTTP request
* @param source the String to decode
* @return the decoded String
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
* @see javax.servlet.ServletRequest#getCharacterEncoding
* @see java.net.URLDecoder#decode(String, String)
* @see java.net.URLDecoder#decode(String)
*/
public String decodeRequestString(HttpServletRequest request, String source) {
if (this.urlDecode) {
String enc = determineEncoding(request);
try {
if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_14) {
throw new UnsupportedEncodingException("JDK 1.3 URLDecoder does not support custom encoding");
}
return URLDecoder.decode(source, enc);
}
catch (UnsupportedEncodingException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not decode request string [" + source + "] with encoding '" + enc +
"': falling back to platform default encoding; exception message: " + ex.getMessage());
}
return URLDecoder.decode(source);
}
}
return source;
}
/**
* Determine the encoding for the given request.
* Can be overridden in subclasses.
*
The default implementation checks the request encoding,
* falling back to the default encoding specified for this resolver.
* @param request current HTTP request
* @return the encoding for the request (never null
)
* @see javax.servlet.ServletRequest#getCharacterEncoding
* @see #setDefaultEncoding
*/
protected String determineEncoding(HttpServletRequest request) {
String enc = request.getCharacterEncoding();
if (enc == null) {
enc = getDefaultEncoding();
}
return enc;
}
}