
org.springframework.web.util.UrlPathHelper Maven / Gradle / Ivy
/*
* Copyright 2002-2005 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 URL decoding.
*
* Used by AbstractUrlHandlerMapping, AbstractUrlMethodNameResolver
* and RequestContext for path matching and/or URI determination.
*
* @author Juergen Hoeller
* @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 {
/**
* Standard Servlet spec request attributes for include URI and paths.
*
If included via a RequestDispatcher, the current resource will see the
* original request. Its own URI and paths are exposed as request attributes.
*/
public static final String INCLUDE_URI_REQUEST_ATTRIBUTE = "javax.servlet.include.request_uri";
public static final String INCLUDE_CONTEXT_PATH_REQUEST_ATTRIBUTE = "javax.servlet.include.context_path";
public static final String INCLUDE_SERVLET_PATH_REQUEST_ATTRIBUTE = "javax.servlet.include.servlet_path";
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.
return requestUri.substring(contextPath.length());
}
else {
// Special case: rather unusual.
return requestUri;
}
}
/**
* 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(INCLUDE_SERVLET_PATH_REQUEST_ATTRIBUTE);
if (servletPath == null) {
servletPath = request.getServletPath();
}
return servletPath;
}
/**
* Return the context path for the given request, regarding 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(INCLUDE_CONTEXT_PATH_REQUEST_ATTRIBUTE);
if (contextPath == null) {
contextPath = request.getContextPath();
}
return decodeRequestString(request, contextPath);
}
/**
* Return the request URI for the given request, regarding 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(INCLUDE_URI_REQUEST_ATTRIBUTE);
if (uri == null) {
uri = request.getRequestURI();
}
uri = decodeRequestString(request, uri);
int semicolonIndex = uri.indexOf(';');
return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
}
/**
* Decode the given source string with a URLEncoder. The encoding will be taken
* from the request, falling back to the default "ISO-8859-1".
* @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
*/
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 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 = this.defaultEncoding;
}
return enc;
}
}