diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index 1bddd7a4e6b3c6376d73199b6a694e501a34bb98..25c5781387611346669dacf97b2c90068aabd4dd 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -182,12 +182,7 @@ final class HierarchicalUriComponents extends UriComponents { } String encodedScheme = encodeUriComponent(this.getScheme(), encoding, Type.SCHEME); String encodedUserInfo = encodeUriComponent(this.userInfo, encoding, Type.USER_INFO); - String encodedHost; - if(StringUtils.hasLength(this.host) && this.host.startsWith("[")) { - encodedHost = encodeUriComponent(this.host, encoding, Type.HOST_IPV6); - } else { - encodedHost = encodeUriComponent(this.host, encoding, Type.HOST); - } + String encodedHost = encodeUriComponent(this.host, encoding, getHostType()); PathComponent encodedPath = this.path.encode(encoding); MultiValueMap encodedQueryParams = @@ -246,6 +241,9 @@ final class HierarchicalUriComponents extends UriComponents { return bos.toByteArray(); } + private Type getHostType() { + return ((this.host != null) && this.host.startsWith("[")) ? Type.HOST_IPV6 : Type.HOST_IPV4; + } // verifying @@ -260,7 +258,7 @@ final class HierarchicalUriComponents extends UriComponents { } verifyUriComponent(getScheme(), Type.SCHEME); verifyUriComponent(userInfo, Type.USER_INFO); - verifyUriComponent(host, Type.HOST); + verifyUriComponent(host, getHostType()); this.path.verify(); for (Map.Entry> entry : queryParams.entrySet()) { verifyUriComponent(entry.getKey(), Type.QUERY_PARAM); @@ -468,7 +466,7 @@ final class HierarchicalUriComponents extends UriComponents { return isUnreserved(c) || isSubDelimiter(c) || ':' == c; } }, - HOST { + HOST_IPV4 { @Override public boolean isAllowed(int c) { return isUnreserved(c) || isSubDelimiter(c); diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index f9d20ebf1bfdd41afcf3b72f5bf04ddf95938023..fa5e7aeba082a0d07a2b9b9a4231e0cc0a916fb1 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -64,11 +64,11 @@ public class UriComponentsBuilder { private static final String USERINFO_PATTERN = "([^@/]*)"; - private static final String HOST_IPv4_PATTERN = "[^\\[/?#:]*"; + private static final String HOST_IPV4_PATTERN = "[^\\[/?#:]*"; private static final String HOST_IPV6_PATTERN = "\\[[\\p{XDigit}\\:\\.]*[%\\p{Alnum}]*\\]"; - private static final String HOST_PATTERN = "("+HOST_IPV6_PATTERN + "|" + HOST_IPv4_PATTERN + ")"; + private static final String HOST_PATTERN = "(" + HOST_IPV6_PATTERN + "|" + HOST_IPV4_PATTERN + ")"; private static final String PORT_PATTERN = "(\\d*)"; diff --git a/spring-web/src/main/java/org/springframework/web/util/UriUtils.java b/spring-web/src/main/java/org/springframework/web/util/UriUtils.java index 3a3088e7e62148e2391607960369c392622ac542..6abdb392f47d1d17b27c2f5960fe777feaf4a17e 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriUtils.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriUtils.java @@ -254,7 +254,7 @@ public abstract class UriUtils { */ public static String encodeHost(String host, String encoding) throws UnsupportedEncodingException { return HierarchicalUriComponents - .encodeUriComponent(host, encoding, HierarchicalUriComponents.Type.HOST); + .encodeUriComponent(host, encoding, HierarchicalUriComponents.Type.HOST_IPV4); } /** diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index a62e593b219e74a73f8bfd6bf4b76f653667255e..2fb397a1aa1330796f05ee2e3918df0b6bf6d8ca 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -173,8 +173,7 @@ public class UriComponentsBuilderTests { @Test(expected = IllegalArgumentException.class) public void fromHttpUrlStringInvalidIPv6Host() throws URISyntaxException { - UriComponents result = 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 @@ -183,15 +182,15 @@ public class UriComponentsBuilderTests { public void fromUriStringIPv6Host() throws URISyntaxException { UriComponents result = UriComponentsBuilder .fromUriString("http://[1abc:2abc:3abc::5ABC:6abc]:8080/resource").build().encode(); - assertEquals("[1abc:2abc:3abc::5ABC:6abc]",result.getHost()); + assertEquals("[1abc:2abc:3abc::5ABC:6abc]", result.getHost()); UriComponents resultWithScopeId = UriComponentsBuilder .fromUriString("http://[1abc:2abc:3abc::5ABC:6abc%eth0]:8080/resource").build().encode(); - assertEquals("[1abc:2abc:3abc::5ABC:6abc%25eth0]",resultWithScopeId.getHost()); + assertEquals("[1abc:2abc:3abc::5ABC:6abc%25eth0]", resultWithScopeId.getHost()); UriComponents resultIPv4compatible = UriComponentsBuilder .fromUriString("http://[::192.168.1.1]:8080/resource").build().encode(); - assertEquals("[::192.168.1.1]",resultIPv4compatible.getHost()); + assertEquals("[::192.168.1.1]", resultIPv4compatible.getHost()); } @Test diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java index 2013e6df659e547020b467196c59865580582a49..458a08a59369f4cc2e8cca40f3f7bed7329d9a27 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java @@ -25,9 +25,7 @@ import java.net.URISyntaxException; import org.junit.Test; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; /** @@ -45,20 +43,38 @@ public class UriComponentsTests { @Test public void toUriEncoded() throws URISyntaxException { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com/hotel list/Z\u00fcrich").build(); - UriComponents encoded = uriComponents.encode(); - assertEquals(new URI("http://example.com/hotel%20list/Z%C3%BCrich"), encoded.toUri()); + UriComponents uriComponents = UriComponentsBuilder.fromUriString( + "http://example.com/hotel list/Z\u00fcrich").build(); + assertEquals(new URI("http://example.com/hotel%20list/Z%C3%BCrich"), uriComponents.encode().toUri()); } @Test public void toUriNotEncoded() throws URISyntaxException { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com/hotel list/Z\u00fcrich").build(); + UriComponents uriComponents = UriComponentsBuilder.fromUriString( + "http://example.com/hotel list/Z\u00fcrich").build(); assertEquals(new URI("http://example.com/hotel%20list/Z\u00fcrich"), uriComponents.toUri()); } + @Test + public void toUriAlreadyEncoded() throws URISyntaxException { + UriComponents uriComponents = UriComponentsBuilder.fromUriString( + "http://example.com/hotel%20list/Z%C3%BCrich").build(true); + UriComponents encoded = uriComponents.encode(); + assertEquals(new URI("http://example.com/hotel%20list/Z%C3%BCrich"), encoded.toUri()); + } + + @Test + public void toUriWithIpv6HostAlreadyEncoded() throws URISyntaxException { + UriComponents uriComponents = UriComponentsBuilder.fromUriString( + "http://[1abc:2abc:3abc::5ABC:6abc]:8080/hotel%20list/Z%C3%BCrich").build(true); + UriComponents encoded = uriComponents.encode(); + assertEquals(new URI("http://[1abc:2abc:3abc::5ABC:6abc]:8080/hotel%20list/Z%C3%BCrich"), encoded.toUri()); + } + @Test public void expand() { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com").path("/{foo} {bar}").build(); + UriComponents uriComponents = UriComponentsBuilder.fromUriString( + "http://example.com").path("/{foo} {bar}").build(); uriComponents = uriComponents.expand("1 2", "3 4"); assertEquals("/1 2 3 4", uriComponents.getPath()); assertEquals("http://example.com/1 2 3 4", uriComponents.toUriString());