You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by nk...@apache.org on 2020/10/09 11:55:01 UTC

[zookeeper] branch branch-3.5 updated: ZOOKEEPER-3886: Client connection string should support IPV6 with or without enclosed in square bracket

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

nkalmar pushed a commit to branch branch-3.5
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/branch-3.5 by this push:
     new 5a149c5  ZOOKEEPER-3886: Client connection string should support IPV6 with or without enclosed in square bracket
5a149c5 is described below

commit 5a149c5a09b2c7dcac28d5b546c833fcc90f9934
Author: Mohammad Arshad <ar...@apache.org>
AuthorDate: Fri Oct 9 13:54:53 2020 +0200

    ZOOKEEPER-3886: Client connection string should support IPV6 with or without enclosed in square bracket
    
    …without enclosed in square bracket.
    
    Author: Mohammad Arshad <ar...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@apache.org>, Norbert Kalmar <nk...@apache.org>
    
    Closes #1494 from arshadmohammad/ZOOKEEPER-3886-branch-3.5
---
 .../zookeeper/client/ConnectStringParser.java      | 21 ++++++---
 .../java/org/apache/zookeeper/common/NetUtils.java | 45 ++++++++++++++++++
 .../org/apache/zookeeper/common/NetUtilsTest.java  | 54 ++++++++++++++++++++--
 .../zookeeper/test/ConnectStringParserTest.java    | 22 +++++++++
 4 files changed, 132 insertions(+), 10 deletions(-)

diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/client/ConnectStringParser.java b/zookeeper-server/src/main/java/org/apache/zookeeper/client/ConnectStringParser.java
index 085e44d..fe24fa2 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/client/ConnectStringParser.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/client/ConnectStringParser.java
@@ -18,6 +18,7 @@
 
 package org.apache.zookeeper.client;
 
+import org.apache.zookeeper.common.NetUtils;
 import org.apache.zookeeper.common.PathUtils;
 
 import java.net.InetSocketAddress;
@@ -68,13 +69,21 @@ public final class ConnectStringParser {
         List<String> hostsList = split(connectString,",");
         for (String host : hostsList) {
             int port = DEFAULT_PORT;
-            int pidx = host.lastIndexOf(':');
-            if (pidx >= 0) {
-                // otherwise : is at the end of the string, ignore
-                if (pidx < host.length() - 1) {
-                    port = Integer.parseInt(host.substring(pidx + 1));
+            String[] hostAndPort = NetUtils.getIPV6HostAndPort(host);
+            if (hostAndPort.length != 0) {
+                host = hostAndPort[0];
+                if (hostAndPort.length == 2) {
+                    port = Integer.parseInt(hostAndPort[1]);
+                }
+            } else {
+                int pidx = host.lastIndexOf(':');
+                if (pidx >= 0) {
+                    // otherwise : is at the end of the string, ignore
+                    if (pidx < host.length() - 1) {
+                        port = Integer.parseInt(host.substring(pidx + 1));
+                    }
+                    host = host.substring(0, pidx);
                 }
-                host = host.substring(0, pidx);
             }
             serverAddresses.add(InetSocketAddress.createUnresolved(host, port));
         }
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/NetUtils.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/NetUtils.java
index 4779003..a5f43d9 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/NetUtils.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/NetUtils.java
@@ -40,4 +40,49 @@ public class NetUtils {
             return String.format("%s:%s", ia.getHostAddress(), addr.getPort());
         }
     }
+
+    /**
+     * Separates host and port from given host port string if host port string is enclosed
+     * within square bracket.
+     *
+     * @param hostPort host port string
+     * @return String[]{host, port} if host port string is host:port
+     * or String[] {host, port:port} if host port string is host:port:port
+     * or String[] {host} if host port string is host
+     * or String[]{} if not a ipv6 host port string.
+     */
+    public static String[] getIPV6HostAndPort(String hostPort) {
+        if (hostPort.startsWith("[")) {
+            int i = hostPort.lastIndexOf(']');
+            if (i < 0) {
+                throw new IllegalArgumentException(
+                    hostPort + " starts with '[' but has no matching ']'");
+            }
+            String host = hostPort.substring(1, i);
+            if (host.isEmpty()) {
+                throw new IllegalArgumentException(host + " is empty.");
+            }
+            if (hostPort.length() > i + 1) {
+                return getHostPort(hostPort, i, host);
+            }
+            return new String[] { host };
+        } else {
+            //Not an IPV6 host port string
+            return new String[] {};
+        }
+    }
+
+    private static String[] getHostPort(String hostPort, int indexOfClosingBracket, String host) {
+        // [127::1]:2181 , check separator : exits
+        if (hostPort.charAt(indexOfClosingBracket + 1) != ':') {
+            throw new IllegalArgumentException(hostPort + " does not have : after ]");
+        }
+        // [127::1]: scenario
+        if (indexOfClosingBracket + 2 == hostPort.length()) {
+            throw new IllegalArgumentException(hostPort + " doesn't have a port after colon.");
+        }
+        //do not include
+        String port = hostPort.substring(indexOfClosingBracket + 2);
+        return new String[] { host, port };
+    }
 }
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/NetUtilsTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/NetUtilsTest.java
index 4f8379e..81aff78 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/common/NetUtilsTest.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/NetUtilsTest.java
@@ -18,6 +18,7 @@
 
 package org.apache.zookeeper.common;
 
+import static org.junit.Assert.assertEquals;
 import org.apache.zookeeper.ZKTestCase;
 import org.hamcrest.core.AnyOf;
 import org.hamcrest.core.IsEqual;
@@ -38,21 +39,21 @@ public class NetUtilsTest extends ZKTestCase {
     @Test
     public void testFormatInetAddrGoodIpv4() {
         InetSocketAddress isa = new InetSocketAddress(v4addr, port);
-        Assert.assertEquals("127.0.0.1:1234", NetUtils.formatInetAddr(isa));
+        assertEquals("127.0.0.1:1234", NetUtils.formatInetAddr(isa));
     }
 
     @Test
     public void testFormatInetAddrGoodIpv6Local() {
         // Have to use the expanded address here, hence not using v6addr in instantiation
         InetSocketAddress isa = new InetSocketAddress("::1", port);
-        Assert.assertEquals(v6local, NetUtils.formatInetAddr(isa));
+        assertEquals(v6local, NetUtils.formatInetAddr(isa));
     }
 
     @Test
     public void testFormatInetAddrGoodIpv6Ext() {
         // Have to use the expanded address here, hence not using v6addr in instantiation
         InetSocketAddress isa = new InetSocketAddress("2600::", port);
-        Assert.assertEquals(v6ext, NetUtils.formatInetAddr(isa));
+        assertEquals(v6ext, NetUtils.formatInetAddr(isa));
     }
 
     @Test
@@ -67,6 +68,51 @@ public class NetUtilsTest extends ZKTestCase {
     @Test
     public void testFormatAddrUnresolved() {
         InetSocketAddress isa = InetSocketAddress.createUnresolved("doesnt.exist.com", 1234);
-        Assert.assertEquals("doesnt.exist.com:1234", NetUtils.formatInetAddr(isa));
+        assertEquals("doesnt.exist.com:1234", NetUtils.formatInetAddr(isa));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void tetGetIPV6HostAndPort_WhenHostDoesNotEndWithBracket() {
+        NetUtils.getIPV6HostAndPort("[2001:0db8:85a3:0000:0000:8a2e:0370:7334:443");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void tetGetIPV6HostAndPort_WhenNoPortAfterColon() {
+        NetUtils.getIPV6HostAndPort("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void tetGetIPV6HostAndPort_WhenPortIsNotSeparatedProperly() {
+        NetUtils.getIPV6HostAndPort("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]2181");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void tetGetIPV6HostAndPort_WhenHostIsEmpty() {
+        NetUtils.getIPV6HostAndPort("[]:2181");
+    }
+
+    @Test
+    public void tetGetIPV6HostAndPort_EmptyStringArrayIfDoesNotStartWithBracket() {
+        String[] ipv6HostAndPort =
+            NetUtils.getIPV6HostAndPort("2001:0db8:85a3:0000:0000:8a2e:0370:7334]");
+        assertEquals(0, ipv6HostAndPort.length);
+    }
+
+    @Test
+    public void tetGetIPV6HostAndPort_ReturnHostPort() {
+        String[] ipv6HostAndPort =
+            NetUtils.getIPV6HostAndPort("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:2181");
+        assertEquals(2, ipv6HostAndPort.length);
+        assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", ipv6HostAndPort[0]);
+        assertEquals("2181", ipv6HostAndPort[1]);
+    }
+
+    @Test
+    public void tetGetIPV6HostAndPort_ReturnHostPortPort() {
+        String[] ipv6HostAndPort =
+            NetUtils.getIPV6HostAndPort("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:2181:3181");
+        assertEquals(2, ipv6HostAndPort.length);
+        assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", ipv6HostAndPort[0]);
+        assertEquals("2181:3181", ipv6HostAndPort[1]);
     }
 }
\ No newline at end of file
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ConnectStringParserTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ConnectStringParserTest.java
index 393cc03..1444d69 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ConnectStringParserTest.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ConnectStringParserTest.java
@@ -65,4 +65,26 @@ public class ConnectStringParserTest extends ZKTestCase{
     private void assertChrootPath(String expected, ConnectStringParser parser){
         Assert.assertEquals(expected, parser.getChrootPath());
     }
+
+    @Test
+    public void testParseIPV6ConnectionString() {
+        String servers = "[127::1],127.0.10.2";
+        ConnectStringParser parser = new ConnectStringParser(servers);
+
+        Assert.assertEquals("127::1", parser.getServerAddresses().get(0).getHostString());
+        Assert.assertEquals("127.0.10.2", parser.getServerAddresses().get(1).getHostString());
+        Assert.assertEquals(2181, parser.getServerAddresses().get(0).getPort());
+        Assert.assertEquals(2181, parser.getServerAddresses().get(1).getPort());
+
+        servers = "[127::1]:2181,[127::2]:2182,[127::3]:2183";
+        parser = new ConnectStringParser(servers);
+
+        Assert.assertEquals("127::1", parser.getServerAddresses().get(0).getHostString());
+        Assert.assertEquals("127::2", parser.getServerAddresses().get(1).getHostString());
+        Assert.assertEquals("127::3", parser.getServerAddresses().get(2).getHostString());
+        Assert.assertEquals(2181, parser.getServerAddresses().get(0).getPort());
+        Assert.assertEquals(2182, parser.getServerAddresses().get(1).getPort());
+        Assert.assertEquals(2183, parser.getServerAddresses().get(2).getPort());
+    }
+
 }