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 55d0756 commit 2281e42
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@
public class MockHttpServletRequestBuilder
implements ConfigurableSmartRequestBuilder<MockHttpServletRequestBuilder>, Mergeable {

private static final UrlPathHelper urlPathHelper = new UrlPathHelper();


private final String method;

private final URI url;
Expand Down Expand Up @@ -697,7 +694,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
Original file line number Diff line number Diff line change
@@ -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 @@ -45,8 +45,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 @@ -96,7 +94,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
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,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 @@ -149,7 +140,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
}
else {
HttpServletRequest wrappedRequest =
new ForwardedHeaderExtractingRequest(request, this.pathHelper);
new ForwardedHeaderExtractingRequest(request);

HttpServletResponse wrappedResponse = this.relativeRedirects ?
RelativeRedirectResponseWrapper.wrapIfNecessary(response, HttpStatus.SEE_OTHER) :
Expand Down Expand Up @@ -230,7 +221,7 @@ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRem
private final ForwardedPrefixExtractor forwardedPrefixExtractor;


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

HttpRequest httpRequest = new ServletServerHttpRequest(request);
Expand All @@ -244,7 +235,7 @@ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRem

String baseUrl = this.scheme + "://" + this.host + (port == -1 ? "" : ":" + port);
Supplier<HttpServletRequest> delegateRequest = () -> (HttpServletRequest) getRequest();
this.forwardedPrefixExtractor = new ForwardedPrefixExtractor(delegateRequest, pathHelper, baseUrl);
this.forwardedPrefixExtractor = new ForwardedPrefixExtractor(delegateRequest, baseUrl);
}


Expand Down Expand Up @@ -296,8 +287,6 @@ private static class ForwardedPrefixExtractor {

private final Supplier<HttpServletRequest> delegate;

private final UrlPathHelper pathHelper;

private final String baseUrl;

private String actualRequestUri;
Expand All @@ -316,14 +305,10 @@ private static class ForwardedPrefixExtractor {
* @param delegateRequest supplier for the current
* {@link HttpServletRequestWrapper#getRequest() delegate request} which
* may change during a forward (e.g. Tomcat.
* @param pathHelper the path helper instance
* @param baseUrl the host, scheme, and port based on forwarded headers
*/
public ForwardedPrefixExtractor(
Supplier<HttpServletRequest> delegateRequest, UrlPathHelper pathHelper, String baseUrl) {

public ForwardedPrefixExtractor(Supplier<HttpServletRequest> delegateRequest, String baseUrl) {
this.delegate = delegateRequest;
this.pathHelper = pathHelper;
this.baseUrl = baseUrl;
this.actualRequestUri = delegateRequest.get().getRequestURI();

Expand Down Expand Up @@ -353,7 +338,8 @@ private static String initForwardedPrefix(HttpServletRequest request) {
@Nullable
private String initRequestUri() {
if (this.forwardedPrefix != null) {
return this.forwardedPrefix + this.pathHelper.getPathWithinApplication(this.delegate.get());
return this.forwardedPrefix +
UrlPathHelper.rawPathInstance.getPathWithinApplication(this.delegate.get());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.apache.commons.logging.LogFactory;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -70,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 @@ -81,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 @@ -103,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 @@ -119,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 @@ -143,6 +150,7 @@ public boolean shouldRemoveSemicolonContent() {
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
*/
public void setDefaultEncoding(String defaultEncoding) {
checkReadOnly();
this.defaultEncoding = defaultEncoding;
}

Expand All @@ -153,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 @@ -606,4 +625,39 @@ private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request)
return !flagToUse;
}


/**
* 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();
}

}
Original file line number Diff line number Diff line change
@@ -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 @@ -106,7 +106,7 @@ private PatternsRequestCondition(Collection<String> patterns, @Nullable UrlPathH
boolean useTrailingSlashMatch, @Nullable 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
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,6 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
new ParameterizedTypeReference<List<ResourceRegion>>() { }.getType();


private static final UrlPathHelper decodingUrlPathHelper = new UrlPathHelper();

private static final UrlPathHelper rawUrlPathHelper = new UrlPathHelper();

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


private final ContentNegotiationManager contentNegotiationManager;

private final PathExtensionContentNegotiationStrategy pathStrategy;
Expand Down Expand Up @@ -426,7 +416,7 @@ private void addContentDispositionHeader(ServletServerHttpRequest request, Servl
}

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

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

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

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

if (!safeExtension(servletRequest, ext) || !safeExtension(servletRequest, extInPathParams)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 @@ -37,7 +37,7 @@
*/
public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {

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


public ServletCookieValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 @@ -53,7 +53,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
Original file line number Diff line number Diff line change
@@ -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 @@ -53,7 +53,7 @@ public abstract class AbstractFlashMapManager implements FlashMapManager {

private int flashMapTimeout = 180;

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


/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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 @@ -92,7 +92,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 2281e42

Please sign in to comment.