Skip to content

Commit bdcb189

Browse files
committed
Shared read-only instances of UrlPathHelper
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
1 parent caa22b7 commit bdcb189

File tree

10 files changed

+77
-42
lines changed

10 files changed

+77
-42
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -83,8 +83,6 @@ public class MockHttpServletRequestBuilder
8383

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

86-
private static final UrlPathHelper urlPathHelper = new UrlPathHelper();
87-
8886

8987
private final String method;
9088

@@ -697,7 +695,7 @@ private void updatePathRequestProperties(MockHttpServletRequest request, String
697695
}
698696
String extraPath = requestUri.substring(this.contextPath.length() + this.servletPath.length());
699697
this.pathInfo = (StringUtils.hasText(extraPath) ?
700-
urlPathHelper.decodeRequestString(request, extraPath) : null);
698+
UrlPathHelper.defaultInstance.decodeRequestString(request, extraPath) : null);
701699
}
702700
request.setPathInfo(this.pathInfo);
703701
}

spring-test/src/main/java/org/springframework/test/web/servlet/setup/PatternMappingFilterProxy.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,8 +44,6 @@ final class PatternMappingFilterProxy implements Filter {
4444

4545
private static final String PATH_MAPPING_PATTERN = "/*";
4646

47-
private static final UrlPathHelper urlPathHelper = new UrlPathHelper();
48-
4947
private final Filter delegate;
5048

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

9795
HttpServletRequest httpRequest = (HttpServletRequest) request;
98-
String requestPath = urlPathHelper.getPathWithinApplication(httpRequest);
96+
String requestPath = UrlPathHelper.defaultInstance.getPathWithinApplication(httpRequest);
9997

10098
if (matches(requestPath)) {
10199
this.delegate.doFilter(request, response, filterChain);

spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,11 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
7575
}
7676

7777

78-
private final UrlPathHelper pathHelper;
79-
8078
private boolean removeOnly;
8179

8280
private boolean relativeRedirects;
8381

8482

85-
public ForwardedHeaderFilter() {
86-
this.pathHelper = new UrlPathHelper();
87-
this.pathHelper.setUrlDecode(false);
88-
this.pathHelper.setRemoveSemicolonContent(false);
89-
}
90-
91-
9283
/**
9384
* Enables mode in which any "Forwarded" or "X-Forwarded-*" headers are
9485
* removed only and the information in them ignored.
@@ -146,7 +137,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
146137
filterChain.doFilter(theRequest, response);
147138
}
148139
else {
149-
HttpServletRequest theRequest = new ForwardedHeaderExtractingRequest(request, this.pathHelper);
140+
HttpServletRequest theRequest = new ForwardedHeaderExtractingRequest(request);
150141
HttpServletResponse theResponse = (this.relativeRedirects ?
151142
RelativeRedirectResponseWrapper.wrapIfNecessary(response, HttpStatus.SEE_OTHER) :
152143
new ForwardedHeaderExtractingResponse(response, theRequest));
@@ -219,7 +210,7 @@ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRem
219210

220211
private final String requestUrl;
221212

222-
public ForwardedHeaderExtractingRequest(HttpServletRequest request, UrlPathHelper pathHelper) {
213+
public ForwardedHeaderExtractingRequest(HttpServletRequest request) {
223214
super(request);
224215

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

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

spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,11 +22,13 @@
2222
import java.util.List;
2323
import java.util.Map;
2424
import java.util.Properties;
25+
2526
import javax.servlet.http.HttpServletRequest;
2627

2728
import org.apache.commons.logging.Log;
2829
import org.apache.commons.logging.LogFactory;
2930

31+
import org.springframework.util.Assert;
3032
import org.springframework.util.LinkedMultiValueMap;
3133
import org.springframework.util.MultiValueMap;
3234
import org.springframework.util.StringUtils;
@@ -69,6 +71,8 @@ public class UrlPathHelper {
6971

7072
private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
7173

74+
private boolean readOnly = false;
75+
7276

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

@@ -102,6 +107,7 @@ public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
102107
* @see java.net.URLDecoder#decode(String, String)
103108
*/
104109
public void setUrlDecode(boolean urlDecode) {
110+
checkReadOnly();
105111
this.urlDecode = urlDecode;
106112
}
107113

@@ -118,13 +124,15 @@ public boolean isUrlDecode() {
118124
* <p>Default is "true".
119125
*/
120126
public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
127+
checkReadOnly();
121128
this.removeSemicolonContent = removeSemicolonContent;
122129
}
123130

124131
/**
125132
* Whether configured to remove ";" (semicolon) content from the request URI.
126133
*/
127134
public boolean shouldRemoveSemicolonContent() {
135+
checkReadOnly();
128136
return this.removeSemicolonContent;
129137
}
130138

@@ -142,6 +150,7 @@ public boolean shouldRemoveSemicolonContent() {
142150
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
143151
*/
144152
public void setDefaultEncoding(String defaultEncoding) {
153+
checkReadOnly();
145154
this.defaultEncoding = defaultEncoding;
146155
}
147156

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

164+
/**
165+
* Switch to read-only mode where further configuration changes are not allowed.
166+
*/
167+
private void setReadOnly() {
168+
this.readOnly = true;
169+
}
170+
171+
private void checkReadOnly() {
172+
Assert.isTrue(!this.readOnly, "This instance cannot be modified");
173+
}
174+
155175

156176
/**
157177
* Return the mapping lookup path for the given request, within the current
@@ -604,4 +624,39 @@ private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request)
604624
return !websphereComplianceFlag;
605625
}
606626

627+
628+
/**
629+
* Shared, read-only instance with defaults. The following apply:
630+
* <ul>
631+
* <li>{@code alwaysUseFullPath=false}
632+
* <li>{@code urlDecode=true}
633+
* <li>{@code removeSemicolon=true}
634+
* <li>{@code defaultEncoding=}{@link WebUtils#DEFAULT_CHARACTER_ENCODING}
635+
* </ul>
636+
*/
637+
public static final UrlPathHelper defaultInstance = new UrlPathHelper();
638+
639+
static {
640+
defaultInstance.setReadOnly();
641+
}
642+
643+
644+
/**
645+
* Shared, read-only instance for the full, encoded path. The following apply:
646+
* <ul>
647+
* <li>{@code alwaysUseFullPath=true}
648+
* <li>{@code urlDecode=false}
649+
* <li>{@code removeSemicolon=false}
650+
* <li>{@code defaultEncoding=}{@link WebUtils#DEFAULT_CHARACTER_ENCODING}
651+
* </ul>
652+
*/
653+
public static final UrlPathHelper rawPathInstance = new UrlPathHelper();
654+
655+
static {
656+
rawPathInstance.setAlwaysUseFullPath(true);
657+
rawPathInstance.setUrlDecode(false);
658+
rawPathInstance.setRemoveSemicolonContent(false);
659+
rawPathInstance.setReadOnly();
660+
}
661+
607662
}

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -103,7 +103,7 @@ private PatternsRequestCondition(Collection<String> patterns, UrlPathHelper urlP
103103
List<String> fileExtensions) {
104104

105105
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
106-
this.pathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
106+
this.pathHelper = (urlPathHelper != null ? urlPathHelper : UrlPathHelper.defaultInstance);
107107
this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
108108
this.useSuffixPatternMatch = useSuffixPatternMatch;
109109
this.useTrailingSlashMatch = useTrailingSlashMatch;

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -75,13 +75,6 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
7575

7676
private static final UrlPathHelper DECODING_URL_PATH_HELPER = new UrlPathHelper();
7777

78-
private static final UrlPathHelper RAW_URL_PATH_HELPER = new UrlPathHelper();
79-
80-
static {
81-
RAW_URL_PATH_HELPER.setRemoveSemicolonContent(false);
82-
RAW_URL_PATH_HELPER.setUrlDecode(false);
83-
}
84-
8578

8679
private final ContentNegotiationManager contentNegotiationManager;
8780

@@ -364,7 +357,7 @@ private void addContentDispositionHeader(ServletServerHttpRequest request, Servl
364357
}
365358

366359
HttpServletRequest servletRequest = request.getServletRequest();
367-
String requestUri = RAW_URL_PATH_HELPER.getOriginatingRequestUri(servletRequest);
360+
String requestUri = UrlPathHelper.rawPathInstance.getOriginatingRequestUri(servletRequest);
368361

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

379-
filename = DECODING_URL_PATH_HELPER.decodeRequestString(servletRequest, filename);
372+
filename = UrlPathHelper.defaultInstance.decodeRequestString(servletRequest, filename);
380373
String ext = StringUtils.getFilenameExtension(filename);
381374

382-
pathParams = DECODING_URL_PATH_HELPER.decodeRequestString(servletRequest, pathParams);
375+
pathParams = UrlPathHelper.defaultInstance.decodeRequestString(servletRequest, pathParams);
383376
String extInPathParams = StringUtils.getFilenameExtension(pathParams);
384377

385378
if (!safeExtension(servletRequest, ext) || !safeExtension(servletRequest, extInPathParams)) {

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletCookieValueMethodArgumentResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
3535
*/
3636
public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {
3737

38-
private UrlPathHelper urlPathHelper = new UrlPathHelper();
38+
private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;
3939

4040

4141
public ServletCookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {

spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
5252

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

55-
private UrlPathHelper urlPathHelper = new UrlPathHelper();
55+
private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;
5656

5757
private PathMatcher pathMatcher = new AntPathMatcher();
5858

spring-webmvc/src/main/java/org/springframework/web/servlet/support/AbstractFlashMapManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ public abstract class AbstractFlashMapManager implements FlashMapManager {
5151

5252
private int flashMapTimeout = 180;
5353

54-
private UrlPathHelper urlPathHelper = new UrlPathHelper();
54+
private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;
5555

5656

5757
/**

spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -106,7 +106,7 @@ public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest req
106106
*/
107107
public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest request) {
108108
ServletUriComponentsBuilder builder = fromContextPath(request);
109-
if (StringUtils.hasText(new UrlPathHelper().getPathWithinServletMapping(request))) {
109+
if (StringUtils.hasText(UrlPathHelper.defaultInstance.getPathWithinServletMapping(request))) {
110110
builder.path(request.getServletPath());
111111
}
112112
return builder;

0 commit comments

Comments
 (0)