http-client-branch: more binding to 0.0.0.0 instead of localhost/127.0.0.1 http-client-branch
authordfuchs
Tue, 06 Feb 2018 11:04:44 +0000
branchhttp-client-branch
changeset 56076 9a2855e0a796
parent 56075 c76699d2e572
child 56077 3f6b75adcdc0
http-client-branch: more binding to 0.0.0.0 instead of localhost/127.0.0.1
test/jdk/java/net/httpclient/AbstractNoBody.java
test/jdk/java/net/httpclient/CancelledResponse.java
test/jdk/java/net/httpclient/ConcurrentResponses.java
test/jdk/java/net/httpclient/CustomResponseSubscriber.java
test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java
test/jdk/java/net/httpclient/LineBodyHandlerTest.java
test/jdk/java/net/httpclient/MockServer.java
test/jdk/java/net/httpclient/ProxyTest.java
test/jdk/java/net/httpclient/SplitResponse.java
test/jdk/java/net/httpclient/http2/ProxyTest2.java
test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java
--- a/test/jdk/java/net/httpclient/AbstractNoBody.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/AbstractNoBody.java	Tue Feb 06 11:04:44 2018 +0000
@@ -101,7 +101,7 @@
         // HTTP/1.1
         HttpHandler h1_fixedLengthNoBodyHandler = new HTTP1_FixedLengthNoBodyHandler();
         HttpHandler h1_chunkNoBodyHandler = new HTTP1_ChunkedNoBodyHandler();
-        InetSocketAddress sa = new InetSocketAddress("localhost", 0);
+        InetSocketAddress sa = new InetSocketAddress(0);
         httpTestServer = HttpServer.create(sa, 0);
         httpTestServer.setExecutor(serverExecutor);
         httpTestServer.createContext("/http1/noBodyFixed", h1_fixedLengthNoBodyHandler);
--- a/test/jdk/java/net/httpclient/CancelledResponse.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/CancelledResponse.java	Tue Feb 06 11:04:44 2018 +0000
@@ -50,6 +50,7 @@
 
 import static java.lang.String.format;
 import static java.lang.System.out;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
 
 /**
  * @test
@@ -73,7 +74,9 @@
         if (!serverKeepalive)
             sb.append("Connection: Close\r\n");
 
-        sb.append("Content-length: ").append(body.length()).append("\r\n");
+        sb.append("Content-length: ")
+                .append(body.getBytes(ISO_8859_1).length)
+                .append("\r\n");
         sb.append("\r\n");
         sb.append(body);
         return sb.toString();
--- a/test/jdk/java/net/httpclient/ConcurrentResponses.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/ConcurrentResponses.java	Tue Feb 06 11:04:44 2018 +0000
@@ -254,7 +254,7 @@
         if (sslContext == null)
             throw new AssertionError("Unexpected null sslContext");
 
-        InetSocketAddress sa = new InetSocketAddress("localhost", 0);
+        InetSocketAddress sa = new InetSocketAddress(0);
         httpTestServer = HttpServer.create(sa, 0);
         httpTestServer.createContext("/http1/fixed", new Http1FixedHandler());
         httpFixedURI = "http://127.0.0.1:" + httpTestServer.getAddress().getPort() + "/http1/fixed";
--- a/test/jdk/java/net/httpclient/CustomResponseSubscriber.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/CustomResponseSubscriber.java	Tue Feb 06 11:04:44 2018 +0000
@@ -188,7 +188,7 @@
         // HTTP/1.1
         HttpHandler h1_fixedLengthHandler = new HTTP1_FixedLengthHandler();
         HttpHandler h1_chunkHandler = new HTTP1_ChunkedHandler();
-        InetSocketAddress sa = new InetSocketAddress("localhost", 0);
+        InetSocketAddress sa = new InetSocketAddress(0);
         httpTestServer = HttpServer.create(sa, 0);
         httpTestServer.createContext("/http1/fixed", h1_fixedLengthHandler);
         httpTestServer.createContext("/http1/chunk", h1_chunkHandler);
--- a/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java	Tue Feb 06 11:04:44 2018 +0000
@@ -334,7 +334,7 @@
         if (sslContext == null)
             throw new AssertionError("Unexpected null sslContext");
 
-        InetSocketAddress sa = new InetSocketAddress("localhost", 0);
+        InetSocketAddress sa = new InetSocketAddress(0);
         httpTestServer = HttpServer.create(sa, 0);
         httpTestServer.createContext("/http1/echo", new Http1EchoHandler());
         httpURI = "http://127.0.0.1:" + httpTestServer.getAddress().getPort() + "/http1/echo";
--- a/test/jdk/java/net/httpclient/LineBodyHandlerTest.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/LineBodyHandlerTest.java	Tue Feb 06 11:04:44 2018 +0000
@@ -649,7 +649,7 @@
         if (sslContext == null)
             throw new AssertionError("Unexpected null sslContext");
 
-        InetSocketAddress sa = new InetSocketAddress("localhost", 0);
+        InetSocketAddress sa = new InetSocketAddress(0);
         httpTestServer = HttpTestServer.of(HttpServer.create(sa, 0));
         httpTestServer.addHandler(new HttpTestEchoHandler(), "/http1/echo");
         int port = httpTestServer.getAddress().getPort();
--- a/test/jdk/java/net/httpclient/MockServer.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/MockServer.java	Tue Feb 06 11:04:44 2018 +0000
@@ -37,6 +37,7 @@
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
 
 /**
  * A cut-down Http/1 Server for testing various error situations
@@ -160,7 +161,7 @@
                         cleanup();
                         return;
                     }
-                    String s0 = new String(buf, 0, n, StandardCharsets.ISO_8859_1);
+                    String s0 = new String(buf, 0, n, ISO_8859_1);
                     s = s + s0;
                     int i;
                     while ((i=s.indexOf(CRLF)) != -1) {
@@ -195,7 +196,7 @@
             for (int i=0; i<headers.length; i+=2) {
                 r1 += headers[i] + ": " + headers[i+1] + CRLF;
             }
-            int clen = body == null ? 0 : body.length();
+            int clen = body == null ? 0 : body.getBytes(ISO_8859_1).length;
             r1 += "Content-Length: " + Integer.toString(clen) + CRLF;
             r1 += CRLF;
             if (body != null) {
@@ -208,7 +209,7 @@
         public void sendIncompleteHttpResponseBody(int code) throws IOException {
             String body = "Hello World Helloworld Goodbye World";
             String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
-            int clen = body.length() + 10;
+            int clen = body.getBytes(ISO_8859_1).length + 10;
             r1 += "Content-Length: " + Integer.toString(clen) + CRLF;
             r1 += CRLF;
             if (body != null) {
@@ -226,7 +227,7 @@
 
         public void send(String r) throws IOException {
             try {
-                os.write(r.getBytes(StandardCharsets.ISO_8859_1));
+                os.write(r.getBytes(ISO_8859_1));
             } catch (IOException x) {
                 IOException suppressed =
                         new IOException("MockServer["
--- a/test/jdk/java/net/httpclient/ProxyTest.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/ProxyTest.java	Tue Feb 06 11:04:44 2018 +0000
@@ -47,6 +47,8 @@
 import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CopyOnWriteArrayList;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
@@ -102,7 +104,7 @@
         });
 
         server.setHttpsConfigurator(new Configurator(SSLContext.getDefault()));
-        server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
+        server.bind(new InetSocketAddress(0), 0);
         return server;
     }
 
@@ -162,7 +164,8 @@
     {
         System.out.println("Server is: " + server.getAddress().toString());
         System.out.println("Verifying communication with server");
-        URI uri = new URI("https:/" + server.getAddress().toString() + PATH + "x");
+        URI uri = new URI("https://localhost:"
+                          + server.getAddress().getPort() + PATH + "x");
         try (InputStream is = uri.toURL().openConnection().getInputStream()) {
             String resp = new String(is.readAllBytes(), StandardCharsets.UTF_8);
             System.out.println(resp);
@@ -177,7 +180,8 @@
         try {
             System.out.println("Proxy started");
             Proxy p = new Proxy(Proxy.Type.HTTP,
-                    InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
+                    InetSocketAddress.createUnresolved("localhost",
+                            proxy.getAddress().getPort()));
             System.out.println("Verifying communication with proxy");
             HttpURLConnection conn = (HttpURLConnection)uri.toURL().openConnection(p);
             try (InputStream is = conn.getInputStream()) {
@@ -192,7 +196,8 @@
             System.out.println("Setting up request with HttpClient for version: "
                     + version.name());
             CountingProxySelector ps = CountingProxySelector.of(
-                    InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
+                    InetSocketAddress.createUnresolved("localhost",
+                            proxy.getAddress().getPort()));
             HttpClient client = HttpClient.newBuilder()
                 .version(version)
                 .proxy(ps)
@@ -226,19 +231,24 @@
         final ServerSocket ss;
         final boolean DEBUG = false;
         final HttpServer serverImpl;
+        final CopyOnWriteArrayList<CompletableFuture<Void>> connectionCFs
+                = new CopyOnWriteArrayList<>();
+        private volatile boolean stopped;
         TunnelingProxy(HttpServer serverImpl) throws IOException {
             this.serverImpl = serverImpl;
             ss = new ServerSocket();
             accept = new Thread(this::accept);
+            accept.setDaemon(true);
         }
 
         void start() throws IOException {
-            ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+            ss.bind(new InetSocketAddress(0));
             accept.start();
         }
 
         // Pipe the input stream to the output stream.
-        private synchronized Thread pipe(InputStream is, OutputStream os, char tag) {
+        private synchronized Thread pipe(InputStream is, OutputStream os,
+                                         char tag, CompletableFuture<Void> end) {
             return new Thread("TunnelPipe("+tag+")") {
                 @Override
                 public void run() {
@@ -258,13 +268,17 @@
                         }
                     } catch (IOException ex) {
                         if (DEBUG) ex.printStackTrace(System.out);
+                    } finally {
+                        end.complete(null);
                     }
                 }
             };
         }
 
         public InetSocketAddress getAddress() {
-            return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
+            return new InetSocketAddress(
+                    "localhost",
+                    ss.getLocalPort());
         }
 
         // This is a bit shaky. It doesn't handle continuation
@@ -289,18 +303,14 @@
         public void accept() {
             Socket clientConnection = null;
             try {
-                while (true) {
+                while (!stopped) {
                     System.out.println("Tunnel: Waiting for client");
-                    Socket previous = clientConnection;
+                    Socket toClose;
                     try {
-                        clientConnection = ss.accept();
+                        toClose = clientConnection = ss.accept();
                     } catch (IOException io) {
                         if (DEBUG) io.printStackTrace(System.out);
                         break;
-                    } finally {
-                        // we have only 1 client at a time, so it is safe
-                        // to close the previous connection here
-                        if (previous != null) previous.close();
                     }
                     System.out.println("Tunnel: Client accepted");
                     Socket targetConnection = null;
@@ -325,7 +335,7 @@
 
                         // Open target connection
                         targetConnection = new Socket(
-                                serverImpl.getAddress().getAddress(),
+                                InetAddress.getLoopbackAddress(),
                                 serverImpl.getAddress().getPort());
 
                         // Then send the 200 OK response to the client
@@ -334,26 +344,45 @@
                         pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
                         pw.flush();
                     } else {
-                        // This should not happen.
-                        throw new IOException("Tunnel: Unexpected status line: "
-                                           + requestLine);
+                        // This should not happen. If it does then just print an
+                        // error - both on out and err, and close the accepted
+                        // socket
+                        System.out.println("WARNING: Tunnel: Unexpected status line: "
+                                + requestLine + " received by "
+                                + ss.getLocalSocketAddress()
+                                + " from "
+                                + toClose.getRemoteSocketAddress()
+                                + " - closing accepted socket");
+                        // Print on err
+                        System.err.println("WARNING: Tunnel: Unexpected status line: "
+                                + requestLine + " received by "
+                                + ss.getLocalSocketAddress()
+                                + " from "
+                                + toClose.getRemoteSocketAddress());
+                        // close accepted socket.
+                        toClose.close();
+                        System.err.println("Tunnel: accepted socket closed.");
+                        continue;
                     }
 
                     // Pipe the input stream of the client connection to the
                     // output stream of the target connection and conversely.
                     // Now the client and target will just talk to each other.
                     System.out.println("Tunnel: Starting tunnel pipes");
-                    Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
-                    Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
+                    CompletableFuture<Void> end, end1, end2;
+                    Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+',
+                            end1 = new CompletableFuture<>());
+                    Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-',
+                            end2 = new CompletableFuture<>());
+                    end = CompletableFuture.allOf(end1, end2);
+                    end.whenComplete(
+                            (r,t) -> {
+                                try { toClose.close(); } catch (IOException x) { }
+                                finally {connectionCFs.remove(end);}
+                            });
+                    connectionCFs.add(end);
                     t1.start();
                     t2.start();
-
-                    // We have only 1 client... wait until it has finished before
-                    // accepting a new connection request.
-                    // System.out.println("Tunnel: Waiting for pipes to close");
-                    // t1.join();
-                    // t2.join();
-                    System.out.println("Tunnel: Done - waiting for next client");
                 }
             } catch (Throwable ex) {
                 try {
@@ -362,10 +391,14 @@
                     ex.addSuppressed(ex1);
                 }
                 ex.printStackTrace(System.err);
+            } finally {
+                System.out.println("Tunnel: exiting (stopped=" + stopped + ")");
+                connectionCFs.forEach(cf -> cf.complete(null));
             }
         }
 
-        void stop() throws IOException {
+        public void stop() throws IOException {
+            stopped = true;
             ss.close();
         }
 
--- a/test/jdk/java/net/httpclient/SplitResponse.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/SplitResponse.java	Tue Feb 06 11:04:44 2018 +0000
@@ -34,6 +34,7 @@
 import jdk.testlibrary.SimpleSSLContext;
 import static java.lang.System.out;
 import static java.lang.String.format;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static jdk.incubator.http.HttpResponse.BodyHandler.asString;
 
 /**
@@ -60,7 +61,9 @@
         if (!serverKeepalive)
             sb.append("Connection: Close\r\n");
 
-        sb.append("Content-length: ").append(body.length()).append("\r\n");
+        sb.append("Content-length: ")
+                .append(body.getBytes(ISO_8859_1).length)
+                .append("\r\n");
         sb.append("\r\n");
         sb.append(body);
         return sb.toString();
--- a/test/jdk/java/net/httpclient/http2/ProxyTest2.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/http2/ProxyTest2.java	Tue Feb 06 11:04:44 2018 +0000
@@ -165,19 +165,24 @@
         final ServerSocket ss;
         final boolean DEBUG = false;
         final Http2TestServer serverImpl;
+        final CopyOnWriteArrayList<CompletableFuture<Void>> connectionCFs
+                = new CopyOnWriteArrayList<>();
+        private volatile boolean stopped;
         TunnelingProxy(Http2TestServer serverImpl) throws IOException {
             this.serverImpl = serverImpl;
             ss = new ServerSocket();
             accept = new Thread(this::accept);
+            accept.setDaemon(true);
         }
 
         void start() throws IOException {
-            ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+            ss.bind(new InetSocketAddress(0));
             accept.start();
         }
 
         // Pipe the input stream to the output stream.
-        private synchronized Thread pipe(InputStream is, OutputStream os, char tag) {
+        private synchronized Thread pipe(InputStream is, OutputStream os,
+                                         char tag, CompletableFuture<Void> end) {
             return new Thread("TunnelPipe("+tag+")") {
                 @Override
                 public void run() {
@@ -197,13 +202,17 @@
                         }
                     } catch (IOException ex) {
                         if (DEBUG) ex.printStackTrace(System.out);
+                    } finally {
+                        end.complete(null);
                     }
                 }
             };
         }
 
         public InetSocketAddress getAddress() {
-            return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
+            return new InetSocketAddress(
+                    "localhost",
+                    ss.getLocalPort());
         }
 
         // This is a bit shaky. It doesn't handle continuation
@@ -228,18 +237,14 @@
         public void accept() {
             Socket clientConnection = null;
             try {
-                while (true) {
+                while (!stopped) {
                     System.out.println("Tunnel: Waiting for client");
-                    Socket previous = clientConnection;
+                    Socket toClose;
                     try {
-                        clientConnection = ss.accept();
+                        toClose = clientConnection = ss.accept();
                     } catch (IOException io) {
                         if (DEBUG) io.printStackTrace(System.out);
                         break;
-                    } finally {
-                        // we have only 1 client at a time, so it is safe
-                        // to close the previous connection here
-                        if (previous != null) previous.close();
                     }
                     System.out.println("Tunnel: Client accepted");
                     Socket targetConnection = null;
@@ -259,40 +264,59 @@
                         // signals the end of all headers.
                         while(!requestLine.equals("")) {
                             System.out.println("Tunnel: Reading header: "
-                                               + (requestLine = readLine(ccis)));
+                                    + (requestLine = readLine(ccis)));
                         }
 
                         // Open target connection
                         targetConnection = new Socket(
-                                serverImpl.getAddress().getAddress(),
+                                InetAddress.getLoopbackAddress(),
                                 serverImpl.getAddress().getPort());
 
                         // Then send the 200 OK response to the client
                         System.out.println("Tunnel: Sending "
-                                           + "HTTP/1.1 200 OK\r\n\r\n");
+                                + "HTTP/1.1 200 OK\r\n\r\n");
                         pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
                         pw.flush();
                     } else {
-                        // This should not happen.
-                        throw new IOException("Tunnel: Unexpected status line: "
-                                           + requestLine);
+                        // This should not happen. If it does then just print an
+                        // error - both on out and err, and close the accepted
+                        // socket
+                        System.out.println("WARNING: Tunnel: Unexpected status line: "
+                                + requestLine + " received by "
+                                + ss.getLocalSocketAddress()
+                                + " from "
+                                + toClose.getRemoteSocketAddress()
+                                + " - closing accepted socket");
+                        // Print on err
+                        System.err.println("WARNING: Tunnel: Unexpected status line: "
+                                + requestLine + " received by "
+                                + ss.getLocalSocketAddress()
+                                + " from "
+                                + toClose.getRemoteSocketAddress());
+                        // close accepted socket.
+                        toClose.close();
+                        System.err.println("Tunnel: accepted socket closed.");
+                        continue;
                     }
 
                     // Pipe the input stream of the client connection to the
                     // output stream of the target connection and conversely.
                     // Now the client and target will just talk to each other.
                     System.out.println("Tunnel: Starting tunnel pipes");
-                    Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
-                    Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
+                    CompletableFuture<Void> end, end1, end2;
+                    Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+',
+                            end1 = new CompletableFuture<>());
+                    Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-',
+                            end2 = new CompletableFuture<>());
+                    end = CompletableFuture.allOf(end1, end2);
+                    end.whenComplete(
+                            (r,t) -> {
+                                try { toClose.close(); } catch (IOException x) { }
+                                finally {connectionCFs.remove(end);}
+                            });
+                    connectionCFs.add(end);
                     t1.start();
                     t2.start();
-
-                    // We have only 1 client... wait until it has finished before
-                    // accepting a new connection request.
-                    // System.out.println("Tunnel: Waiting for pipes to close");
-                    t1.join();
-                    t2.join();
-                    System.out.println("Tunnel: Done - waiting for next client");
                 }
             } catch (Throwable ex) {
                 try {
@@ -301,10 +325,14 @@
                     ex.addSuppressed(ex1);
                 }
                 ex.printStackTrace(System.err);
+            } finally {
+                System.out.println("Tunnel: exiting (stopped=" + stopped + ")");
+                connectionCFs.forEach(cf -> cf.complete(null));
             }
         }
 
-        void stop() throws IOException {
+        public void stop() throws IOException {
+            stopped = true;
             ss.close();
         }
 
--- a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java	Tue Feb 06 10:34:47 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java	Tue Feb 06 11:04:44 2018 +0000
@@ -145,7 +145,7 @@
         ssc = ServerSocketChannel.open();
         try {
             ssc.configureBlocking(true);
-            ssc.bind(new InetSocketAddress("localhost", 0));
+            ssc.bind(new InetSocketAddress(0));
             address = (InetSocketAddress) ssc.getLocalAddress();
             thread.start();
         } catch (IOException e) {
@@ -165,7 +165,7 @@
         if (!started.get()) {
             throw new IllegalStateException("Not yet started");
         }
-        return URI.create("ws://" + address.getHostName() + ":" + address.getPort());
+        return URI.create("ws://localhost:" + address.getPort());
     }
 
     private boolean readRequest(SocketChannel channel, StringBuilder request)