Skip to content

Commit 8a40d25

Browse files
Larry-NRealCLanger
authored andcommitted
8268617: [11u REDO] - WebSocket over authenticating proxy fails with NPE
Reviewed-by: clanger
1 parent b74d798 commit 8a40d25

File tree

12 files changed

+931
-38
lines changed

12 files changed

+931
-38
lines changed

src/java.net.http/share/classes/jdk/internal/net/http/AuthenticationFilter.java

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -240,20 +240,23 @@ public HttpRequestImpl response(Response r) throws IOException {
240240
HttpHeaders hdrs = r.headers();
241241
HttpRequestImpl req = r.request();
242242

243-
if (status != UNAUTHORIZED && status != PROXY_UNAUTHORIZED) {
244-
// check if any authentication succeeded for first time
245-
if (exchange.serverauth != null && !exchange.serverauth.fromcache) {
246-
AuthInfo au = exchange.serverauth;
247-
cache.store(au.scheme, req.uri(), false, au.credentials);
248-
}
243+
if (status != PROXY_UNAUTHORIZED) {
249244
if (exchange.proxyauth != null && !exchange.proxyauth.fromcache) {
250245
AuthInfo au = exchange.proxyauth;
251246
URI proxyURI = getProxyURI(req);
252247
if (proxyURI != null) {
248+
exchange.proxyauth = null;
253249
cache.store(au.scheme, proxyURI, true, au.credentials);
254250
}
255251
}
252+
if (status != UNAUTHORIZED) {
253+
// check if any authentication succeeded for first time
254+
if (exchange.serverauth != null && !exchange.serverauth.fromcache) {
255+
AuthInfo au = exchange.serverauth;
256+
cache.store(au.scheme, req.uri(), false, au.credentials);
257+
}
256258
return null;
259+
}
257260
}
258261

259262
boolean proxy = status == PROXY_UNAUTHORIZED;

src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -142,6 +142,7 @@ synchronized HttpConnection getConnection(boolean secure,
142142
HttpConnection c = secure ? findConnection(key, sslPool)
143143
: findConnection(key, plainPool);
144144
//System.out.println ("getConnection returning: " + c);
145+
assert c == null || c.isSecure() == secure;
145146
return c;
146147
}
147148

@@ -155,6 +156,10 @@ void returnToPool(HttpConnection conn) {
155156
// Called also by whitebox tests
156157
void returnToPool(HttpConnection conn, Instant now, long keepAlive) {
157158

159+
assert (conn instanceof PlainHttpConnection) || conn.isSecure()
160+
: "Attempting to return unsecure connection to SSL pool: "
161+
+ conn.getClass();
162+
158163
// Don't call registerCleanupTrigger while holding a lock,
159164
// but register it before the connection is added to the pool,
160165
// since we don't want to trigger the cleanup if the connection
@@ -450,7 +455,7 @@ private void removeFromPool(HttpConnection c) {
450455
if (c instanceof PlainHttpConnection) {
451456
removeFromPool(c, plainPool);
452457
} else {
453-
assert c.isSecure();
458+
assert c.isSecure() : "connection " + c + " is not secure!";
454459
removeFromPool(c, sslPool);
455460
}
456461
}

src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -263,7 +263,7 @@ public CompletableFuture<Void> ignoreBody(Executor executor) {
263263
connection.close();
264264
return MinimalFuture.completedFuture(null); // not treating as error
265265
} else {
266-
return readBody(discarding(), true, executor);
266+
return readBody(discarding(), !request.isWebSocket(), executor);
267267
}
268268
}
269269

@@ -387,6 +387,14 @@ public void onComplete() {
387387
public <U> CompletableFuture<U> readBody(HttpResponse.BodySubscriber<U> p,
388388
boolean return2Cache,
389389
Executor executor) {
390+
if (debug.on()) {
391+
debug.log("readBody: return2Cache: " + return2Cache);
392+
if (request.isWebSocket() && return2Cache && connection != null) {
393+
debug.log("websocket connection will be returned to cache: "
394+
+ connection.getClass() + "/" + connection );
395+
}
396+
}
397+
assert !return2Cache || !request.isWebSocket();
390398
this.return2Cache = return2Cache;
391399
final Http1BodySubscriber<U> subscriber = new Http1BodySubscriber<>(p);
392400

src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -160,6 +160,26 @@ public synchronized RawChannel rawChannel() throws IOException {
160160
return rawchan;
161161
}
162162

163+
/**
164+
* Closes the RawChannel that may have been used for WebSocket protocol.
165+
*
166+
* @apiNote This method should be called to close the connection
167+
* if an exception occurs during the websocket handshake, in cases where
168+
* {@link #rawChannel() rawChannel().close()} would have been called.
169+
* An unsuccessful handshake may prevent the creation of the RawChannel:
170+
* if a RawChannel has already been created, this method wil close it.
171+
* Otherwise, it will close the connection.
172+
*
173+
* @throws IOException if an I/O exception occurs while closing
174+
* the channel.
175+
*/
176+
public synchronized void closeRawChannel() throws IOException {
177+
// close the rawChannel, if created, or the
178+
// connection, if not.
179+
if (rawchan != null) rawchan.close();
180+
else connection.close();
181+
}
182+
163183
@Override
164184
public String toString() {
165185
StringBuilder sb = new StringBuilder();

src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -363,6 +363,10 @@ private CompletableFuture<Response> responseAsyncImpl() {
363363
this.response =
364364
new HttpResponseImpl<>(currentreq, response, this.response, null, exch);
365365
Exchange<T> oldExch = exch;
366+
if (currentreq.isWebSocket()) {
367+
// need to close the connection and open a new one.
368+
exch.exchImpl.connection().close();
369+
}
366370
return exch.ignoreBody().handle((r,t) -> {
367371
previousreq = currentreq;
368372
currentreq = newrequest;

src/java.net.http/share/classes/jdk/internal/net/http/RawChannelTube.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -73,7 +73,7 @@ public class RawChannelTube implements RawChannel {
7373
this.initial = initial;
7474
this.writePublisher = new WritePublisher();
7575
this.readSubscriber = new ReadSubscriber();
76-
dbgTag = "[WebSocket] RawChannelTube(" + tube.toString() +")";
76+
dbgTag = "[WebSocket] RawChannelTube(" + tube +")";
7777
debug = Utils.getWebSocketLogger(dbgTag::toString, Utils.DEBUG_WS);
7878
connection.client().webSocketOpen();
7979
connectFlows();

src/java.net.http/share/classes/jdk/internal/net/http/common/Log.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@
4141
import javax.net.ssl.SSLParameters;
4242

4343
/**
44-
* -Djava.net.HttpClient.log=
44+
* -Djdk.httpclient.HttpClient.log=
4545
* errors,requests,headers,
4646
* frames[:control:data:window:all..],content,ssl,trace,channel
4747
*

src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -215,19 +215,26 @@ private CompletableFuture<Result> resultFrom(HttpResponse<?> response) {
215215
//
216216
// See https://tools.ietf.org/html/rfc6455#section-7.4.1
217217
Result result = null;
218-
Exception exception = null;
218+
Throwable exception = null;
219219
try {
220220
result = handleResponse(response);
221221
} catch (IOException e) {
222222
exception = e;
223223
} catch (Exception e) {
224224
exception = new WebSocketHandshakeException(response).initCause(e);
225+
} catch (Error e) {
226+
// We should attempt to close the connection and relay
227+
// the error through the completable future even in this
228+
// case.
229+
exception = e;
225230
}
226231
if (exception == null) {
227232
return MinimalFuture.completedFuture(result);
228233
}
229234
try {
230-
((RawChannel.Provider) response).rawChannel().close();
235+
// calling this method will close the rawChannel, if created,
236+
// or the connection, if not.
237+
((RawChannel.Provider) response).closeRawChannel();
231238
} catch (IOException e) {
232239
exception.addSuppressed(e);
233240
}

src/java.net.http/share/classes/jdk/internal/net/http/websocket/RawChannel.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@ public interface RawChannel extends Closeable {
4040
interface Provider {
4141

4242
RawChannel rawChannel() throws IOException;
43+
void closeRawChannel() throws IOException;
4344
}
4445

4546
interface RawEvent {

0 commit comments

Comments
 (0)