You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2020/07/31 16:37:40 UTC

[httpcomponents-core] 02/02: RFC 3986 conformance: support percent-encoded reserved characters in the host component; host component can be empty

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch 5.1.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 19feeaea169e205a76cc8ee1ba2cb79e33fa9efe
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sat Jul 25 12:47:27 2020 +0200

    RFC 3986 conformance: support percent-encoded reserved characters in the host component; host component can be empty
---
 .../main/java/org/apache/hc/core5/net/URIAuthority.java    | 10 +---------
 .../src/main/java/org/apache/hc/core5/net/URIBuilder.java  | 14 ++++++++++++--
 .../java/org/apache/hc/core5/net/TestURIAuthority.java     | 14 ++++----------
 .../test/java/org/apache/hc/core5/net/TestURIBuilder.java  | 14 ++++++++++++++
 4 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/URIAuthority.java b/httpcore5/src/main/java/org/apache/hc/core5/net/URIAuthority.java
index 1cae817..920c426 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/URIAuthority.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/URIAuthority.java
@@ -34,7 +34,6 @@ import java.util.Locale;
 
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.LangUtils;
 import org.apache.hc.core5.util.TextUtils;
 import org.apache.hc.core5.util.Tokenizer;
@@ -104,9 +103,6 @@ public final class URIAuthority implements NamedEndpoint, Serializable {
         } else {
             hostName = token;
         }
-        if (TextUtils.isBlank(hostName)) {
-            throw createException(s, cursor, "Authority host is empty");
-        }
         final int port;
         if (!TextUtils.isBlank(portText)) {
             try {
@@ -162,12 +158,8 @@ public final class URIAuthority implements NamedEndpoint, Serializable {
      */
     public URIAuthority(final String userInfo, final String hostname, final int port) {
         super();
-        Args.containsNoBlanks(hostname, "Host name");
-        if (userInfo != null) {
-            Args.containsNoBlanks(userInfo, "User info");
-        }
         this.userInfo = userInfo;
-        this.hostname = hostname.toLowerCase(Locale.ROOT);
+        this.hostname = hostname != null ? hostname.toLowerCase(Locale.ROOT) : null;
         this.port = Ports.checkWithDefault(port);
     }
 
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 70358e2..c8f3fa7 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
@@ -292,7 +292,7 @@ public class URIBuilder {
                 if (InetAddressUtils.isIPv6Address(this.host)) {
                     sb.append("[").append(this.host).append("]");
                 } else {
-                    sb.append(this.host);
+                    sb.append(PercentCodec.encode(this.host, this.charset));
                 }
                 if (this.port >= 0) {
                     sb.append(":").append(this.port);
@@ -336,6 +336,16 @@ public class URIBuilder {
         this.port = uri.getPort();
         this.encodedUserInfo = uri.getRawUserInfo();
         this.userInfo = uri.getUserInfo();
+        if (this.encodedAuthority != null && this.host == null) {
+            try {
+                final URIAuthority uriAuthority = URIAuthority.parse(this.encodedAuthority);
+                this.encodedUserInfo = uriAuthority.getUserInfo();
+                this.userInfo = PercentCodec.decode(uriAuthority.getUserInfo(), charset);
+                this.host = PercentCodec.decode(uriAuthority.getHostName(), charset);
+                this.port = uriAuthority.getPort();
+            } catch (final URISyntaxException ignore) {
+            }
+        }
         this.encodedPath = uri.getRawPath();
         this.pathSegments = parsePath(uri.getRawPath(), charset);
         this.pathRootless = uri.getRawPath() != null && !uri.getRawPath().startsWith("/");
@@ -447,7 +457,7 @@ public class URIBuilder {
      * @return this.
      */
     public URIBuilder setHost(final String host) {
-        this.host = !TextUtils.isBlank(host) ? host : null;
+        this.host = host;
         this.encodedSchemeSpecificPart = null;
         this.encodedAuthority = null;
         return this;
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 76c3b41..3aa1986 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
@@ -129,16 +129,10 @@ public class TestURIAuthority {
                 CoreMatchers.equalTo(new URIAuthority("somehost", -1)));
         MatcherAssert.assertThat(URIAuthority.parse("somehost#blah"),
                 CoreMatchers.equalTo(new URIAuthority("somehost", -1)));
-        try {
-            URIAuthority.create("aaaa@:8080");
-            Assert.fail("URISyntaxException expected");
-        } catch (final URISyntaxException expected) {
-        }
-        try {
-            URIAuthority.create("@:");
-            Assert.fail("URISyntaxException expected");
-        } catch (final URISyntaxException expected) {
-        }
+        MatcherAssert.assertThat(URIAuthority.parse("aaaa@:8080"),
+                CoreMatchers.equalTo(new URIAuthority("aaaa", "", 8080)));
+        MatcherAssert.assertThat(URIAuthority.parse("@:"),
+                CoreMatchers.equalTo(new URIAuthority(null, "", -1)));
         MatcherAssert.assertThat(URIAuthority.parse("somehost:8080"),
                 CoreMatchers.equalTo(new URIAuthority("somehost", 8080)));
         MatcherAssert.assertThat(URIAuthority.parse("somehost:8080/blah"),
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 ea153cf..8e5b334 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
@@ -512,6 +512,20 @@ public class TestURIBuilder {
     }
 
     @Test
+    public void testSetHostWithReservedChars() throws Exception {
+        final URIBuilder uribuilder = new URIBuilder();
+        uribuilder.setScheme("http").setHost("!example!.com");
+        Assert.assertEquals(URI.create("http://%21example%21.com"), uribuilder.build());
+    }
+
+    @Test
+    public void testGetHostWithReservedChars() throws Exception {
+        final URIBuilder uribuilder = new URIBuilder("http://someuser%21@%21example%21.com/");
+        Assert.assertEquals("!example!.com", uribuilder.getHost());
+        Assert.assertEquals("someuser!", uribuilder.getUserInfo());
+    }
+
+    @Test
     public void testMultipleLeadingPathSlashes() throws Exception {
         final URI uri = new URIBuilder()
                 .setScheme("ftp")