--- old/src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java 2018-08-07 15:13:57.000000000 +0100 +++ new/src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java 2018-08-07 15:13:56.000000000 +0100 @@ -26,11 +26,13 @@ package jdk.internal.net.http; import java.io.IOException; -import java.lang.System.Logger.Level; import java.net.InetSocketAddress; +import java.net.http.HttpTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.time.Duration; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.function.Function; import java.net.http.HttpHeaders; import jdk.internal.net.http.common.FlowTube; @@ -60,9 +62,10 @@ } @Override - public CompletableFuture connectAsync() { + public CompletableFuture connectAsync(Exchange exchange) { if (debug.on()) debug.log("Connecting plain connection"); - return delegate.connectAsync() + return delegate.connectAsync(exchange) + .thenCompose(unused -> delegate.finishConnect()) .thenCompose((Void v) -> { if (debug.on()) debug.log("sending HTTP/1.1 CONNECT"); HttpClientImpl client = client(); @@ -70,7 +73,7 @@ HttpRequestImpl req = new HttpRequestImpl("CONNECT", address, proxyHeaders); MultiExchange mulEx = new MultiExchange<>(null, req, client, discarding(), null, null); - Exchange connectExchange = new Exchange<>(req, mulEx); + Exchange connectExchange = mulEx.getExchange(); return connectExchange .responseAsyncImpl(delegate) @@ -96,14 +99,36 @@ ByteBuffer b = ((Http1Exchange)connectExchange.exchImpl).drainLeftOverBytes(); int remaining = b.remaining(); assert remaining == 0: "Unexpected remaining: " + remaining; - connected = true; cf.complete(null); } return cf; - }); + }) + .handle((result, ex) -> { + if (ex == null) { + return MinimalFuture.completedFuture(result); + } else { + if (debug.on()) + debug.log("tunnel failed with \"%s\"", ex.toString()); + Throwable t = ex; + if (t instanceof CompletionException) + t = t.getCause(); + if (t instanceof HttpTimeoutException) { + String msg = "proxy tunneling CONNECT request timed out"; + t = new HttpTimeoutException(msg); + t.initCause(ex); + } + return MinimalFuture.failedFuture(t); + } + }) + .thenCompose(Function.identity()); }); } + public CompletableFuture finishConnect() { + connected = true; + return MinimalFuture.completedFuture(null); + } + @Override boolean isTunnel() { return true; }