- /*
- * Copyright 2002-2004 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;
- /**
- * Helper class for URL path matching. Provides support for URL paths
- * in ServletDispatcher includes, and support for URL decoding.
- *
- * <p>Used by AbstractUrlHandlerMapping and AbstractMethodNameResolver.
- *
- * @author Juergen Hoeller
- * @since 14.01.2004
- * @see org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
- * @see org.springframework.web.servlet.mvc.multiaction.AbstractUrlMethodNameResolver
- */
- public class UrlPathHelper {
- /**
- * Standard servlet spec request attributes for include URI and paths.
- * <p>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 <i>undecoded</i> by the Servlet API,
- * in contrast to the servlet path.
- * <p>Uses either the request encoding or the default encoding according
- * to the Servlet spec (ISO-8859-1).
- * <p>Note: Setting this to true requires J2SE 1.4, as J2SE 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)
- */
- 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.
- * <p>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.
- * <p>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.
- * <p>Regards include request URL if called within a RequestDispatcher include.
- * <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
- * <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
- * <p>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) {
- return getPathWithinApplication(request).substring(getServletPath(request).length());
- }
- /**
- * Return the path within the web application for the given request.
- * <p>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) {
- return getRequestUri(request).substring(getContextPath(request).length());
- }
- /**
- * Return the servlet path for the given request, regarding an include request
- * URL if called within a RequestDispatcher include.
- * <p>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.
- * <p>As the value returned by request.getContextPath() is <i>not</i> 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.
- * <p>As the value returned by request.getRequestURI() is <i>not</i> decoded by
- * the servlet container, this method will decode it.
- * <p>The URI that the web container resolves <i>should</i> 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 {
- return URLDecoder.decode(source, enc);
- }
- catch (UnsupportedEncodingException ex) {
- logger.warn("Could not decode request string [" + source +
- "] with encoding '" + enc + "': using platform default");
- return URLDecoder.decode(source);
- }
- }
- return source;
- }
- /**
- * Determine the encoding for the given request.
- * Can be overridden in subclasses.
- * <p>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;
- }
- }