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/20 12:35:32 UTC
[httpcomponents-core] branch master updated: HTTPCORE-616: Make
parsing IPv6 ready
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 041b4a7 HTTPCORE-616: Make parsing IPv6 ready
041b4a7 is described below
commit 041b4a7f2b6d7beecdce7ac7b1b304d017a3f8d1
Author: Carter Kozak <ck...@apache.org>
AuthorDate: Mon Apr 5 15:25:23 2021 -0400
HTTPCORE-616: Make parsing IPv6 ready
This adds support for bracketed IPv6 host parsing to the following:
* `org.apache.hc.core5.net.Host.create(String)`
* `org.apache.hc.core5.net.URIAuthority.create(String)`
* `org.apache.hc.core5.http.HttpHost.create(String)`
This commit does not address `InetAddressUtils: Parsing may fail when an
IPv6 scope id might be provided.`
---
.../main/java/org/apache/hc/core5/net/Host.java | 26 ++++++++++++--
.../java/org/apache/hc/core5/net/URISupport.java | 2 ++
.../org/apache/hc/core5/http/TestHttpHost.java | 40 ++++++++++++++++++++++
.../java/org/apache/hc/core5/net/TestHost.java | 33 ++++++++++++++++++
.../org/apache/hc/core5/net/TestURIAuthority.java | 31 +++++++++++++++++
5 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/Host.java b/httpcore5/src/main/java/org/apache/hc/core5/net/Host.java
index d915b0e..2feda01 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/Host.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/Host.java
@@ -60,7 +60,21 @@ public final class Host implements NamedEndpoint, Serializable {
static Host parse(final CharSequence s, final Tokenizer.Cursor cursor) throws URISyntaxException {
final Tokenizer tokenizer = Tokenizer.INSTANCE;
- final String hostName = tokenizer.parseContent(s, cursor, URISupport.PORT_SEPARATORS);
+ final String hostName;
+ final boolean ipv6Brackets = !cursor.atEnd() && s.charAt(cursor.getPos()) == '[';
+ if (ipv6Brackets) {
+ cursor.updatePos(cursor.getPos() + 1);
+ hostName = tokenizer.parseContent(s, cursor, URISupport.IPV6_HOST_TERMINATORS);
+ if (cursor.atEnd() || !(s.charAt(cursor.getPos()) == ']')) {
+ throw URISupport.createException(s, cursor, "Expected an IPv6 closing bracket ']'");
+ }
+ cursor.updatePos(cursor.getPos() + 1);
+ if (!InetAddressUtils.isIPv6Address(hostName)) {
+ throw URISupport.createException(s, cursor, "Expected an IPv6 address");
+ }
+ } else {
+ hostName = tokenizer.parseContent(s, cursor, URISupport.PORT_SEPARATORS);
+ }
String portText = null;
if (!cursor.atEnd() && s.charAt(cursor.getPos()) == ':') {
cursor.updatePos(cursor.getPos() + 1);
@@ -68,6 +82,9 @@ public final class Host implements NamedEndpoint, Serializable {
}
final int port;
if (!TextUtils.isBlank(portText)) {
+ if (!ipv6Brackets && portText.contains(":")) {
+ throw URISupport.createException(s, cursor, "Expected IPv6 address to be enclosed in brackets");
+ }
try {
port = Integer.parseInt(portText);
} catch (final NumberFormatException ex) {
@@ -85,7 +102,12 @@ public final class Host implements NamedEndpoint, Serializable {
}
static void format(final StringBuilder buf, final NamedEndpoint endpoint) {
- buf.append(endpoint.getHostName());
+ final String hostName = endpoint.getHostName();
+ if (InetAddressUtils.isIPv6Address(hostName)) {
+ buf.append('[').append(hostName).append(']');
+ } else {
+ buf.append(hostName);
+ }
if (endpoint.getPort() != -1) {
buf.append(":");
buf.append(endpoint.getPort());
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/URISupport.java b/httpcore5/src/main/java/org/apache/hc/core5/net/URISupport.java
index 6948dc8..e884794 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/URISupport.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/URISupport.java
@@ -34,6 +34,7 @@ import org.apache.hc.core5.util.Tokenizer;
final class URISupport {
static final BitSet HOST_SEPARATORS = new BitSet(256);
+ static final BitSet IPV6_HOST_TERMINATORS = new BitSet(256);
static final BitSet PORT_SEPARATORS = new BitSet(256);
static final BitSet TERMINATORS = new BitSet(256);
@@ -43,6 +44,7 @@ final class URISupport {
TERMINATORS.set('?');
HOST_SEPARATORS.or(TERMINATORS);
HOST_SEPARATORS.set('@');
+ IPV6_HOST_TERMINATORS.set(']');
PORT_SEPARATORS.or(TERMINATORS);
PORT_SEPARATORS.set(':');
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/TestHttpHost.java b/httpcore5/src/test/java/org/apache/hc/core5/http/TestHttpHost.java
index 54019d1..f944f2f 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/TestHttpHost.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/TestHttpHost.java
@@ -230,4 +230,44 @@ public class TestHttpHost {
}
}
+ @Test
+ public void testIpv6HostAndPort() throws Exception {
+ final HttpHost host = HttpHost.create("[::1]:80");
+ Assert.assertEquals("http", host.getSchemeName());
+ Assert.assertEquals("::1", host.getHostName());
+ Assert.assertEquals(80, host.getPort());
+ }
+
+ @Test
+ public void testIpv6HostAndPortWithScheme() throws Exception {
+ final HttpHost host = HttpHost.create("https://[::1]:80");
+ Assert.assertEquals("https", host.getSchemeName());
+ Assert.assertEquals("::1", host.getHostName());
+ Assert.assertEquals(80, host.getPort());
+ }
+
+ @Test
+ public void testIpv6HostAndPortWithoutBrackets() throws Exception {
+ try {
+ // ambiguous
+ HttpHost.create("::1:80");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ }
+ }
+
+ @Test
+ public void testIpv6HostWithoutPort() throws Exception {
+ try {
+ HttpHost.create("::1");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ }
+ }
+
+ @Test
+ public void testIpv6HostToString() {
+ Assert.assertEquals("http://[::1]:80", new HttpHost("::1", 80).toString());
+ Assert.assertEquals("http://[::1]", new HttpHost("::1", -1).toString());
+ }
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/net/TestHost.java b/httpcore5/src/test/java/org/apache/hc/core5/net/TestHost.java
index 71f35d5..d03a35a 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/net/TestHost.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/net/TestHost.java
@@ -129,4 +129,37 @@ public class TestHost {
}
}
+ @Test
+ public void testIpv6HostAndPort() throws Exception {
+ final Host host = Host.create("[::1]:80");
+ Assert.assertEquals("::1", host.getHostName());
+ Assert.assertEquals(80, host.getPort());
+ }
+
+ @Test
+ public void testIpv6HostAndPortWithoutBrackets() {
+ try {
+ // ambiguous
+ Host.create("::1:80");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ Assert.assertTrue(expected.getMessage().contains("Expected IPv6 address to be enclosed in brackets"));
+ }
+ }
+
+ @Test
+ public void testIpv6HostWithoutPort() {
+ try {
+ Host.create("::1");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ Assert.assertTrue(expected.getMessage().contains("Expected IPv6 address to be enclosed in brackets"));
+ }
+ }
+
+ @Test
+ public void testIpv6HostToString() {
+ Assert.assertEquals("[::1]:80", new Host("::1", 80).toString());
+ Assert.assertEquals("[::1]", new Host("::1", -1).toString());
+ }
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIAuthority.java b/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIAuthority.java
index 8aa4a22..3fd972c 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIAuthority.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/net/TestURIAuthority.java
@@ -220,4 +220,35 @@ public class TestURIAuthority {
}
}
+ @Test
+ public void testCreateFromIPv6String() throws Exception {
+ Assert.assertEquals(new URIAuthority("::1", 8080), URIAuthority.create("[::1]:8080"));
+ Assert.assertEquals(new URIAuthority("::1", -1), URIAuthority.create("[::1]"));
+ try {
+ URIAuthority.create("::1");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ }
+ try {
+ URIAuthority.create("[::1");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ Assert.assertTrue(expected.getMessage().contains("Expected an IPv6 closing bracket"));
+ }
+
+ try {
+ URIAuthority.create("[a]:8080");
+ Assert.fail("URISyntaxException expected");
+ } catch (final URISyntaxException expected) {
+ Assert.assertTrue(expected.getMessage().contains("Expected an IPv6 address"));
+ }
+ }
+
+ @Test
+ public void testIpv6HostToString() {
+ Assert.assertEquals("[::1]:80", new URIAuthority("::1", 80).toString());
+ Assert.assertEquals("user@[::1]:80", new URIAuthority("user", "::1", 80).toString());
+ Assert.assertEquals("[::1]", new URIAuthority("::1", -1).toString());
+ Assert.assertEquals("user@[::1]", new URIAuthority("user", "::1", -1).toString());
+ }
}