http-client-branch: add an immutable request implementation http-client-branch
authorchegar
Fri, 15 Jun 2018 15:16:52 +0100
branchhttp-client-branch
changeset 56766 713f08212a7e
parent 56763 25821dd1d917
child 56767 014ef88f5066
http-client-branch: add an immutable request implementation
src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java
src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java
src/java.net.http/share/classes/jdk/internal/net/http/ImmutableHttpRequest.java
src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java
test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java
test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java	Fri Jun 15 12:43:10 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java	Fri Jun 15 15:16:52 2018 +0100
@@ -216,6 +216,13 @@
         if (uri == null)
             throw new IllegalStateException("uri is null");
         assert method != null;
+        return new ImmutableHttpRequest(this);
+    }
+
+    public HttpRequestImpl buildForWebSocket() {
+        if (uri == null)
+            throw new IllegalStateException("uri is null");
+        assert method != null;
         return new HttpRequestImpl(this);
     }
 
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java	Fri Jun 15 12:43:10 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java	Fri Jun 15 15:16:52 2018 +0100
@@ -47,7 +47,7 @@
 
 import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS;
 
-class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
+public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
 
     private final HttpHeaders userHeaders;
     private final HttpHeadersBuilder systemHeadersBuilder;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/ImmutableHttpRequest.java	Fri Jun 15 15:16:52 2018 +0100
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.net.http;
+
+import java.net.URI;
+import java.net.http.HttpHeaders;
+import java.net.http.HttpRequest;
+import java.time.Duration;
+import java.util.Objects;
+import java.util.Optional;
+import java.net.http.HttpClient.Version;
+import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS;
+
+final class ImmutableHttpRequest extends HttpRequest {
+
+    private final String method;
+    private final URI uri;
+    private final HttpHeaders headers;
+    private final Optional<BodyPublisher> requestPublisher;
+    private final boolean expectContinue;
+    private final Optional<Duration> timeout;
+    private final Optional<Version> version;
+
+    /** Creates an ImmutableHttpRequest from the given builder. */
+    ImmutableHttpRequest(HttpRequestBuilderImpl builder) {
+        this.method = Objects.requireNonNull(builder.method());
+        this.uri = Objects.requireNonNull(builder.uri());
+        this.headers = HttpHeaders.of(builder.headersBuilder().map(), ALLOWED_HEADERS);
+        this.requestPublisher = Optional.ofNullable(builder.bodyPublisher());
+        this.expectContinue = builder.expectContinue();
+        this.timeout = Optional.ofNullable(builder.timeout());
+        this.version = Objects.requireNonNull(builder.version());
+    }
+
+    @Override
+    public String method() { return method; }
+
+    @Override
+    public URI uri() { return uri; }
+
+    @Override
+    public HttpHeaders headers() {
+        return headers;
+    }
+
+    @Override
+    public Optional<BodyPublisher> bodyPublisher() { return requestPublisher; }
+
+    @Override
+    public boolean expectContinue() { return expectContinue; }
+
+    @Override
+    public Optional<Duration> timeout() { return timeout; }
+
+    @Override
+    public Optional<Version> version() { return version; }
+
+    @Override
+    public String toString() {
+        return uri.toString() + " " + method;
+    }
+}
--- a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java	Fri Jun 15 12:43:10 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java	Fri Jun 15 15:16:52 2018 +0100
@@ -32,6 +32,9 @@
 import java.net.http.HttpResponse;
 import java.net.http.HttpResponse.BodyHandlers;
 import java.net.http.WebSocketHandshakeException;
+
+import jdk.internal.net.http.HttpRequestBuilderImpl;
+import jdk.internal.net.http.HttpRequestImpl;
 import jdk.internal.net.http.common.MinimalFuture;
 import jdk.internal.net.http.common.Pair;
 import jdk.internal.net.http.common.Utils;
@@ -104,7 +107,7 @@
         }
     }
 
-    private final HttpRequest request;
+    private final HttpRequestImpl request;
     private final Collection<String> subprotocols;
     private final String nonce;
 
@@ -114,7 +117,7 @@
         checkPermissions(b, proxy);
         this.client = b.getClient();
         URI httpURI = createRequestURI(b.getUri());
-        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(httpURI);
+        HttpRequestBuilderImpl requestBuilder = new HttpRequestBuilderImpl(httpURI);
         Duration connectTimeout = b.getConnectTimeout();
         if (connectTimeout != null) {
             requestBuilder.timeout(connectTimeout);
@@ -137,12 +140,12 @@
         // to upgrade from HTTP/2 to WebSocket (as of August 2016):
         //
         //     https://tools.ietf.org/html/draft-hirano-httpbis-websocket-over-http2-00
-        this.request = requestBuilder.version(Version.HTTP_1_1).GET().build();
-        WebSocketRequest r = (WebSocketRequest) this.request;
-        r.isWebSocket(true);
-        r.setSystemHeader(HEADER_UPGRADE, "websocket");
-        r.setSystemHeader(HEADER_CONNECTION, "Upgrade");
-        r.setProxy(proxy);
+        requestBuilder.version(Version.HTTP_1_1).GET();
+        request = requestBuilder.buildForWebSocket();
+        request.isWebSocket(true);
+        request.setSystemHeader(HEADER_UPGRADE, "websocket");
+        request.setSystemHeader(HEADER_CONNECTION, "Upgrade");
+        request.setProxy(proxy);
     }
 
     private static Collection<String> createRequestSubprotocols(
--- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java	Fri Jun 15 12:43:10 2018 +0100
+++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java	Fri Jun 15 15:16:52 2018 +0100
@@ -47,6 +47,7 @@
 import jdk.internal.net.http.websocket.WebSocketRequest;
 import org.testng.annotations.Test;
 import static java.net.http.HttpResponse.BodyHandlers.discarding;
+import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.testng.Assert.assertEquals;
 
 /*
@@ -104,6 +105,7 @@
             // tell the server we have read the initial bytes, so
             // that it makes sure there is something for us to
             // read next in case the initialBytes have already drained the
+
             // channel dry.
             initialReadStall.countDown();
 
@@ -210,11 +212,19 @@
         HttpRequest req = HttpRequest.newBuilder(uri).build();
         // Switch on isWebSocket flag to prevent the connection from
         // being returned to the pool.
-        ((WebSocketRequest)req).isWebSocket(true);
         HttpClient client = HttpClient.newHttpClient();
+        HttpClientImpl clientImpl = ((HttpClientFacade)client).impl;
+        HttpRequestImpl requestImpl = new HttpRequestImpl(req, null);
+        requestImpl.isWebSocket(true);
         try {
-            HttpResponse<?> r = client.send(req, discarding());
-            r.body();
+            MultiExchange<Void> mex = new MultiExchange<>(req,
+                    requestImpl,
+                    clientImpl,
+                    discarding(),
+                    null,
+                    null);
+            HttpResponse<?> r = mex.responseAsync(clientImpl.theExecutor())
+                                   .get(30, SECONDS);
             return ((HttpResponseImpl) r).rawChannel();
         } finally {
            // Need to hold onto the client until the RawChannel is
--- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java	Fri Jun 15 12:43:10 2018 +0100
+++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java	Fri Jun 15 15:16:52 2018 +0100
@@ -30,7 +30,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import org.testng.annotations.Test;
 import jdk.internal.net.http.websocket.RawChannel;
@@ -150,11 +149,11 @@
     static RawChannel getARawChannel(int port) throws Exception {
         URI uri = URI.create("http://localhost:" + port + "/");
         out.println("client connecting to " + uri.toString());
-        HttpRequest req = HttpRequest.newBuilder(uri).build();
+        HttpRequestImpl req = new HttpRequestBuilderImpl(uri).buildForWebSocket();
         // Otherwise HttpClient will think this is an ordinary connection and
         // thus all ordinary procedures apply to it, e.g. it must be put into
         // the cache
-        ((HttpRequestImpl) req).isWebSocket(true);
+        req.isWebSocket(true);
         HttpResponse<?> r = defaultClient().send(req, discarding());
         r.body();
         return ((HttpResponseImpl) r).rawChannel();