Fix NumberFormatException with X-Forwarded-Host

This commit fixes `NumberFormatException`s that were thrown when parsing
IPv6 host values in `X-Forwarded-Host` request headers.

Issue: SPR-14761
This commit is contained in:
Brian Clozel 2016-10-06 15:36:48 +02:00
parent 53441f8962
commit ea5ff87f8e
2 changed files with 92 additions and 62 deletions

View File

@ -51,6 +51,7 @@ import org.springframework.web.util.HierarchicalUriComponents.PathComponent;
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Phillip Webb * @author Phillip Webb
* @author Oliver Gierke * @author Oliver Gierke
* @author Brian Clozel
* @since 3.1 * @since 3.1
* @see #newInstance() * @see #newInstance()
* @see #fromPath(String) * @see #fromPath(String)
@ -687,10 +688,10 @@ public class UriComponentsBuilder implements Cloneable {
String hostHeader = headers.getFirst("X-Forwarded-Host"); String hostHeader = headers.getFirst("X-Forwarded-Host");
if (StringUtils.hasText(hostHeader)) { if (StringUtils.hasText(hostHeader)) {
String hostToUse = StringUtils.tokenizeToStringArray(hostHeader, ",")[0]; String hostToUse = StringUtils.tokenizeToStringArray(hostHeader, ",")[0];
String[] hostAndPort = StringUtils.split(hostToUse, ":"); int portSeparatorIdx = hostToUse.lastIndexOf(":");
if (hostAndPort != null) { if (portSeparatorIdx > hostToUse.lastIndexOf("]")) {
host(hostAndPort[0]); host(hostToUse.substring(0, portSeparatorIdx));
port(Integer.parseInt(hostAndPort[1])); port(Integer.parseInt(hostToUse.substring(portSeparatorIdx + 1)));
} }
else { else {
host(hostToUse); host(hostToUse);

View File

@ -125,9 +125,7 @@ public class UriComponentsBuilderTests {
assertEquals("Invalid result URI", uri, result.toUri()); assertEquals("Invalid result URI", uri, result.toUri());
} }
// SPR-9317 @Test // SPR-9317
@Test
public void fromUriEncodedQuery() throws URISyntaxException { public void fromUriEncodedQuery() throws URISyntaxException {
URI uri = new URI("http://www.example.org/?param=aGVsbG9Xb3JsZA%3D%3D"); URI uri = new URI("http://www.example.org/?param=aGVsbG9Xb3JsZA%3D%3D");
String fromUri = UriComponentsBuilder.fromUri(uri).build().getQueryParams().get("param").get(0); String fromUri = UriComponentsBuilder.fromUri(uri).build().getQueryParams().get("param").get(0);
@ -182,9 +180,7 @@ public class UriComponentsBuilderTests {
assertEquals("28", result.getFragment()); assertEquals("28", result.getFragment());
} }
// SPR-9832 @Test // SPR-9832
@Test
public void fromUriStringQueryParamWithReservedCharInValue() throws URISyntaxException { public void fromUriStringQueryParamWithReservedCharInValue() throws URISyntaxException {
String uri = "http://www.google.com/ig/calculator?q=1USD=?EUR"; String uri = "http://www.google.com/ig/calculator?q=1USD=?EUR";
UriComponents result = UriComponentsBuilder.fromUriString(uri).build(); UriComponents result = UriComponentsBuilder.fromUriString(uri).build();
@ -193,24 +189,20 @@ public class UriComponentsBuilderTests {
assertEquals("1USD=?EUR", result.getQueryParams().getFirst("q")); assertEquals("1USD=?EUR", result.getQueryParams().getFirst("q"));
} }
// SPR-10779 @Test // SPR-10779
@Test
public void fromHttpUrlStringCaseInsesitiveScheme() { public void fromHttpUrlStringCaseInsesitiveScheme() {
assertEquals("http", UriComponentsBuilder.fromHttpUrl("HTTP://www.google.com").build().getScheme()); assertEquals("http", UriComponentsBuilder.fromHttpUrl("HTTP://www.google.com").build().getScheme());
assertEquals("https", UriComponentsBuilder.fromHttpUrl("HTTPS://www.google.com").build().getScheme()); assertEquals("https", UriComponentsBuilder.fromHttpUrl("HTTPS://www.google.com").build().getScheme());
} }
// SPR-10539
@Test(expected = IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class) // SPR-10539
public void fromHttpUrlStringInvalidIPv6Host() throws URISyntaxException { public void fromHttpUrlStringInvalidIPv6Host() throws URISyntaxException {
UriComponentsBuilder.fromHttpUrl("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource").build().encode(); UriComponentsBuilder.fromHttpUrl("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource").build().encode();
} }
// SPR-10539 @Test // SPR-10539
@Test
public void fromUriStringIPv6Host() throws URISyntaxException { public void fromUriStringIPv6Host() throws URISyntaxException {
UriComponents result = UriComponentsBuilder UriComponents result = UriComponentsBuilder
.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc]:8080/resource").build().encode(); .fromUriString("http://[1abc:2abc:3abc::5ABC:6abc]:8080/resource").build().encode();
@ -225,9 +217,7 @@ public class UriComponentsBuilderTests {
assertEquals("[::192.168.1.1]", resultIPv4compatible.getHost()); assertEquals("[::192.168.1.1]", resultIPv4compatible.getHost());
} }
// SPR-11970 @Test // SPR-11970
@Test
public void fromUriStringNoPathWithReservedCharInQuery() { public void fromUriStringNoPathWithReservedCharInQuery() {
UriComponents result = UriComponentsBuilder.fromUriString("http://example.com?foo=bar@baz").build(); UriComponents result = UriComponentsBuilder.fromUriString("http://example.com?foo=bar@baz").build();
assertTrue(StringUtils.isEmpty(result.getUserInfo())); assertTrue(StringUtils.isEmpty(result.getUserInfo()));
@ -253,9 +243,7 @@ public class UriComponentsBuilderTests {
assertEquals("a=1", result.getQuery()); assertEquals("a=1", result.getQuery());
} }
// SPR-12771 @Test // SPR-12771
@Test
public void fromHttpRequestResetsPortBeforeSettingIt() throws Exception { public void fromHttpRequestResetsPortBeforeSettingIt() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("X-Forwarded-Proto", "https"); request.addHeader("X-Forwarded-Proto", "https");
@ -275,6 +263,67 @@ public class UriComponentsBuilderTests {
assertEquals("/rest/mobile/users/1", result.getPath()); assertEquals("/rest/mobile/users/1", result.getPath());
} }
@Test //SPR-14761
public void fromHttpRequestWithForwardedIPv4Host() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http");
request.setServerName("localhost");
request.setServerPort(-1);
request.setRequestURI("/mvc-showcase");
request.addHeader("Forwarded", "host=192.168.0.1");
HttpRequest httpRequest = new ServletServerHttpRequest(request);
UriComponents result = UriComponentsBuilder.fromHttpRequest(httpRequest).build();
assertEquals("http://192.168.0.1/mvc-showcase", result.toString());
}
@Test //SPR-14761
public void fromHttpRequestWithForwardedIPv6() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http");
request.setServerName("localhost");
request.setServerPort(-1);
request.setRequestURI("/mvc-showcase");
request.addHeader("Forwarded", "host=[1abc:2abc:3abc::5ABC:6abc]");
HttpRequest httpRequest = new ServletServerHttpRequest(request);
UriComponents result = UriComponentsBuilder.fromHttpRequest(httpRequest).build();
assertEquals("http://[1abc:2abc:3abc::5ABC:6abc]/mvc-showcase", result.toString());
}
@Test //SPR-14761
public void fromHttpRequestWithForwardedIPv6Host() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http");
request.setServerName("localhost");
request.setServerPort(-1);
request.setRequestURI("/mvc-showcase");
request.addHeader("X-Forwarded-Host", "[1abc:2abc:3abc::5ABC:6abc]");
HttpRequest httpRequest = new ServletServerHttpRequest(request);
UriComponents result = UriComponentsBuilder.fromHttpRequest(httpRequest).build();
assertEquals("http://[1abc:2abc:3abc::5ABC:6abc]/mvc-showcase", result.toString());
}
@Test //SPR-14761
public void fromHttpRequestWithForwardedIPv6HostAndPort() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http");
request.setServerName("localhost");
request.setServerPort(-1);
request.setRequestURI("/mvc-showcase");
request.addHeader("X-Forwarded-Host", "[1abc:2abc:3abc::5ABC:6abc]:8080");
HttpRequest httpRequest = new ServletServerHttpRequest(request);
UriComponents result = UriComponentsBuilder.fromHttpRequest(httpRequest).build();
assertEquals("http://[1abc:2abc:3abc::5ABC:6abc]:8080/mvc-showcase", result.toString());
}
@Test @Test
public void fromHttpRequestWithForwardedHost() { public void fromHttpRequestWithForwardedHost() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
@ -290,9 +339,7 @@ public class UriComponentsBuilderTests {
assertEquals("http://anotherHost/mvc-showcase", result.toString()); assertEquals("http://anotherHost/mvc-showcase", result.toString());
} }
// SPR-10701 @Test // SPR-10701
@Test
public void fromHttpRequestWithForwardedHostIncludingPort() { public void fromHttpRequestWithForwardedHostIncludingPort() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -308,9 +355,7 @@ public class UriComponentsBuilderTests {
assertEquals(443, result.getPort()); assertEquals(443, result.getPort());
} }
// SPR-11140 @Test // SPR-11140
@Test
public void fromHttpRequestWithForwardedHostMultiValuedHeader() { public void fromHttpRequestWithForwardedHostMultiValuedHeader() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -325,9 +370,7 @@ public class UriComponentsBuilderTests {
assertEquals(-1, result.getPort()); assertEquals(-1, result.getPort());
} }
// SPR-11855 @Test // SPR-11855
@Test
public void fromHttpRequestWithForwardedHostAndPort() { public void fromHttpRequestWithForwardedHostAndPort() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -343,9 +386,7 @@ public class UriComponentsBuilderTests {
assertEquals(9090, result.getPort()); assertEquals(9090, result.getPort());
} }
// SPR-11872 @Test // SPR-11872
@Test
public void fromHttpRequestWithForwardedHostWithDefaultPort() { public void fromHttpRequestWithForwardedHostWithDefaultPort() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -378,9 +419,7 @@ public class UriComponentsBuilderTests {
assertEquals(-1, result.getPort()); assertEquals(-1, result.getPort());
} }
// SPR-12771 @Test // SPR-12771
@Test
public void fromHttpRequestWithForwardedProtoAndDefaultPort() { public void fromHttpRequestWithForwardedProtoAndDefaultPort() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -397,9 +436,7 @@ public class UriComponentsBuilderTests {
assertEquals("https://84.198.58.199/mvc-showcase", result.toString()); assertEquals("https://84.198.58.199/mvc-showcase", result.toString());
} }
// SPR-12813 @Test // SPR-12813
@Test
public void fromHttpRequestWithForwardedPortMultiValueHeader() { public void fromHttpRequestWithForwardedPortMultiValueHeader() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -415,9 +452,7 @@ public class UriComponentsBuilderTests {
assertEquals("http://a.example.org/mvc-showcase", result.toString()); assertEquals("http://a.example.org/mvc-showcase", result.toString());
} }
// SPR-12816 @Test // SPR-12816
@Test
public void fromHttpRequestWithForwardedProtoMultiValueHeader() { public void fromHttpRequestWithForwardedProtoMultiValueHeader() {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setScheme("http"); request.setScheme("http");
@ -434,9 +469,7 @@ public class UriComponentsBuilderTests {
assertEquals("https://a.example.org/mvc-showcase", result.toString()); assertEquals("https://a.example.org/mvc-showcase", result.toString());
} }
// SPR-12742 @Test // SPR-12742
@Test
public void fromHttpRequestWithTrailingSlash() throws Exception { public void fromHttpRequestWithTrailingSlash() throws Exception {
UriComponents before = UriComponentsBuilder.fromPath("/foo/").build(); UriComponents before = UriComponentsBuilder.fromPath("/foo/").build();
UriComponents after = UriComponentsBuilder.newInstance().uriComponents(before).build(); UriComponents after = UriComponentsBuilder.newInstance().uriComponents(before).build();
@ -506,9 +539,7 @@ public class UriComponentsBuilderTests {
assertEquals(Arrays.asList("foo", "bar"), result.getPathSegments()); assertEquals(Arrays.asList("foo", "bar"), result.getPathSegments());
} }
// SPR-12398 @Test // SPR-12398
@Test
public void pathWithDuplicateSlashes() throws URISyntaxException { public void pathWithDuplicateSlashes() throws URISyntaxException {
UriComponents uriComponents = UriComponentsBuilder.fromPath("/foo/////////bar").build(); UriComponents uriComponents = UriComponentsBuilder.fromPath("/foo/////////bar").build();
assertEquals("/foo/bar", uriComponents.getPath()); assertEquals("/foo/bar", uriComponents.getPath());
@ -686,9 +717,7 @@ public class UriComponentsBuilderTests {
assertEquals("f2", result2.getFragment()); assertEquals("f2", result2.getFragment());
} }
// SPR-11856 @Test // SPR-11856
@Test
public void fromHttpRequestForwardedHeader() throws Exception { public void fromHttpRequestForwardedHeader() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Forwarded", "proto=https; host=84.198.58.199"); request.addHeader("Forwarded", "proto=https; host=84.198.58.199");