You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2017/12/24 11:09:26 UTC

[1/2] httpcomponents-client git commit: Added Cancellable convenience methods

Repository: httpcomponents-client
Updated Branches:
  refs/heads/master d6d3d364e -> 1e4e20416


Added Cancellable convenience methods


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/e2628424
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/e2628424
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/e2628424

Branch: refs/heads/master
Commit: e26284246638a750d74f9d96b4f9761e914f884f
Parents: d6d3d36
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Fri Dec 22 20:27:45 2017 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Sat Dec 23 10:48:46 2017 +0100

----------------------------------------------------------------------
 .../http/cache/HttpAsyncCacheStorage.java       |  9 ---
 .../cache/HttpAsyncCacheStorageAdaptor.java     | 11 ++--
 .../AbstractSerializingAsyncCacheStorage.java   |  9 +--
 .../MemcachedHttpAsyncCacheStorage.java         | 28 ++------
 .../apache/hc/client5/http/impl/Operations.java | 68 ++++++++++++++++++++
 5 files changed, 83 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e2628424/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
index 72064b3..6fdf1f8 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
@@ -42,15 +42,6 @@ import org.apache.hc.core5.concurrent.FutureCallback;
  */
 public interface HttpAsyncCacheStorage {
 
-    Cancellable NOOP_CANCELLABLE = new Cancellable() {
-
-        @Override
-        public boolean cancel() {
-            return false;
-        }
-
-    };
-
     /**
      * Store a given cache entry under the given key.
      * @param key where in the cache to store the entry

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e2628424/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
index d5199af..55bd095 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
@@ -29,6 +29,7 @@ package org.apache.hc.client5.http.cache;
 import java.util.Collection;
 import java.util.Map;
 
+import org.apache.hc.client5.http.impl.Operations;
 import org.apache.hc.core5.concurrent.Cancellable;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.util.Args;
@@ -57,7 +58,7 @@ public final class HttpAsyncCacheStorageAdaptor implements HttpAsyncCacheStorage
         } catch (final Exception ex) {
             callback.failed(ex);
         }
-        return NOOP_CANCELLABLE;
+        return Operations.nonCancellable();
     }
 
     public Cancellable getEntry(final String key, final FutureCallback<HttpCacheEntry> callback) {
@@ -69,7 +70,7 @@ public final class HttpAsyncCacheStorageAdaptor implements HttpAsyncCacheStorage
         } catch (final Exception ex) {
             callback.failed(ex);
         }
-        return NOOP_CANCELLABLE;
+        return Operations.nonCancellable();
     }
 
     public Cancellable removeEntry(final String key, final FutureCallback<Boolean> callback) {
@@ -81,7 +82,7 @@ public final class HttpAsyncCacheStorageAdaptor implements HttpAsyncCacheStorage
         } catch (final Exception ex) {
             callback.failed(ex);
         }
-        return NOOP_CANCELLABLE;
+        return Operations.nonCancellable();
     }
 
     public Cancellable updateEntry(
@@ -95,7 +96,7 @@ public final class HttpAsyncCacheStorageAdaptor implements HttpAsyncCacheStorage
         } catch (final Exception ex) {
             callback.failed(ex);
         }
-        return NOOP_CANCELLABLE;
+        return Operations.nonCancellable();
     }
 
     public Cancellable getEntries(final Collection<String> keys, final FutureCallback<Map<String, HttpCacheEntry>> callback) {
@@ -106,7 +107,7 @@ public final class HttpAsyncCacheStorageAdaptor implements HttpAsyncCacheStorage
         } catch (final Exception ex) {
             callback.failed(ex);
         }
-        return NOOP_CANCELLABLE;
+        return Operations.nonCancellable();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e2628424/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
index 60805dd..ce4ed7c 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
@@ -40,6 +40,7 @@ import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
 import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
 import org.apache.hc.client5.http.cache.HttpCacheUpdateException;
 import org.apache.hc.client5.http.cache.ResourceIOException;
+import org.apache.hc.client5.http.impl.Operations;
 import org.apache.hc.core5.concurrent.Cancellable;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.util.Args;
@@ -86,7 +87,7 @@ public abstract class AbstractSerializingAsyncCacheStorage<T, CAS> implements Ht
             return store(storageKey, storageObject, callback);
         } catch (final Exception ex) {
             callback.failed(ex);
-            return NOOP_CANCELLABLE;
+            return Operations.nonCancellable();
         }
     }
 
@@ -129,7 +130,7 @@ public abstract class AbstractSerializingAsyncCacheStorage<T, CAS> implements Ht
             });
         } catch (final Exception ex) {
             callback.failed(ex);
-            return NOOP_CANCELLABLE;
+            return Operations.nonCancellable();
         }
     }
 
@@ -142,7 +143,7 @@ public abstract class AbstractSerializingAsyncCacheStorage<T, CAS> implements Ht
             return delete(storageKey, callback);
         } catch (final Exception ex) {
             callback.failed(ex);
-            return NOOP_CANCELLABLE;
+            return Operations.nonCancellable();
         }
     }
 
@@ -276,7 +277,7 @@ public abstract class AbstractSerializingAsyncCacheStorage<T, CAS> implements Ht
             });
         } catch (final Exception ex) {
             callback.failed(ex);
-            return NOOP_CANCELLABLE;
+            return Operations.nonCancellable();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e2628424/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
index 296b85a..b59529d 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
@@ -35,6 +35,7 @@ import java.util.concurrent.ExecutionException;
 
 import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
 import org.apache.hc.client5.http.cache.ResourceIOException;
+import org.apache.hc.client5.http.impl.Operations;
 import org.apache.hc.client5.http.impl.cache.AbstractBinaryAsyncCacheStorage;
 import org.apache.hc.client5.http.impl.cache.ByteArrayCacheEntrySerializer;
 import org.apache.hc.client5.http.impl.cache.CacheConfig;
@@ -176,14 +177,7 @@ public class MemcachedHttpAsyncCacheStorage extends AbstractBinaryAsyncCacheStor
             }
 
         });
-        return new Cancellable() {
-
-            @Override
-            public boolean cancel() {
-                return operationFuture.cancel();
-            }
-
-        };
+        return Operations.cancellable(operationFuture);
     }
 
     @Override
@@ -210,14 +204,7 @@ public class MemcachedHttpAsyncCacheStorage extends AbstractBinaryAsyncCacheStor
             }
 
         });
-        return new Cancellable() {
-
-            @Override
-            public boolean cancel() {
-                return getFuture.cancel(true);
-            }
-
-        };
+        return Operations.cancellable(getFuture);
     }
 
     @Override
@@ -268,14 +255,7 @@ public class MemcachedHttpAsyncCacheStorage extends AbstractBinaryAsyncCacheStor
                 callback.completed(resultMap);
             }
         });
-        return new Cancellable() {
-
-            @Override
-            public boolean cancel() {
-                return future.cancel(true);
-            }
-
-        };
+        return Operations.cancellable(future);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e2628424/httpclient5/src/main/java/org/apache/hc/client5/http/impl/Operations.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/Operations.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/Operations.java
new file mode 100644
index 0000000..f6b6351
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/Operations.java
@@ -0,0 +1,68 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.impl;
+
+import java.util.concurrent.Future;
+
+import org.apache.hc.core5.concurrent.Cancellable;
+
+public final class Operations {
+
+    private final static Cancellable NOOP_CANCELLABLE = new Cancellable() {
+
+        @Override
+        public boolean cancel() {
+            return false;
+        }
+
+    };
+
+    public static Cancellable nonCancellable() {
+        return NOOP_CANCELLABLE;
+    }
+
+    public static Cancellable cancellable(final Future<?> future) {
+        if (future == null) {
+            return NOOP_CANCELLABLE;
+        } else {
+            if (future instanceof Cancellable) {
+                return (Cancellable) future;
+            } else {
+                return new Cancellable() {
+
+                    @Override
+                    public boolean cancel() {
+                        return future.cancel(true);
+                    }
+
+                };
+            }
+        }
+    }
+
+}


[2/2] httpcomponents-client git commit: Request execution futures to cancel dependent operations when cancelled by the caller

Posted by ol...@apache.org.
Request execution futures to cancel dependent operations when cancelled by the caller


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/1e4e2041
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/1e4e2041
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/1e4e2041

Branch: refs/heads/master
Commit: 1e4e204162655a2256951b9b60257106bafca744
Parents: e262842
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Sat Dec 23 10:56:09 2017 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Sat Dec 23 11:21:55 2017 +0100

----------------------------------------------------------------------
 .../hc/client5/http/async/AsyncExecChain.java   |  9 +++-
 .../hc/client5/http/async/AsyncExecRuntime.java |  5 +-
 .../http/impl/async/AsyncConnectExec.java       | 40 +++++++-------
 .../http/impl/async/AsyncRedirectExec.java      |  4 +-
 .../async/InternalAbstractHttpAsyncClient.java  |  7 +--
 .../async/InternalHttp2AsyncExecRuntime.java    | 55 +++++++++++---------
 .../async/InternalHttpAsyncExecRuntime.java     | 48 ++++++++++-------
 7 files changed, 97 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java
index f0214d6..fa4f49b 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java
@@ -30,6 +30,7 @@ import java.io.IOException;
 
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.concurrent.ComplexFuture;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
@@ -42,20 +43,24 @@ public interface AsyncExecChain {
         public final String exchangeId;
         public final HttpRoute route;
         public final HttpRequest originalRequest;
-        public final AsyncExecRuntime execRuntime;
+        //TODO: replace with CancellableDependency from HttpCore
+        public final ComplexFuture<?> future;
         public final HttpClientContext clientContext;
+        public final AsyncExecRuntime execRuntime;
 
         public Scope(
                 final String exchangeId,
                 final HttpRoute route,
                 final HttpRequest originalRequest,
+                final ComplexFuture<?> future,
                 final HttpClientContext clientContext,
                 final AsyncExecRuntime execRuntime) {
             this.exchangeId = Args.notBlank(exchangeId, "Exchange id");
             this.route = Args.notNull(route, "Route");
             this.originalRequest = Args.notNull(originalRequest, "Original request");
-            this.execRuntime = Args.notNull(execRuntime, "Exec runtime");
+            this.future = Args.notNull(future, "Future");
             this.clientContext = clientContext != null ? clientContext : HttpClientContext.create();
+            this.execRuntime = Args.notNull(execRuntime, "Exec runtime");
         }
 
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java
index ae49e2d..402b2c3 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java
@@ -30,6 +30,7 @@ package org.apache.hc.client5.http.async;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.concurrent.Cancellable;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
 import org.apache.hc.core5.util.TimeValue;
@@ -48,7 +49,7 @@ public interface AsyncExecRuntime {
 
     boolean isConnectionAcquired();
 
-    void acquireConnection(
+    Cancellable acquireConnection(
             HttpRoute route,
             Object state,
             HttpClientContext clientContext,
@@ -62,7 +63,7 @@ public interface AsyncExecRuntime {
 
     boolean isConnected();
 
-    void connect(
+    Cancellable connect(
             HttpClientContext clientContext,
             FutureCallback<AsyncExecRuntime> callback);
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
index e10b3c0..378b44e 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
@@ -47,6 +47,7 @@ import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.routing.HttpRouteDirector;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.concurrent.ComplexFuture;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.HttpException;
@@ -118,6 +119,7 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
 
         final String exchangeId = scope.exchangeId;
         final HttpRoute route = scope.route;
+        final ComplexFuture<?> future = scope.future;
         final HttpClientContext clientContext = scope.clientContext;
         final AsyncExecRuntime execRuntime = scope.execRuntime;
         final State state = new State(route);
@@ -147,24 +149,25 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
             if (log.isDebugEnabled()) {
                 log.debug(exchangeId + ": acquiring connection with route " + route);
             }
-            execRuntime.acquireConnection(route, userToken, clientContext, new FutureCallback<AsyncExecRuntime>() {
+            future.setDependency(execRuntime.acquireConnection(
+                    route, userToken, clientContext, new FutureCallback<AsyncExecRuntime>() {
 
-                @Override
-                public void completed(final AsyncExecRuntime execRuntime) {
-                    routeInitiation.run();
-                }
+                        @Override
+                        public void completed(final AsyncExecRuntime execRuntime) {
+                            routeInitiation.run();
+                        }
 
-                @Override
-                public void failed(final Exception ex) {
-                    asyncExecCallback.failed(ex);
-                }
+                        @Override
+                        public void failed(final Exception ex) {
+                            asyncExecCallback.failed(ex);
+                        }
 
-                @Override
-                public void cancelled() {
-                    asyncExecCallback.failed(new InterruptedIOException());
-                }
+                        @Override
+                        public void cancelled() {
+                            asyncExecCallback.failed(new InterruptedIOException());
+                        }
 
-            });
+                    }));
         } else {
             routeInitiation.run();
         }
@@ -181,6 +184,7 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
         final RouteTracker tracker = state.tracker;
         final AsyncExecRuntime execRuntime = scope.execRuntime;
         final HttpRoute route = scope.route;
+        final ComplexFuture<?> future = scope.future;
         final HttpClientContext clientContext = scope.clientContext;
 
         int step;
@@ -189,7 +193,7 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
             step = routeDirector.nextStep(route, fact);
             switch (step) {
                 case HttpRouteDirector.CONNECT_TARGET:
-                    execRuntime.connect(clientContext, new FutureCallback<AsyncExecRuntime>() {
+                    future.setDependency(execRuntime.connect(clientContext, new FutureCallback<AsyncExecRuntime>() {
 
                         @Override
                         public void completed(final AsyncExecRuntime execRuntime) {
@@ -208,11 +212,11 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
                             asyncExecCallback.failed(new InterruptedIOException());
                         }
 
-                    });
+                    }));
                     return;
 
                 case HttpRouteDirector.CONNECT_PROXY:
-                    execRuntime.connect(clientContext, new FutureCallback<AsyncExecRuntime>() {
+                    future.setDependency(execRuntime.connect(clientContext, new FutureCallback<AsyncExecRuntime>() {
 
                         @Override
                         public void completed(final AsyncExecRuntime execRuntime) {
@@ -232,7 +236,7 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
                             asyncExecCallback.failed(new InterruptedIOException());
                         }
 
-                    });
+                    }));
                     return;
 
                 case HttpRouteDirector.TUNNEL_TARGET:

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
index f59277e..4f34bf6 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
@@ -143,8 +143,8 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
                             }
                         }
                         final HttpRoute newRoute = routePlanner.determineRoute(newTarget, clientContext);
-                        state.currentScope = new AsyncExecChain.Scope(
-                                scope.exchangeId, newRoute, scope.originalRequest, clientContext, scope.execRuntime);
+                        state.currentScope = new AsyncExecChain.Scope(scope.exchangeId, newRoute,
+                                scope.originalRequest, scope.future, clientContext, scope.execRuntime);
                         state.redirectURI = redirectUri;
                     } else {
                         state.reroute = false;

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalAbstractHttpAsyncClient.java
----------------------------------------------------------------------
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 aab6f78..813494e 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
@@ -49,7 +49,7 @@ import org.apache.hc.client5.http.cookie.CookieStore;
 import org.apache.hc.client5.http.impl.ExecSupport;
 import org.apache.hc.client5.http.impl.RequestCopier;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.core5.concurrent.BasicFuture;
+import org.apache.hc.core5.concurrent.ComplexFuture;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.HttpException;
@@ -140,7 +140,7 @@ abstract class InternalAbstractHttpAsyncClient extends AbstractHttpAsyncClientBa
             final HttpContext context,
             final FutureCallback<T> callback) {
         ensureRunning();
-        final BasicFuture<T> future = new BasicFuture<>(callback);
+        final ComplexFuture<T> future = new ComplexFuture<>(callback);
         try {
             final HttpClientContext clientContext = HttpClientContext.adapt(context);
             requestProducer.sendRequest(new RequestChannel() {
@@ -166,7 +166,8 @@ abstract class InternalAbstractHttpAsyncClient extends AbstractHttpAsyncClientBa
 
                     setupContext(clientContext);
 
-                    final AsyncExecChain.Scope scope = new AsyncExecChain.Scope(exchangeId, route, request, clientContext, execRuntime);
+                    final AsyncExecChain.Scope scope = new AsyncExecChain.Scope(exchangeId, route, request, future,
+                            clientContext, execRuntime);
                     final AtomicReference<T> resultRef = new AtomicReference<>(null);
                     final AtomicBoolean outputTerminated = new AtomicBoolean(false);
                     execChain.execute(

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncExecRuntime.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncExecRuntime.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncExecRuntime.java
index 0c4176c..62fa5ab 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncExecRuntime.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncExecRuntime.java
@@ -34,7 +34,9 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.async.AsyncExecRuntime;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
+import org.apache.hc.client5.http.impl.Operations;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.concurrent.Cancellable;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
@@ -65,7 +67,7 @@ class InternalHttp2AsyncExecRuntime implements AsyncExecRuntime {
     }
 
     @Override
-    public void acquireConnection(
+    public Cancellable acquireConnection(
             final HttpRoute route,
             final Object object,
             final HttpClientContext context,
@@ -73,28 +75,32 @@ class InternalHttp2AsyncExecRuntime implements AsyncExecRuntime {
         if (sessionRef.get() == null) {
             final HttpHost target = route.getTargetHost();
             final RequestConfig requestConfig = context.getRequestConfig();
-            connPool.getSession(target, requestConfig.getConnectionTimeout(), new FutureCallback<IOSession>() {
-
-                @Override
-                public void completed(final IOSession ioSession) {
-                    sessionRef.set(new Endpoint(target, ioSession));
-                    reusable = true;
-                    callback.completed(InternalHttp2AsyncExecRuntime.this);
-                }
-
-                @Override
-                public void failed(final Exception ex) {
-                    callback.failed(ex);
-                }
-
-                @Override
-                public void cancelled() {
-                    callback.cancelled();
-                }
-
-            });
+            return Operations.cancellable(connPool.getSession(
+                    target,
+                    requestConfig.getConnectionTimeout(),
+                    new FutureCallback<IOSession>() {
+
+                        @Override
+                        public void completed(final IOSession ioSession) {
+                            sessionRef.set(new Endpoint(target, ioSession));
+                            reusable = true;
+                            callback.completed(InternalHttp2AsyncExecRuntime.this);
+                        }
+
+                        @Override
+                        public void failed(final Exception ex) {
+                            callback.failed(ex);
+                        }
+
+                        @Override
+                        public void cancelled() {
+                            callback.cancelled();
+                        }
+
+                    }));
         } else {
             callback.completed(this);
+            return Operations.nonCancellable();
         }
     }
 
@@ -144,16 +150,17 @@ class InternalHttp2AsyncExecRuntime implements AsyncExecRuntime {
     }
 
     @Override
-    public void connect(
+    public Cancellable connect(
             final HttpClientContext context,
             final FutureCallback<AsyncExecRuntime> callback) {
         final Endpoint endpoint = ensureValid();
         if (!endpoint.session.isClosed()) {
             callback.completed(this);
+            return Operations.nonCancellable();
         } else {
             final HttpHost target = endpoint.target;
             final RequestConfig requestConfig = context.getRequestConfig();
-            connPool.getSession(target, requestConfig.getConnectionTimeout(), new FutureCallback<IOSession>() {
+            return Operations.cancellable(connPool.getSession(target, requestConfig.getConnectionTimeout(), new FutureCallback<IOSession>() {
 
                 @Override
                 public void completed(final IOSession ioSession) {
@@ -172,7 +179,7 @@ class InternalHttp2AsyncExecRuntime implements AsyncExecRuntime {
                     callback.cancelled();
                 }
 
-            });
+            }));
         }
 
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1e4e2041/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
index e7566c4..d927fc2 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncExecRuntime.java
@@ -35,9 +35,11 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.async.AsyncExecRuntime;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
+import org.apache.hc.client5.http.impl.Operations;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
 import org.apache.hc.client5.http.nio.AsyncConnectionEndpoint;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.concurrent.Cancellable;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
@@ -76,7 +78,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
     }
 
     @Override
-    public void acquireConnection(
+    public Cancellable acquireConnection(
             final HttpRoute route,
             final Object object,
             final HttpClientContext context,
@@ -84,27 +86,32 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
         if (endpointRef.get() == null) {
             state = object;
             final RequestConfig requestConfig = context.getRequestConfig();
-            manager.lease(route, object, requestConfig.getConnectionRequestTimeout(), new FutureCallback<AsyncConnectionEndpoint>() {
+            return Operations.cancellable(manager.lease(
+                    route,
+                    object,
+                    requestConfig.getConnectionRequestTimeout(),
+                    new FutureCallback<AsyncConnectionEndpoint>() {
 
-                @Override
-                public void completed(final AsyncConnectionEndpoint connectionEndpoint) {
-                    endpointRef.set(connectionEndpoint);
-                    reusable = connectionEndpoint.isConnected();
-                    callback.completed(InternalHttpAsyncExecRuntime.this);
-                }
+                        @Override
+                        public void completed(final AsyncConnectionEndpoint connectionEndpoint) {
+                            endpointRef.set(connectionEndpoint);
+                            reusable = connectionEndpoint.isConnected();
+                            callback.completed(InternalHttpAsyncExecRuntime.this);
+                        }
 
-                @Override
-                public void failed(final Exception ex) {
-                    callback.failed(ex);
-                }
+                        @Override
+                        public void failed(final Exception ex) {
+                            callback.failed(ex);
+                        }
 
-                @Override
-                public void cancelled() {
-                    callback.cancelled();
-                }
-            });
+                        @Override
+                        public void cancelled() {
+                            callback.cancelled();
+                        }
+                    }));
         } else {
             callback.completed(this);
+            return Operations.nonCancellable();
         }
     }
 
@@ -175,16 +182,17 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
     }
 
     @Override
-    public void connect(
+    public Cancellable connect(
             final HttpClientContext context,
             final FutureCallback<AsyncExecRuntime> callback) {
         final AsyncConnectionEndpoint endpoint = ensureValid();
         if (endpoint.isConnected()) {
             callback.completed(this);
+            return Operations.nonCancellable();
         } else {
             final RequestConfig requestConfig = context.getRequestConfig();
             final TimeValue timeout = requestConfig.getConnectionTimeout();
-            manager.connect(
+            return Operations.cancellable(manager.connect(
                     endpoint,
                     connectionInitiator,
                     timeout,
@@ -210,7 +218,7 @@ class InternalHttpAsyncExecRuntime implements AsyncExecRuntime {
                             callback.cancelled();
                         }
 
-            });
+            }));
         }
 
     }