Skip to content

Commit d322bcf

Browse files
committed
Use X-Forwarded-Prefix in ServletUriComponentsBuilder
Issue: SPR-12500
1 parent af2782a commit d322bcf

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
*/
3636
public class ServletUriComponentsBuilder extends UriComponentsBuilder {
3737

38-
private String servletRequestURI;
38+
private String originalPath;
3939

4040

4141
/**
@@ -86,7 +86,6 @@ public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest
8686
*/
8787
public static ServletUriComponentsBuilder fromRequestUri(HttpServletRequest request) {
8888
ServletUriComponentsBuilder builder = fromRequest(request);
89-
builder.pathFromRequest(request);
9089
builder.replaceQuery(null);
9190
return builder;
9291
}
@@ -99,6 +98,7 @@ public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request
9998
String scheme = request.getScheme();
10099
String host = request.getServerName();
101100
int port = request.getServerPort();
101+
String path = request.getRequestURI();
102102

103103
String hostHeader = request.getHeader("X-Forwarded-Host");
104104
if (StringUtils.hasText(hostHeader)) {
@@ -125,13 +125,18 @@ public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request
125125
scheme = protocolHeader;
126126
}
127127

128+
String prefix = request.getHeader("X-Forwarded-Prefix");
129+
if (StringUtils.hasText(prefix)) {
130+
path = prefix + path;
131+
}
132+
128133
ServletUriComponentsBuilder builder = new ServletUriComponentsBuilder();
129134
builder.scheme(scheme);
130135
builder.host(host);
131136
if (scheme.equals("http") && port != 80 || scheme.equals("https") && port != 443) {
132137
builder.port(port);
133138
}
134-
builder.pathFromRequest(request);
139+
builder.initPath(path);
135140
builder.query(request.getQueryString());
136141
return builder;
137142
}
@@ -180,37 +185,37 @@ protected static HttpServletRequest getCurrentRequest() {
180185
return servletRequest;
181186
}
182187

183-
private void pathFromRequest(HttpServletRequest request) {
184-
this.servletRequestURI = request.getRequestURI();
185-
replacePath(request.getRequestURI());
188+
private void initPath(String path) {
189+
this.originalPath = path;
190+
replacePath(path);
186191
}
187192

188193
/**
189194
* Removes any path extension from the {@link HttpServletRequest#getRequestURI()
190195
* requestURI}. This method must be invoked before any calls to {@link #path(String)}
191196
* or {@link #pathSegment(String...)}.
192197
* <pre>
193-
* // GET http://foo.com/rest/books/6.json
194198
*
195-
* ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromRequestUri(this.request);
196-
* String ext = builder.removePathExtension();
197-
* String uri = builder.path("/pages/1.{ext}").buildAndExpand(ext).toUriString();
199+
* GET http://foo.com/rest/books/6.json
198200
*
199-
* assertEquals("http://foo.com/rest/books/6/pages/1.json", result);
201+
* ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromRequestUri(this.request);
202+
* String ext = builder.removePathExtension();
203+
* String uri = builder.path("/pages/1.{ext}").buildAndExpand(ext).toUriString();
204+
* assertEquals("http://foo.com/rest/books/6/pages/1.json", result);
200205
* </pre>
201206
* @return the removed path extension for possible re-use, or {@code null}
202207
* @since 4.0
203208
*/
204209
public String removePathExtension() {
205210
String extension = null;
206-
if (this.servletRequestURI != null) {
207-
String filename = WebUtils.extractFullFilenameFromUrlPath(this.servletRequestURI);
211+
if (this.originalPath != null) {
212+
String filename = WebUtils.extractFullFilenameFromUrlPath(this.originalPath);
208213
extension = StringUtils.getFilenameExtension(filename);
209214
if (!StringUtils.isEmpty(extension)) {
210-
int end = this.servletRequestURI.length() - (extension.length() + 1);
211-
replacePath(this.servletRequestURI.substring(0, end));
215+
int end = this.originalPath.length() - (extension.length() + 1);
216+
replacePath(this.originalPath.substring(0, end));
212217
}
213-
this.servletRequestURI = null;
218+
this.originalPath = null;
214219
}
215220
return extension;
216221
}

spring-webmvc/src/test/java/org/springframework/web/servlet/support/ServletUriComponentsBuilderTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,24 @@ public void fromRequestWithForwardedHostWithForwardedScheme() {
150150
assertEquals("should have used the default port of the forwarded request", -1, result.getPort());
151151
}
152152

153+
@Test
154+
public void fromRequestWithForwardedPrefix() {
155+
this.request.setRequestURI("/bar");
156+
this.request.addHeader("X-Forwarded-Prefix", "/foo");
157+
UriComponents result = ServletUriComponentsBuilder.fromRequest(request).build();
158+
159+
assertEquals("http://localhost/foo/bar", result.toUriString());
160+
}
161+
162+
@Test
163+
public void fromRequestWithForwardedPrefixTrailingSlash() {
164+
this.request.setRequestURI("/bar");
165+
this.request.addHeader("X-Forwarded-Prefix", "/foo/");
166+
UriComponents result = ServletUriComponentsBuilder.fromRequest(request).build();
167+
168+
assertEquals("http://localhost/foo/bar", result.toUriString());
169+
}
170+
153171
@Test
154172
public void fromContextPath() {
155173
request.setRequestURI("/mvc-showcase/data/param");

0 commit comments

Comments
 (0)