提交 2dd44801 编写于 作者: B Brian Clozel

Add IPv6 support in RestTemplate

Prior to this commit, RestTemplate would not would
not accept IPv6 raw addresses in URLs because UriComponentsBuilder
would not parse/encode the Host part correctly.

The UriComponentsBuilder now parses and encode raw IPv6 addresses
in the "[1abc:2abc:3abc::5ABC:6abc]" format and also supports the
use of IPv6 scope_ids (see JDK8 java.net.Inet6Address),
like "[1abc:2abc:3abc::5ABC:6abc%eth0]".

Issue: SPR-10539
上级 beaf6992
......@@ -182,7 +182,13 @@ final class HierarchicalUriComponents extends UriComponents {
}
String encodedScheme = encodeUriComponent(this.getScheme(), encoding, Type.SCHEME);
String encodedUserInfo = encodeUriComponent(this.userInfo, encoding, Type.USER_INFO);
String encodedHost = encodeUriComponent(this.host, encoding, Type.HOST);
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);
}
PathComponent encodedPath = this.path.encode(encoding);
MultiValueMap<String, String> encodedQueryParams =
new LinkedMultiValueMap<String, String>(this.queryParams.size());
......@@ -468,6 +474,12 @@ final class HierarchicalUriComponents extends UriComponents {
return isUnreserved(c) || isSubDelimiter(c);
}
},
HOST_IPV6 {
@Override
public boolean isAllowed(int c) {
return isUnreserved(c) || isSubDelimiter(c) || '[' == c || ']' == c || ':' == c;
}
},
PORT {
@Override
public boolean isAllowed(int c) {
......
......@@ -64,7 +64,11 @@ public class UriComponentsBuilder {
private static final String USERINFO_PATTERN = "([^@/]*)";
private static final String HOST_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 PORT_PATTERN = "(\\d*)";
......@@ -226,7 +230,11 @@ public class UriComponentsBuilder {
String scheme = m.group(1);
builder.scheme((scheme != null) ? scheme.toLowerCase() : scheme);
builder.userInfo(m.group(4));
builder.host(m.group(5));
String host = m.group(5);
if(StringUtils.hasLength(scheme) && !StringUtils.hasLength(host)) {
throw new IllegalArgumentException("[" + httpUrl + "] is not a valid HTTP URL");
}
builder.host(host);
String port = m.group(7);
if (StringUtils.hasLength(port)) {
builder.port(Integer.parseInt(port));
......
......@@ -169,6 +169,31 @@ public class UriComponentsBuilderTests {
assertEquals("https", UriComponentsBuilder.fromHttpUrl("HTTPS://www.google.com").build().getScheme());
}
// SPR-10539
@Test(expected = IllegalArgumentException.class)
public void fromHttpUrlStringInvalidIPv6Host() throws URISyntaxException {
UriComponents result = UriComponentsBuilder
.fromHttpUrl("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource").build().encode();
}
// SPR-10539
@Test
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());
UriComponents resultWithScopeId = UriComponentsBuilder
.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc%eth0]:8080/resource").build().encode();
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());
}
@Test
public void path() throws URISyntaxException {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/foo/bar");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册