Skip to content

Commit 48a1804

Browse files
committed
HADOOP-19695. Add dual-stack/IPv6 Support to HttpServer2
To enable dual-stack or IPv6 support, use InetAddress.getAllByName(hostname) to resolve the IP addresses of a host. When the system property java.net.preferIPv4Stack is set to true, only IPv4 addresses are returned, and any IPv6 addresses are ignored, so no extra check is needed to exclude IPv6. When java.net.preferIPv4Stack is false, both IPv4 and IPv6 addresses may be returned, and any IPv6 addresses will also be added as connectors. To disable IPv4, you need to configure the OS at the system level.
1 parent 3f638c2 commit 48a1804

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.io.InterruptedIOException;
2424
import java.io.PrintStream;
2525
import java.net.BindException;
26+
import java.net.InetAddress;
2627
import java.net.InetSocketAddress;
2728
import java.net.MalformedURLException;
2829
import java.net.URI;
@@ -549,25 +550,50 @@ public HttpServer2 build() throws IOException {
549550
}
550551

551552
for (URI ep : endpoints) {
552-
final ServerConnector connector;
553+
//
554+
// To enable dual-stack or IPv6 support, use InetAddress
555+
// .getAllByName(hostname) to resolve the IP addresses of a host.
556+
// When the system property java.net.preferIPv4Stack is set to true,
557+
// only IPv4 addresses are returned, and any IPv6 addresses are
558+
// ignored, so no extra check is needed to exclude IPv6.
559+
// When java.net.preferIPv4Stack is false, both IPv4 and IPv6
560+
// addresses may be returned, and any IPv6 addresses will also be
561+
// added as connectors.
562+
// To disable IPv4, you need to configure the OS at the system level.
563+
//
564+
InetAddress[] addresses = InetAddress.getAllByName(ep.getHost());
565+
server = addConnectors(
566+
ep, addresses, server, httpConfig, backlogSize, idleTimeout);
567+
}
568+
server.loadListeners();
569+
return server;
570+
}
571+
572+
@VisibleForTesting
573+
HttpServer2 addConnectors(
574+
URI ep, InetAddress[] addresses, HttpServer2 server,
575+
HttpConfiguration httpConfig, int backlogSize, int idleTimeout){
576+
for (InetAddress addr : addresses) {
577+
ServerConnector connector;
553578
String scheme = ep.getScheme();
554579
if (HTTP_SCHEME.equals(scheme)) {
555-
connector = createHttpChannelConnector(server.webServer,
556-
httpConfig);
580+
connector = createHttpChannelConnector(
581+
server.webServer, httpConfig);
557582
} else if (HTTPS_SCHEME.equals(scheme)) {
558-
connector = createHttpsChannelConnector(server.webServer,
559-
httpConfig);
583+
connector = createHttpsChannelConnector(
584+
server.webServer, httpConfig);
560585
} else {
561586
throw new HadoopIllegalArgumentException(
562587
"unknown scheme for endpoint:" + ep);
563588
}
564-
connector.setHost(ep.getHost());
589+
LOG.debug("Adding connector to WebServer for address {}",
590+
addr.getHostAddress());
591+
connector.setHost(addr.getHostAddress());
565592
connector.setPort(ep.getPort() == -1 ? 0 : ep.getPort());
566593
connector.setAcceptQueueSize(backlogSize);
567594
connector.setIdleTimeout(idleTimeout);
568595
server.addListener(connector);
569596
}
570-
server.loadListeners();
571597
return server;
572598
}
573599

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.hadoop.security.UserGroupInformation;
3131
import org.apache.hadoop.security.authorize.AccessControlList;
3232

33+
import org.eclipse.jetty.server.HttpConfiguration;
3334
import org.eclipse.jetty.server.ServerConnector;
3435
import org.eclipse.jetty.server.handler.StatisticsHandler;
3536
import org.eclipse.jetty.util.ajax.JSON;
@@ -56,6 +57,7 @@
5657
import java.io.PrintWriter;
5758
import java.lang.reflect.Field;
5859
import java.net.HttpURLConnection;
60+
import java.net.InetAddress;
5961
import java.net.URI;
6062
import java.net.URL;
6163
import java.util.Arrays;
@@ -635,6 +637,26 @@ public void testRequiresAuthorizationAccess() throws Exception {
635637
assertFalse(HttpServer2.isInstrumentationAccessAllowed(context, request, response));
636638
}
637639

640+
@Test
641+
public void testAddConnectors() throws Exception {
642+
HttpServer2.Builder builder = new HttpServer2.Builder()
643+
.setName("test").setConf(new Configuration()).setFindPort(false);
644+
URI endpoint = URI.create("http://testaddress.com:8080/my-app");
645+
InetAddress[] addresses = new InetAddress[2];
646+
// IPv4 test address
647+
addresses[0] = InetAddress.getByName("192.168.1.100");
648+
// IPv6 test address
649+
addresses[1] = InetAddress.getByName("fd00::1");
650+
HttpConfiguration httpConfig = new HttpConfiguration();
651+
final int backlogSize = 2048;
652+
final int idleTimeout = 1000;
653+
654+
server = builder.addConnectors(
655+
endpoint, addresses, server, httpConfig, backlogSize, idleTimeout);
656+
//the expected value is 3: the loopback address and the two addresses
657+
assertEquals(server.getListeners().toArray().length, 3);
658+
}
659+
638660
@Test public void testBindAddress() throws Exception {
639661
checkBindAddress("localhost", 0, false).stop();
640662
// hang onto this one for a bit more testing

0 commit comments

Comments
 (0)