浏览代码

HADOOP-17542. IPV6 support in Netutils#createSocketAddress (#3217)

* HADOOP-17542. IPV6 support in Netutils#createSocketAddress

* HADOOP-17542. IPV6 support in Netutils#createSocketAddress, review comments
Renukaprasad C 3 年之前
父节点
当前提交
c0f0b33e40

+ 9 - 1
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java

@@ -199,8 +199,16 @@ public class Path
     int start = 0;
 
     // parse uri scheme, if any
-    int colon = pathString.indexOf(':');
+    int colon = -1;
     int slash = pathString.indexOf('/');
+    if (StringUtils.countMatches(pathString, ":") > 2) {
+      //In case of IPv6 address, we should be able to parse the scheme
+      // correctly (This will ensure to parse path with & without scheme
+      // correctly in IPv6).
+      colon = pathString.indexOf(":/");
+    } else {
+      colon = pathString.indexOf(':');
+    }
     if ((colon != -1) &&
         ((slash == -1) || (colon < slash))) {     // has a scheme
       scheme = pathString.substring(0, colon);

+ 35 - 0
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java

@@ -45,6 +45,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import javax.net.SocketFactory;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.hadoop.security.AccessControlException;
 import org.apache.hadoop.thirdparty.com.google.common.cache.Cache;
 import org.apache.hadoop.thirdparty.com.google.common.cache.CacheBuilder;
@@ -223,6 +224,22 @@ public class NetUtils {
     }
     target = target.trim();
     boolean hasScheme = target.contains("://");
+    if (StringUtils.countMatches(target, ":") > 2) {
+      // if scheme exists in the target
+      // for example : https://ffff:ffff:ffff:ffff::1:XXXXX
+      // we have to form https://[ffff:ffff:ffff:ffff::1]:XXXXX
+      if (hasScheme) {
+        int i = target.lastIndexOf("/");
+        String scheme = target.substring(0, i + 1);
+        String ipAddrWithPort = target.substring(i + 1);
+        target = scheme + normalizeV6Address(ipAddrWithPort);
+      } else {
+        // if scheme does not exists in the target
+        // for example : ffff:ffff:ffff:ffff::1:XXXXX
+        // we have to form [ffff:ffff:ffff:ffff::1]:XXXXX
+        target = normalizeV6Address(target);
+      }
+    }
     URI uri = createURI(target, hasScheme, helpText, useCacheIfPresent);
 
     String host = uri.getHost();
@@ -275,6 +292,24 @@ public class NetUtils {
     return uri;
   }
 
+  public static String normalizeV6Address(String target) {
+    if (!target.startsWith("[")) {
+      if (target.contains("%")) {
+        int i = target.lastIndexOf('%');
+        target = target.trim();
+        String port = target.substring(target.lastIndexOf(":") + 1);
+        String addr = target.substring(0, i);
+        target = "[" + addr + "]" + ":" + port;
+      } else {
+        int i = target.lastIndexOf(':');
+        String port = target.substring(target.lastIndexOf(":") + 1);
+        String addr = target.substring(0, i);
+        target = "[" + addr + "]" + ":" + port;
+      }
+    }
+    return target;
+  }
+
   /**
    * Create a socket address with the given host and port.  The hostname
    * might be replaced with another host that was set via

+ 37 - 0
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java

@@ -817,4 +817,41 @@ public class TestNetUtils {
     String gotStr = StringUtils.join(got, ", ");
     assertEquals(expectStr, gotStr);
   }
+
+  @Test
+  public void testCreateSocketAddressWithIPV6() throws Throwable {
+    String ipv6Address = "2a03:2880:2130:cf05:face:b00c:0:1";
+    String ipv6WithPort = ipv6Address + ":12345";
+
+    InetSocketAddress addr = NetUtils.createSocketAddr(ipv6WithPort,
+        1000, "myconfig");
+    assertEquals("[" + ipv6Address + "]", addr.getHostName());
+    assertEquals(12345, addr.getPort());
+
+    String ipv6SampleAddressWithScope = ipv6Address + "%2";
+    ipv6WithPort = ipv6SampleAddressWithScope + ":12345";
+    addr = NetUtils.createSocketAddr(ipv6WithPort, 1000, "myconfig");
+    assertEquals("[" + ipv6Address + "]", addr.getHostName());
+    assertEquals(12345, addr.getPort());
+
+    ipv6Address = "[2a03:2880:2130:cf05:face:b00c:0:1]";
+    ipv6WithPort = ipv6Address + ":12345";
+
+    addr = NetUtils.createSocketAddr(ipv6WithPort, 1000, "myconfig");
+    assertEquals(ipv6Address, addr.getHostName());
+    assertEquals(12345, addr.getPort());
+
+    String ipv6AddressWithScheme =
+        "https://2a03:2880:2130:cf05:face:b00c:0:1:12345";
+    addr = NetUtils.createSocketAddr(ipv6AddressWithScheme, 1000,
+        "myconfig");
+    assertEquals(ipv6Address, addr.getHostName());
+    assertEquals(12345, addr.getPort());
+
+    ipv6AddressWithScheme = "https://[2a03:2880:2130:cf05:face:b00c:0:1]:12345";
+    addr = NetUtils.createSocketAddr(ipv6AddressWithScheme, 1000,
+        "myconfig");
+    assertEquals(ipv6Address, addr.getHostName());
+    assertEquals(12345, addr.getPort());
+  }
 }