Skip to content

Commit

Permalink
Shared read-only instances of UrlPathHelper
Browse files Browse the repository at this point in the history
UrlPathHelper is often created and used without customizations or with
the same customizations. This commit introduces re-usable, instances.
Effectively a backport of commit 23233c.

Closes gh-25690
  • Loading branch information
rstoyanchev committed Sep 8, 2020
1 parent caa22b7 commit bdcb189
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 42 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -83,8 +83,6 @@ public class MockHttpServletRequestBuilder

private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");

private static final UrlPathHelper urlPathHelper = new UrlPathHelper();


private final String method;

Expand Down Expand Up @@ -697,7 +695,7 @@ private void updatePathRequestProperties(MockHttpServletRequest request, String
}
String extraPath = requestUri.substring(this.contextPath.length() + this.servletPath.length());
this.pathInfo = (StringUtils.hasText(extraPath) ?
urlPathHelper.decodeRequestString(request, extraPath) : null);
UrlPathHelper.defaultInstance.decodeRequestString(request, extraPath) : null);
}
request.setPathInfo(this.pathInfo);
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -44,8 +44,6 @@ final class PatternMappingFilterProxy implements Filter {

private static final String PATH_MAPPING_PATTERN = "/*";

private static final UrlPathHelper urlPathHelper = new UrlPathHelper();

private final Filter delegate;

/** Patterns that require an exact match, e.g. "/test" */
Expand Down Expand Up @@ -95,7 +93,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
throws IOException, ServletException {

HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestPath = urlPathHelper.getPathWithinApplication(httpRequest);
String requestPath = UrlPathHelper.defaultInstance.getPathWithinApplication(httpRequest);

if (matches(requestPath)) {
this.delegate.doFilter(request, response, filterChain);
Expand Down
Expand Up @@ -75,20 +75,11 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
}


private final UrlPathHelper pathHelper;

private boolean removeOnly;

private boolean relativeRedirects;


public ForwardedHeaderFilter() {
this.pathHelper = new UrlPathHelper();
this.pathHelper.setUrlDecode(false);
this.pathHelper.setRemoveSemicolonContent(false);
}


/**
* Enables mode in which any "Forwarded" or "X-Forwarded-*" headers are
* removed only and the information in them ignored.
Expand Down Expand Up @@ -146,7 +137,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
filterChain.doFilter(theRequest, response);
}
else {
HttpServletRequest theRequest = new ForwardedHeaderExtractingRequest(request, this.pathHelper);
HttpServletRequest theRequest = new ForwardedHeaderExtractingRequest(request);
HttpServletResponse theResponse = (this.relativeRedirects ?
RelativeRedirectResponseWrapper.wrapIfNecessary(response, HttpStatus.SEE_OTHER) :
new ForwardedHeaderExtractingResponse(response, theRequest));
Expand Down Expand Up @@ -219,7 +210,7 @@ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRem

private final String requestUrl;

public ForwardedHeaderExtractingRequest(HttpServletRequest request, UrlPathHelper pathHelper) {
public ForwardedHeaderExtractingRequest(HttpServletRequest request) {
super(request);

HttpRequest httpRequest = new ServletServerHttpRequest(request);
Expand All @@ -233,7 +224,7 @@ public ForwardedHeaderExtractingRequest(HttpServletRequest request, UrlPathHelpe

String prefix = getForwardedPrefix(request);
this.contextPath = (prefix != null ? prefix : request.getContextPath());
this.requestUri = this.contextPath + pathHelper.getPathWithinApplication(request);
this.requestUri = this.contextPath + UrlPathHelper.rawPathInstance.getPathWithinApplication(request);
this.requestUrl = this.scheme + "://" + this.host + (port == -1 ? "" : ":" + port) + this.requestUri;
}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
Expand All @@ -22,11 +22,13 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -69,6 +71,8 @@ public class UrlPathHelper {

private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;

private boolean readOnly = false;


/**
* Whether URL lookups should always use the full path within the current
Expand All @@ -80,6 +84,7 @@ public class UrlPathHelper {
* <p>By default this is set to "false".
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
checkReadOnly();
this.alwaysUseFullPath = alwaysUseFullPath;
}

Expand All @@ -102,6 +107,7 @@ public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
* @see java.net.URLDecoder#decode(String, String)
*/
public void setUrlDecode(boolean urlDecode) {
checkReadOnly();
this.urlDecode = urlDecode;
}

Expand All @@ -118,13 +124,15 @@ public boolean isUrlDecode() {
* <p>Default is "true".
*/
public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
checkReadOnly();
this.removeSemicolonContent = removeSemicolonContent;
}

/**
* Whether configured to remove ";" (semicolon) content from the request URI.
*/
public boolean shouldRemoveSemicolonContent() {
checkReadOnly();
return this.removeSemicolonContent;
}

Expand All @@ -142,6 +150,7 @@ public boolean shouldRemoveSemicolonContent() {
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
*/
public void setDefaultEncoding(String defaultEncoding) {
checkReadOnly();
this.defaultEncoding = defaultEncoding;
}

Expand All @@ -152,6 +161,17 @@ protected String getDefaultEncoding() {
return this.defaultEncoding;
}

/**
* Switch to read-only mode where further configuration changes are not allowed.
*/
private void setReadOnly() {
this.readOnly = true;
}

private void checkReadOnly() {
Assert.isTrue(!this.readOnly, "This instance cannot be modified");
}


/**
* Return the mapping lookup path for the given request, within the current
Expand Down Expand Up @@ -604,4 +624,39 @@ private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request)
return !websphereComplianceFlag;
}


/**
* Shared, read-only instance with defaults. The following apply:
* <ul>
* <li>{@code alwaysUseFullPath=false}
* <li>{@code urlDecode=true}
* <li>{@code removeSemicolon=true}
* <li>{@code defaultEncoding=}{@link WebUtils#DEFAULT_CHARACTER_ENCODING}
* </ul>
*/
public static final UrlPathHelper defaultInstance = new UrlPathHelper();

static {
defaultInstance.setReadOnly();
}


/**
* Shared, read-only instance for the full, encoded path. The following apply:
* <ul>
* <li>{@code alwaysUseFullPath=true}
* <li>{@code urlDecode=false}
* <li>{@code removeSemicolon=false}
* <li>{@code defaultEncoding=}{@link WebUtils#DEFAULT_CHARACTER_ENCODING}
* </ul>
*/
public static final UrlPathHelper rawPathInstance = new UrlPathHelper();

static {
rawPathInstance.setAlwaysUseFullPath(true);
rawPathInstance.setUrlDecode(false);
rawPathInstance.setRemoveSemicolonContent(false);
rawPathInstance.setReadOnly();
}

}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -103,7 +103,7 @@ private PatternsRequestCondition(Collection<String> patterns, UrlPathHelper urlP
List<String> fileExtensions) {

this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
this.pathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
this.pathHelper = (urlPathHelper != null ? urlPathHelper : UrlPathHelper.defaultInstance);
this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
this.useSuffixPatternMatch = useSuffixPatternMatch;
this.useTrailingSlashMatch = useTrailingSlashMatch;
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -75,13 +75,6 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe

private static final UrlPathHelper DECODING_URL_PATH_HELPER = new UrlPathHelper();

private static final UrlPathHelper RAW_URL_PATH_HELPER = new UrlPathHelper();

static {
RAW_URL_PATH_HELPER.setRemoveSemicolonContent(false);
RAW_URL_PATH_HELPER.setUrlDecode(false);
}


private final ContentNegotiationManager contentNegotiationManager;

Expand Down Expand Up @@ -364,7 +357,7 @@ private void addContentDispositionHeader(ServletServerHttpRequest request, Servl
}

HttpServletRequest servletRequest = request.getServletRequest();
String requestUri = RAW_URL_PATH_HELPER.getOriginatingRequestUri(servletRequest);
String requestUri = UrlPathHelper.rawPathInstance.getOriginatingRequestUri(servletRequest);

int index = requestUri.lastIndexOf('/') + 1;
String filename = requestUri.substring(index);
Expand All @@ -376,10 +369,10 @@ private void addContentDispositionHeader(ServletServerHttpRequest request, Servl
filename = filename.substring(0, index);
}

filename = DECODING_URL_PATH_HELPER.decodeRequestString(servletRequest, filename);
filename = UrlPathHelper.defaultInstance.decodeRequestString(servletRequest, filename);
String ext = StringUtils.getFilenameExtension(filename);

pathParams = DECODING_URL_PATH_HELPER.decodeRequestString(servletRequest, pathParams);
pathParams = UrlPathHelper.defaultInstance.decodeRequestString(servletRequest, pathParams);
String extInPathParams = StringUtils.getFilenameExtension(pathParams);

if (!safeExtension(servletRequest, ext) || !safeExtension(servletRequest, extInPathParams)) {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -35,7 +35,7 @@
*/
public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {

private UrlPathHelper urlPathHelper = new UrlPathHelper();
private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;


public ServletCookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -52,7 +52,7 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed

protected final Log logger = LogFactory.getLog(getClass());

private UrlPathHelper urlPathHelper = new UrlPathHelper();
private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;

private PathMatcher pathMatcher = new AntPathMatcher();

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -51,7 +51,7 @@ public abstract class AbstractFlashMapManager implements FlashMapManager {

private int flashMapTimeout = 180;

private UrlPathHelper urlPathHelper = new UrlPathHelper();
private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;


/**
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -106,7 +106,7 @@ public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest req
*/
public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest request) {
ServletUriComponentsBuilder builder = fromContextPath(request);
if (StringUtils.hasText(new UrlPathHelper().getPathWithinServletMapping(request))) {
if (StringUtils.hasText(UrlPathHelper.defaultInstance.getPathWithinServletMapping(request))) {
builder.path(request.getServletPath());
}
return builder;
Expand Down

0 comments on commit bdcb189

Please sign in to comment.