--- 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();