Skip to content

Commit 931913f

Browse files
committed
8309200: java/net/httpclient/ExecutorShutdown fails intermittently, if connection closed during upgrade
Reviewed-by: jpai, djelinski
1 parent dc21e8a commit 931913f

File tree

7 files changed

+60
-18
lines changed

7 files changed

+60
-18
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2023, 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
@@ -111,6 +111,11 @@ public void close() {
111111
plainConnection.close();
112112
}
113113

114+
@Override
115+
void close(Throwable cause) {
116+
plainConnection.close(cause);
117+
}
118+
114119
@Override
115120
SSLTube getConnectionFlow() {
116121
return flow;

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2023, 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
@@ -113,6 +113,11 @@ public void close() {
113113
plainConnection.close();
114114
}
115115

116+
@Override
117+
void close(Throwable cause) {
118+
plainConnection.close(cause);
119+
}
120+
116121
@Override
117122
SocketChannel channel() {
118123
return plainConnection.channel();

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ HttpClientImpl client() {
142142
static final class ConnectionAborter {
143143
private volatile HttpConnection connection;
144144
private volatile boolean closeRequested;
145+
private volatile Throwable cause;
145146

146147
void connection(HttpConnection connection) {
147148
boolean closeRequested;
@@ -156,20 +157,27 @@ void connection(HttpConnection connection) {
156157
this.closeRequested = false;
157158
}
158159
}
159-
if (closeRequested) closeConnection(connection);
160+
if (closeRequested) closeConnection(connection, cause);
160161
}
161162

162-
void closeConnection() {
163+
void closeConnection(Throwable error) {
163164
HttpConnection connection;
165+
Throwable cause;
164166
synchronized (this) {
167+
cause = this.cause;
168+
if (cause == null) {
169+
cause = error;
170+
}
165171
connection = this.connection;
166172
if (connection == null) {
167173
closeRequested = true;
174+
this.cause = cause;
168175
} else {
169176
this.connection = null;
177+
this.cause = null;
170178
}
171179
}
172-
closeConnection(connection);
180+
closeConnection(connection, cause);
173181
}
174182

175183
HttpConnection disable() {
@@ -178,14 +186,15 @@ HttpConnection disable() {
178186
connection = this.connection;
179187
this.connection = null;
180188
this.closeRequested = false;
189+
this.cause = null;
181190
}
182191
return connection;
183192
}
184193

185-
private static void closeConnection(HttpConnection connection) {
194+
private static void closeConnection(HttpConnection connection, Throwable cause) {
186195
if (connection != null) {
187196
try {
188-
connection.close();
197+
connection.close(cause);
189198
} catch (Throwable t) {
190199
// ignore
191200
}
@@ -264,11 +273,19 @@ public void cancel(IOException cause) {
264273
impl.cancel(cause);
265274
} else {
266275
// no impl yet. record the exception
267-
failed = cause;
276+
IOException failed = this.failed;
277+
if (failed == null) {
278+
synchronized (this) {
279+
failed = this.failed;
280+
if (failed == null) {
281+
failed = this.failed = cause;
282+
}
283+
}
284+
}
268285

269286
// abort/close the connection if setting up the exchange. This can
270287
// be important when setting up HTTP/2
271-
connectionAborter.closeConnection();
288+
connectionAborter.closeConnection(failed);
272289

273290
// now call checkCancelled to recheck the impl.
274291
// if the failed state is set and the impl is not null, reset

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2023, 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
@@ -427,11 +427,19 @@ final InetSocketAddress address() {
427427
abstract ConnectionPool.CacheKey cacheKey();
428428

429429
/**
430-
* Closes this connection, by returning the socket to its connection pool.
430+
* Closes this connection.
431431
*/
432432
@Override
433433
public abstract void close();
434434

435+
/**
436+
* Closes this connection due to the given cause.
437+
* @param cause the cause for which the connection is closed, may be null
438+
*/
439+
void close(Throwable cause) {
440+
close();
441+
}
442+
435443
abstract FlowTube getConnectionFlow();
436444

437445
/**

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,13 @@ public String toString() {
401401
return "PlainHttpConnection: " + super.toString();
402402
}
403403

404-
/**
405-
* Closes this connection
406-
*/
407404
@Override
408405
public void close() {
406+
close(null);
407+
}
408+
409+
@Override
410+
void close(Throwable cause) {
409411
var closed = this.closed;
410412
if (closed) return;
411413
stateLock.lock();
@@ -423,7 +425,7 @@ public void close() {
423425
}
424426
try {
425427
chan.close();
426-
tube.signalClosed();
428+
tube.signalClosed(cause);
427429
} finally {
428430
client().connectionClosed(this);
429431
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,12 @@ ConnectionPool.CacheKey cacheKey() {
157157

158158
@Override
159159
public void close() {
160-
delegate.close();
160+
close(null);
161+
}
162+
163+
@Override
164+
void close(Throwable cause) {
165+
delegate.close(cause);
161166
connected = false;
162167
}
163168

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,15 @@ public void onComplete() {
149149
// Events //
150150
// ======================================================================//
151151

152-
void signalClosed() {
152+
void signalClosed(Throwable cause) {
153153
// Ensures that the subscriber will be terminated and that future
154154
// subscribers will be notified when the connection is closed.
155155
if (Log.channel()) {
156156
Log.logChannel("Connection close signalled: connection closed locally ({0})",
157157
channelDescr());
158158
}
159159
readPublisher.subscriptionImpl.signalError(
160-
new IOException("connection closed locally"));
160+
new IOException("connection closed locally", cause));
161161
}
162162

163163
/**

0 commit comments

Comments
 (0)