Skip to content

Commit f84c458

Browse files
committed
Add fromHttpRequest to UriComponentsBuilder
Before this change, detection of X-Forwarded-* headers was only built into ServletUriComponentsBuilder. This change adds a new method for creating a UriComponentsBuilder from an existing HttpRequest. This is equivalent to the fromUri method + X-Forwarded-* header values.
1 parent 9b3319b commit f84c458

File tree

4 files changed

+86
-32
lines changed

4 files changed

+86
-32
lines changed

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

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -24,6 +24,7 @@
2424
import java.util.regex.Matcher;
2525
import java.util.regex.Pattern;
2626

27+
import org.springframework.http.HttpRequest;
2728
import org.springframework.util.Assert;
2829
import org.springframework.util.LinkedMultiValueMap;
2930
import org.springframework.util.MultiValueMap;
@@ -263,6 +264,55 @@ public static UriComponentsBuilder fromHttpUrl(String httpUrl) {
263264
}
264265
}
265266

267+
/**
268+
* Create a new {@code UriComponents} object from the URI associated with
269+
* the given HttpRequest while also overlaying with values from the headers
270+
* "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if present.
271+
*
272+
* @param request the source request
273+
* @return the URI components of the UR
274+
*/
275+
public static UriComponentsBuilder fromHttpRequest(HttpRequest request) {
276+
URI uri = request.getURI();
277+
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(uri);
278+
279+
String scheme = uri.getScheme();
280+
String host = uri.getHost();
281+
int port = uri.getPort();
282+
283+
String hostHeader = request.getHeaders().getFirst("X-Forwarded-Host");
284+
if (StringUtils.hasText(hostHeader)) {
285+
String[] hosts = StringUtils.commaDelimitedListToStringArray(hostHeader);
286+
String hostToUse = hosts[0];
287+
if (hostToUse.contains(":")) {
288+
String[] hostAndPort = StringUtils.split(hostToUse, ":");
289+
host = hostAndPort[0];
290+
port = Integer.parseInt(hostAndPort[1]);
291+
}
292+
else {
293+
host = hostToUse;
294+
port = -1;
295+
}
296+
}
297+
298+
String portHeader = request.getHeaders().getFirst("X-Forwarded-Port");
299+
if (StringUtils.hasText(portHeader)) {
300+
port = Integer.parseInt(portHeader);
301+
}
302+
303+
String protocolHeader = request.getHeaders().getFirst("X-Forwarded-Proto");
304+
if (StringUtils.hasText(protocolHeader)) {
305+
scheme = protocolHeader;
306+
}
307+
308+
builder.scheme(scheme);
309+
builder.host(host);
310+
if (scheme.equals("http") && port != 80 || scheme.equals("https") && port != 443) {
311+
builder.port(port);
312+
}
313+
return builder;
314+
}
315+
266316

267317
// build methods
268318

spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -31,11 +31,16 @@
3131
import java.util.Map;
3232

3333
import org.junit.Test;
34+
35+
import org.springframework.http.server.ServletServerHttpRequest;
36+
import org.springframework.mock.web.test.MockHttpServletRequest;
3437
import org.springframework.util.LinkedMultiValueMap;
3538
import org.springframework.util.MultiValueMap;
3639
import org.springframework.util.StringUtils;
3740

3841
/**
42+
* Unit tests for {@link org.springframework.web.util.UriComponentsBuilder}.
43+
*
3944
* @author Arjen Poutsma
4045
* @author Phillip Webb
4146
* @author Oliver Gierke
@@ -232,6 +237,25 @@ public void fromUriStringNoPathWithReservedCharInQuery() {
232237
assertEquals("bar@baz", result.getQueryParams().getFirst("foo"));
233238
}
234239

240+
// Also see X-Forwarded-* related tests in ServletUriComponentsBuilderTests
241+
242+
@Test
243+
public void fromHttpRequest() throws URISyntaxException {
244+
MockHttpServletRequest request = new MockHttpServletRequest();
245+
request.setScheme("http");
246+
request.setServerName("localhost");
247+
request.setServerPort(-1);
248+
request.setRequestURI("/path");
249+
request.setQueryString("a=1");
250+
251+
UriComponents result = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)).build();
252+
assertEquals("http", result.getScheme());
253+
assertEquals("localhost", result.getHost());
254+
assertEquals(-1, result.getPort());
255+
assertEquals("/path", result.getPath());
256+
assertEquals("a=1", result.getQuery());
257+
}
258+
235259
@Test
236260
public void path() throws URISyntaxException {
237261
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/foo/bar");

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

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -18,11 +18,14 @@
1818

1919
import javax.servlet.http.HttpServletRequest;
2020

21+
import org.springframework.http.HttpRequest;
22+
import org.springframework.http.server.ServletServerHttpRequest;
2123
import org.springframework.util.Assert;
2224
import org.springframework.util.StringUtils;
2325
import org.springframework.web.context.request.RequestAttributes;
2426
import org.springframework.web.context.request.RequestContextHolder;
2527
import org.springframework.web.context.request.ServletRequestAttributes;
28+
import org.springframework.web.util.UriComponents;
2629
import org.springframework.web.util.UriComponentsBuilder;
2730
import org.springframework.web.util.UrlPathHelper;
2831
import org.springframework.web.util.WebUtils;
@@ -112,34 +115,11 @@ public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request
112115
* Initialize a builder with a scheme, host,and port (but not path and query).
113116
*/
114117
private static ServletUriComponentsBuilder initFromRequest(HttpServletRequest request) {
115-
String scheme = request.getScheme();
116-
String host = request.getServerName();
117-
int port = request.getServerPort();
118-
119-
String hostHeader = request.getHeader("X-Forwarded-Host");
120-
if (StringUtils.hasText(hostHeader)) {
121-
String[] hosts = StringUtils.commaDelimitedListToStringArray(hostHeader);
122-
String hostToUse = hosts[0];
123-
if (hostToUse.contains(":")) {
124-
String[] hostAndPort = StringUtils.split(hostToUse, ":");
125-
host = hostAndPort[0];
126-
port = Integer.parseInt(hostAndPort[1]);
127-
}
128-
else {
129-
host = hostToUse;
130-
port = -1;
131-
}
132-
}
133-
134-
String portHeader = request.getHeader("X-Forwarded-Port");
135-
if (StringUtils.hasText(portHeader)) {
136-
port = Integer.parseInt(portHeader);
137-
}
138-
139-
String protocolHeader = request.getHeader("X-Forwarded-Proto");
140-
if (StringUtils.hasText(protocolHeader)) {
141-
scheme = protocolHeader;
142-
}
118+
HttpRequest httpRequest = new ServletServerHttpRequest(request);
119+
UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(httpRequest).build();
120+
String scheme = uriComponents.getScheme();
121+
String host = uriComponents.getHost();
122+
int port = uriComponents.getPort();
143123

144124
ServletUriComponentsBuilder builder = new ServletUriComponentsBuilder();
145125
builder.scheme(scheme);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void setup() {
4141
this.request = new MockHttpServletRequest();
4242
this.request.setScheme("http");
4343
this.request.setServerName("localhost");
44-
this.request.setServerPort(80);
44+
this.request.setServerPort(-1);
4545
this.request.setContextPath("/mvc-showcase");
4646
}
4747

0 commit comments

Comments
 (0)