@@ -279,23 +279,25 @@ public String toString() {
279
279
}
280
280
}
281
281
282
- static void registerPending (PendingRequest pending ) {
282
+ static < T > CompletableFuture < T > registerPending (PendingRequest pending , CompletableFuture < T > res ) {
283
283
// shortcut if cf is already completed: no need to go through the trouble of
284
284
// registering it
285
- if (pending .cf .isDone ()) return ;
285
+ if (pending .cf .isDone ()) return res ;
286
286
287
287
var client = pending .client ;
288
288
var cf = pending .cf ;
289
289
var id = pending .id ;
290
290
boolean added = client .pendingRequests .add (pending );
291
291
// this may immediately remove `pending` from the set is the cf is already completed
292
- pending .ref = cf .whenComplete ((r ,t ) -> client .pendingRequests .remove (pending ));
292
+ var ref = res .whenComplete ((r ,t ) -> client .pendingRequests .remove (pending ));
293
+ pending .ref = ref ;
293
294
assert added : "request %d was already added" .formatted (id );
294
295
// should not happen, unless the selector manager has already
295
296
// exited abnormally
296
297
if (client .selmgr .isClosed ()) {
297
298
pending .abort (client .selmgr .selectorClosedException ());
298
299
}
300
+ return ref ;
299
301
}
300
302
301
303
static void abortPendingRequests (HttpClientImpl client , Throwable reason ) {
@@ -875,8 +877,9 @@ private void debugCompleted(String tag, long startNanos, HttpRequest req) {
875
877
cf = sendAsync (req , responseHandler , null , null );
876
878
return cf .get ();
877
879
} catch (InterruptedException ie ) {
878
- if (cf != null )
880
+ if (cf != null ) {
879
881
cf .cancel (true );
882
+ }
880
883
throw ie ;
881
884
} catch (ExecutionException e ) {
882
885
final Throwable throwable = e .getCause ();
@@ -991,19 +994,23 @@ private void debugCompleted(String tag, long startNanos, HttpRequest req) {
991
994
(b ,t ) -> debugCompleted ("ClientImpl (async)" , start , userRequest ));
992
995
}
993
996
994
- // makes sure that any dependent actions happen in the CF default
995
- // executor. This is only needed for sendAsync(...), when
996
- // exchangeExecutor is non-null.
997
- if (exchangeExecutor != null ) {
998
- res = res .whenCompleteAsync ((r , t ) -> { /* do nothing */ }, ASYNC_POOL );
999
- }
1000
-
1001
997
// The mexCf is the Cf we need to abort if the SelectorManager thread
1002
998
// is aborted.
1003
999
PendingRequest pending = new PendingRequest (id , requestImpl , mexCf , mex , this );
1004
- registerPending (pending );
1005
- return res ;
1006
- } catch (Throwable t ) {
1000
+ res = registerPending (pending , res );
1001
+
1002
+ if (exchangeExecutor != null ) {
1003
+ // makes sure that any dependent actions happen in the CF default
1004
+ // executor. This is only needed for sendAsync(...), when
1005
+ // exchangeExecutor is non-null.
1006
+ return res .isDone () ? res
1007
+ : res .whenCompleteAsync ((r , t ) -> { /* do nothing */ }, ASYNC_POOL );
1008
+ } else {
1009
+ // make a defensive copy that can be safely canceled
1010
+ // by the caller
1011
+ return res .isDone () ? res : res .copy ();
1012
+ }
1013
+ } catch (Throwable t ) {
1007
1014
requestUnreference ();
1008
1015
debugCompleted ("ClientImpl (async)" , start , userRequest );
1009
1016
throw t ;
0 commit comments