From 177fc804e5726b1ee156b488b6f40008f437f020 Mon Sep 17 00:00:00 2001 From: Oleg Kalnichevski Date: Sat, 18 Apr 2020 12:08:10 +0200 Subject: [PATCH] HTTPASYNC-160: HttpAsyncClient in INACTIVE or STOPPED state throws a IllegalStateException causing the current thread to terminate --- .../impl/async/AbstractHttpAsyncClientBase.java | 9 ++------- .../async/InternalAbstractHttpAsyncClient.java | 7 +++++-- .../http/impl/async/MinimalH2AsyncClient.java | 9 ++++++--- .../http/impl/async/MinimalHttpAsyncClient.java | 16 +++++++++++----- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java index eb92d14d1..3ab09472e 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java @@ -81,13 +81,8 @@ abstract class AbstractHttpAsyncClientBase extends CloseableHttpAsyncClient { pushConsumerRegistry.register(hostname, uriPattern, supplier); } - void ensureRunning() { - switch (status.get()) { - case READY: - throw new IllegalStateException("Client is not running"); - case TERMINATED: - throw new IllegalStateException("Client has been terminated"); - } + boolean isRunning() { + return status.get() == Status.RUNNING; } ConnectionInitiator getConnectionInitiator() { diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalAbstractHttpAsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalAbstractHttpAsyncClient.java index e16a1a47f..c0105239c 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalAbstractHttpAsyncClient.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalAbstractHttpAsyncClient.java @@ -30,6 +30,7 @@ import java.io.Closeable; import java.io.IOException; import java.util.List; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; @@ -150,9 +151,11 @@ abstract class InternalAbstractHttpAsyncClient extends AbstractHttpAsyncClientBa final HandlerFactory pushHandlerFactory, final HttpContext context, final FutureCallback callback) { - ensureRunning(); final ComplexFuture future = new ComplexFuture<>(callback); try { + if (!isRunning()) { + throw new CancellationException("Request execution cancelled"); + } final HttpClientContext clientContext = context != null ? HttpClientContext.adapt(context) : HttpClientContext.create(); requestProducer.sendRequest(new RequestChannel() { @@ -316,7 +319,7 @@ abstract class InternalAbstractHttpAsyncClient extends AbstractHttpAsyncClientBa } }, context); - } catch (final HttpException | IOException ex) { + } catch (final HttpException | IOException | IllegalStateException ex) { future.failed(ex); } return future; diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java index dc23b6247..411fb8545 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalH2AsyncClient.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.List; +import java.util.concurrent.CancellationException; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; @@ -134,10 +135,12 @@ public final class MinimalH2AsyncClient extends AbstractMinimalHttpAsyncClientBa final AsyncClientExchangeHandler exchangeHandler, final HandlerFactory pushHandlerFactory, final HttpContext context) { - ensureRunning(); final ComplexCancellable cancellable = new ComplexCancellable(); - final HttpClientContext clientContext = context != null ? HttpClientContext.adapt(context) : HttpClientContext.create(); try { + if (!isRunning()) { + throw new CancellationException("Request execution cancelled"); + } + final HttpClientContext clientContext = context != null ? HttpClientContext.adapt(context) : HttpClientContext.create(); exchangeHandler.produceRequest(new RequestChannel() { @Override @@ -270,7 +273,7 @@ public final class MinimalH2AsyncClient extends AbstractMinimalHttpAsyncClientBa } }, context); - } catch (final HttpException | IOException ex) { + } catch (final HttpException | IOException | IllegalStateException ex) { exchangeHandler.failed(ex); } return cancellable; diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java index d4e95d2b3..b3a340d50 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/MinimalHttpAsyncClient.java @@ -29,6 +29,7 @@ package org.apache.hc.client5.http.impl.async; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; +import java.util.concurrent.CancellationException; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; @@ -209,12 +210,15 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient final FutureCallback callback) { Args.notNull(host, "Host"); Args.notNull(context, "HTTP context"); - ensureRunning(); + final BasicFuture future = new BasicFuture<>(callback); + if (!isRunning()) { + future.failed(new CancellationException("Connection lease cancelled")); + return future; + } final HttpClientContext clientContext = HttpClientContext.adapt(context); final RequestConfig requestConfig = clientContext.getRequestConfig(); final Timeout connectionRequestTimeout = requestConfig.getConnectionRequestTimeout(); final Timeout connectTimeout = requestConfig.getConnectTimeout(); - final BasicFuture future = new BasicFuture<>(callback); leaseEndpoint( host, connectionRequestTimeout, @@ -246,10 +250,12 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient final AsyncClientExchangeHandler exchangeHandler, final HandlerFactory pushHandlerFactory, final HttpContext context) { - ensureRunning(); final ComplexCancellable cancellable = new ComplexCancellable(); - final HttpClientContext clientContext = context != null ? HttpClientContext.adapt(context) : HttpClientContext.create(); try { + if (!isRunning()) { + throw new CancellationException("Request execution cancelled"); + } + final HttpClientContext clientContext = context != null ? HttpClientContext.adapt(context) : HttpClientContext.create(); exchangeHandler.produceRequest(new RequestChannel() { @Override @@ -426,7 +432,7 @@ public final class MinimalHttpAsyncClient extends AbstractMinimalHttpAsyncClient } }, context); - } catch (final HttpException | IOException ex) { + } catch (final HttpException | IOException | IllegalStateException ex) { exchangeHandler.failed(ex); } return cancellable;