You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ck...@apache.org on 2021/04/05 15:31:24 UTC
[httpcomponents-core] branch master updated: HTTPCORE-671:
URIBuilder does not precent-encode bracketed IPv6 addresses
This is an automated email from the ASF dual-hosted git repository.
ckozak pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
The following commit(s) were added to refs/heads/master by this push:
new 89e0d3e HTTPCORE-671: URIBuilder does not precent-encode bracketed IPv6 addresses
89e0d3e is described below
commit 89e0d3ed0f2ccecd92c5b857a1429615a7cea7a4
Author: Carter Kozak <ck...@apache.org>
AuthorDate: Wed Mar 24 10:16:01 2021 -0400
HTTPCORE-671: URIBuilder does not precent-encode bracketed IPv6 addresses
URIBuilder complies with https://tools.ietf.org/html/rfc3986
---
.../org/apache/hc/core5/net/InetAddressUtils.java | 11 +++++
.../java/org/apache/hc/core5/net/URIBuilder.java | 17 +++++++-
.../apache/hc/core5/net/TestInetAddressUtils.java | 50 ++++++++++++++++++++++
.../org/apache/hc/core5/net/TestURIBuilder.java | 43 +++++++++++++++++++
4 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/InetAddressUtils.java b/httpcore5/src/main/java/org/apache/hc/core5/net/InetAddressUtils.java
index cf5e9f2..a3aacbf 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/InetAddressUtils.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/InetAddressUtils.java
@@ -138,6 +138,17 @@ public class InetAddressUtils {
}
/**
+ * Checks whether the parameter is a valid URL formatted bracketed IPv6 address (including compressed).
+ * This matches only bracketed values e.g. {@code [::1]}.
+ *
+ * @param input the address string to check for validity
+ * @return true if the input parameter is a valid URL-formatted bracketed IPv6 address
+ */
+ public static boolean isIPv6URLBracketedAddress(final String input) {
+ return input.startsWith("[") && input.endsWith("]") && isIPv6Address(input.substring(1, input.length() - 1));
+ }
+
+ /**
* Formats {@link SocketAddress} as text.
*
* @since 5.0
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java
index a7f2f82..ab864d5 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java
@@ -333,7 +333,12 @@ public class URIBuilder {
this.scheme = uri.getScheme();
this.encodedSchemeSpecificPart = uri.getRawSchemeSpecificPart();
this.encodedAuthority = uri.getRawAuthority();
- this.host = uri.getHost();
+ final String uriHost = uri.getHost();
+ // URI.getHost incorrectly returns bracketed (encoded) IPv6 values. Brackets are an
+ // encoding detail of the URI and not part of the host string.
+ this.host = uriHost != null && InetAddressUtils.isIPv6URLBracketedAddress(uriHost)
+ ? uriHost.substring(1, uriHost.length() - 1)
+ : uriHost;
this.port = uri.getPort();
this.encodedUserInfo = uri.getRawUserInfo();
this.userInfo = uri.getUserInfo();
@@ -454,7 +459,9 @@ public class URIBuilder {
}
/**
- * Sets URI host.
+ * Sets URI host. The input value must not already be URI encoded, for example {@code ::1} is valid however
+ * {@code [::1]} is not. It is dangerous to call {@code uriBuilder.setHost(uri.getHost())} due
+ * to {@link URI#getHost()} returning URI encoded values.
*
* @return this.
*/
@@ -779,6 +786,12 @@ public class URIBuilder {
return this.userInfo;
}
+ /**
+ * Gets the host portion of the {@link URI}. This method returns unencoded IPv6 addresses (without brackets).
+ * This behavior differs from values returned by {@link URI#getHost()}.
+ *
+ * @return The host portion of the URI.
+ */
public String getHost() {
return this.host;
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/net/TestInetAddressUtils.java b/httpcore5/src/test/java/org/apache/hc/core5/net/TestInetAddressUtils.java
index 9d2e9f1..13a742d 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/net/TestInetAddressUtils.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/net/TestInetAddressUtils.java
@@ -79,6 +79,56 @@ public class TestInetAddressUtils {
}
@Test
+ public void testValidIPv6BracketAddress() {
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[2001:0db8:0000:0000:0000:0000:1428:57ab]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[2001:db8:0:0:0:0:1428:57ab]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[0:0:0:0:0:0:0:0]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[0:0:0:0:0:0:0:1]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[2001:0db8:0:0::1428:57ab]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[2001:0db8::1428:57ab]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[2001:db8::1428:57ab]"));
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[::1]"));
+ // http://tools.ietf.org/html/rfc4291#section-2.2
+ Assert.assertTrue(InetAddressUtils.isIPv6URLBracketedAddress("[::]"));
+ }
+
+ @Test
+ public void testInvalidIPv6BracketAddress() {
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("2001:0db8:0000:garb:age0:0000:1428:57ab"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[2001:0db8:0000:garb:age0:0000:1428:57ab]"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("2001:0gb8:0000:0000:0000:0000:1428:57ab"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[2001:0gb8:0000:0000:0000:0000:1428:57ab]"));
+ // Too many
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("0:0:0:0:0:0:0:0:0"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[0:0:0:0:0:0:0:0:0]"));
+ // Too few
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("0:0:0:0:0:0:0"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[0:0:0:0:0:0:0]"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress(":1"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[:1]"));
+ // Cannot have two contractions
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("2001:0db8::0000::57ab"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[2001:0db8::0000::57ab]"));
+ // too many fields before ::
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("1:2:3:4:5:6:7::9"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[1:2:3:4:5:6:7::9]"));
+ // too many fields after ::
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("1::3:4:5:6:7:8:9"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[1::3:4:5:6:7:8:9]"));
+ // too many fields after ::
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("::3:4:5:6:7:8:9"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[::3:4:5:6:7:8:9]"));
+ // empty
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress(""));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("[]"));
+
+ // missing brackets
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("::"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("::1"));
+ Assert.assertFalse(InetAddressUtils.isIPv6URLBracketedAddress("2001:db8::1428:57ab"));
+ }
+
+ @Test
// Test HTTPCLIENT-1319
public void testInvalidIPv6AddressIncorrectGroupCount() {
Assert.assertFalse(InetAddressUtils.isIPv6HexCompressedAddress("1:2::4:5:6:7:8:9")); // too many fields in total
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIBuilder.java b/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIBuilder.java
index 125dd5b..739634a 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIBuilder.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIBuilder.java
@@ -813,4 +813,47 @@ public class TestURIBuilder {
new URIBuilder("http:///../../.././").normalizeSyntax().build().toASCIIString());
}
+ @Test
+ public void testIpv6Host() throws Exception {
+ final URIBuilder builder = new URIBuilder("https://[::1]:432/path");
+ final URI uri = builder.build();
+ Assert.assertEquals(432, builder.getPort());
+ Assert.assertEquals(432, uri.getPort());
+ Assert.assertEquals("https", builder.getScheme());
+ Assert.assertEquals("https", uri.getScheme());
+ Assert.assertEquals("::1", builder.getHost());
+ Assert.assertEquals("[::1]", uri.getHost());
+ Assert.assertEquals("/path", builder.getPath());
+ Assert.assertEquals("/path", uri.getPath());
+ }
+
+ @Test
+ public void testIpv6HostWithPortUpdate() throws Exception {
+ // Updating the port clears URIBuilder.encodedSchemeSpecificPart
+ // and bypasses the fast/simple path which preserves input.
+ final URIBuilder builder = new URIBuilder("https://[::1]:432/path").setPort(123);
+ final URI uri = builder.build();
+ Assert.assertEquals(123, builder.getPort());
+ Assert.assertEquals(123, uri.getPort());
+ Assert.assertEquals("https", builder.getScheme());
+ Assert.assertEquals("https", uri.getScheme());
+ Assert.assertEquals("::1", builder.getHost());
+ Assert.assertEquals("[::1]", uri.getHost());
+ Assert.assertEquals("/path", builder.getPath());
+ Assert.assertEquals("/path", uri.getPath());
+ }
+
+ @Test
+ public void testBuilderWithUnbracketedIpv6Host() throws Exception {
+ final URIBuilder builder = new URIBuilder().setScheme("https").setHost("::1").setPort(443).setPath("/path");
+ final URI uri = builder.build();
+ Assert.assertEquals("https", builder.getScheme());
+ Assert.assertEquals("https", uri.getScheme());
+ Assert.assertEquals(443, builder.getPort());
+ Assert.assertEquals(443, uri.getPort());
+ Assert.assertEquals("::1", builder.getHost());
+ Assert.assertEquals("[::1]", uri.getHost());
+ Assert.assertEquals("/path", builder.getPath());
+ Assert.assertEquals("/path", uri.getPath());
+ }
}