cn.ocoop.framework.common.util.WebUtils Maven / Gradle / Ivy
package cn.ocoop.framework.common.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class WebUtils {
public static final String INCLUDE_REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri";
public static final String INCLUDE_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.include.context_path";
public static final String INCLUDE_SERVLET_PATH_ATTRIBUTE = "javax.servlet.include.servlet_path";
public static final String INCLUDE_PATH_INFO_ATTRIBUTE = "javax.servlet.include.path_info";
public static final String INCLUDE_QUERY_STRING_ATTRIBUTE = "javax.servlet.include.query_string";
/**
* Standard Servlet 2.4+ spec request attributes for forward URI and paths.
* If forwarded to via a RequestDispatcher, the current resource will see its
* own URI and paths. The originating URI and paths are exposed as request attributes.
*/
public static final String FORWARD_REQUEST_URI_ATTRIBUTE = "javax.servlet.forward.request_uri";
public static final String FORWARD_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.forward.context_path";
public static final String FORWARD_SERVLET_PATH_ATTRIBUTE = "javax.servlet.forward.servlet_path";
public static final String FORWARD_PATH_INFO_ATTRIBUTE = "javax.servlet.forward.path_info";
public static final String FORWARD_QUERY_STRING_ATTRIBUTE = "javax.servlet.forward.query_string";
/**
* Default character encoding to use when request.getCharacterEncoding
* returns null
, according to the Servlet spec.
*
* @see ServletRequest#getCharacterEncoding
*/
public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
/**
* Return the path within the web application for the given request.
* Detects include request URL if called within a RequestDispatcher include.
*
* For example, for a request to URL
*
* http://www.somehost.com/myapp/my/url.jsp
,
*
* for an application deployed to /mayapp
(the application's context path), this method would return
*
* /my/url.jsp
.
*
* @param request current HTTP request
* @return the path within the web application
*/
public static 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.isNotBlank(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 static String getRequestUri(HttpServletRequest request) {
String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
if (uri == null) {
uri = request.getRequestURI();
}
return normalize(decodeAndCleanUriString(request, uri));
}
/**
* Normalize a relative URI path that may have relative values ("/./",
* "/../", and so on ) it it. WARNING - This method is
* useful only for normalizing application-generated paths. It does not
* try to perform security checks for malicious input.
* Normalize operations were was happily taken from org.apache.catalina.util.RequestUtil in
* Tomcat trunk, r939305
*
* @param path Relative path to be normalized
* @return normalized path
*/
public static String normalize(String path) {
return normalize(path, true);
}
/**
* Normalize a relative URI path that may have relative values ("/./",
* "/../", and so on ) it it. WARNING - This method is
* useful only for normalizing application-generated paths. It does not
* try to perform security checks for malicious input.
* Normalize operations were was happily taken from org.apache.catalina.util.RequestUtil in
* Tomcat trunk, r939305
*
* @param path Relative path to be normalized
* @param replaceBackSlash Should '\\' be replaced with '/'
* @return normalized path
*/
private static String normalize(String path, boolean replaceBackSlash) {
if (path == null)
return null;
// Create a place for the normalized path
String normalized = path;
if (replaceBackSlash && normalized.indexOf('\\') >= 0)
normalized = normalized.replace('\\' , '/');
if (normalized.equals("/."))
return "/";
// Add a leading "/" if necessary
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
return (null); // Trying to go outside our context
int index2 = normalized.lastIndexOf('/' , index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Return the normalized path that we have completed
return (normalized);
}
/**
* Decode the supplied URI string and strips any extraneous portion after a ';'.
*
* @param request the incoming HttpServletRequest
* @param uri the application's URI string
* @return the supplied URI string stripped of any extraneous portion after a ';'.
*/
private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
uri = decodeRequestString(request, uri);
int semicolonIndex = uri.indexOf(';');
return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : 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 static String getContextPath(HttpServletRequest request) {
String contextPath = (String) request.getAttribute(INCLUDE_CONTEXT_PATH_ATTRIBUTE);
if (contextPath == null) {
contextPath = request.getContextPath();
}
contextPath = normalize(decodeRequestString(request, contextPath));
if ("/".equals(contextPath)) {
// the normalize method will return a "/" and includes on Jetty, will also be a "/".
contextPath = "";
}
return contextPath;
}
/**
* Decode the given source string with a URLDecoder. The encoding will be taken
* from the request, falling back to the default "ISO-8859-1".
*
The default implementation uses URLDecoder.decode(input, enc)
.
*
* @param request current HTTP request
* @param source the String to decode
* @return the decoded String
* @see #DEFAULT_CHARACTER_ENCODING
* @see ServletRequest#getCharacterEncoding
* @see URLDecoder#decode(String, String)
* @see URLDecoder#decode(String)
*/
@SuppressWarnings({"deprecation"})
public static String decodeRequestString(HttpServletRequest request, String source) {
String enc = determineEncoding(request);
try {
return URLDecoder.decode(source, enc);
} catch (UnsupportedEncodingException ex) {
if (log.isWarnEnabled()) {
log.warn("Could not decode request string [" + source + "] with encoding '" + enc +
"': falling back to platform default encoding; exception message: " + ex.getMessage());
}
return URLDecoder.decode(source);
}
}
/**
* Determine the encoding for the given request.
* Can be overridden in subclasses.
*
The default implementation checks the request's
* {@link ServletRequest#getCharacterEncoding() character encoding}, and if that
* null
, falls back to the {@link #DEFAULT_CHARACTER_ENCODING}.
*
* @param request current HTTP request
* @return the encoding for the request (never null
)
* @see ServletRequest#getCharacterEncoding()
*/
protected static String determineEncoding(HttpServletRequest request) {
String enc = request.getCharacterEncoding();
if (enc == null) {
enc = DEFAULT_CHARACTER_ENCODING;
}
return enc;
}
/**
* A convenience method that merely casts the incoming ServletRequest
to an
* HttpServletRequest
:
*
* return (HttpServletRequest)request;
*
* Logic could be changed in the future for logging or throwing an meaningful exception in
* non HTTP request environments (e.g. Portlet API).
*
* @param request the incoming ServletRequest
* @return the request
argument casted to an HttpServletRequest
.
*/
public static HttpServletRequest toHttp(ServletRequest request) {
return (HttpServletRequest) request;
}
/**
* A convenience method that merely casts the incoming ServletResponse
to an
* HttpServletResponse
:
*
* return (HttpServletResponse)response;
*
* Logic could be changed in the future for logging or throwing an meaningful exception in
* non HTTP request environments (e.g. Portlet API).
*
* @param response the outgoing ServletResponse
* @return the response
argument casted to an HttpServletResponse
.
*/
public static HttpServletResponse toHttp(ServletResponse response) {
return (HttpServletResponse) response;
}
/**
* Convenience method that returns a request parameter value, first running it through
*
* @param request the servlet request.
* @param paramName the parameter name.
* @return the clean param value, or null if the param does not exist or is empty.
*/
public static String getCleanParam(ServletRequest request, String paramName) {
return clean(request.getParameter(paramName));
}
private static String clean(String in) {
String out = in;
if (in != null) {
out = in.trim();
if (out.equals("")) {
out = null;
}
}
return out;
}
public static String removeParam(String queryString, String name) {
if (StringUtils.isBlank(queryString)) return "";
Pattern compile = Pattern.compile("(?i)" + name + "=[^&]*&?");
Matcher matcher = compile.matcher(queryString);
while (matcher.find()) {
queryString = matcher.replaceFirst("");
matcher.reset(queryString);
}
queryString = StringUtils.removeEnd(queryString, "&");
queryString = StringUtils.removeStart(queryString, "?");
return StringUtils.isNotBlank(queryString) ? "?" + queryString : "";
}
}