diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java index 2649d279aa1..998c741d019 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java @@ -198,8 +198,16 @@ public Path(String pathString) throws IllegalArgumentException { 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); diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java index f1e209fe1f9..4c15a94135b 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java @@ -46,6 +46,7 @@ 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; @@ -218,6 +219,22 @@ public static InetSocketAddress createSocketAddr(String target, } 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(); @@ -270,6 +287,24 @@ private static URI createURI(String target, 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 diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java index 0bf2c4473a7..63c010ddfdf 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java @@ -778,4 +778,41 @@ private void assertBetterArrayEquals(T[] expect, T[]got) { 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()); + } }