diff --git a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java index 1d18386a3a4..ca899ad82c7 100644 --- a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java +++ b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java @@ -78,6 +78,12 @@ public abstract class HttpChannel implements CyclicTimeouts.Expirable return result; } + /** + *
Disassociates the exchange from this channel.
+ * + * @param exchange the current exchange that must be already completed + * @return true if the exchange was disassociated, false otherwise + */ public boolean disassociate(HttpExchange exchange) { boolean result = false; @@ -97,6 +103,14 @@ public abstract class HttpChannel implements CyclicTimeouts.Expirable return result; } + /** + *Returns the {@code HttpExchange} currently associated + * with this channel, possibly {@code null}.
+ *The exchange may be completed and disassociated concurrently, + * so callers must act atomically on the exchange.
+ * + * @return the {@code HttpExchange} currently associated with this channel, possibly {@code null}. + */ public HttpExchange getHttpExchange() { try (AutoLock l = _lock.lock()) diff --git a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java index ad76d51c9f6..1782867a648 100644 --- a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java +++ b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java @@ -386,23 +386,19 @@ public abstract class HttpReceiver LOG.debug("Failing with {} on {}", failure, this); HttpExchange exchange = getHttpExchange(); - // In case of a response error, the failure has already been notified - // and it is possible that a further attempt to read in the receive - // loop throws an exception that reenters here but without exchange; - // or, the server could just have timed out the connection. - if (exchange == null) - { - promise.succeeded(false); - return; - } // Mark atomically the response as completed, with respect // to concurrency between response success and response failure. - boolean completed = exchange.responseComplete(failure); - if (completed) + if (exchange != null && exchange.responseComplete(failure)) + { abort(exchange, failure, promise); + } else + { + // The response was already completed (either successfully + // or with a failure) by a previous event, bail out. promise.succeeded(false); + } } private void terminateResponse(HttpExchange exchange)