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/09/01 18:15:29 UTC

[5/6] httpcomponents-client git commit: Upgraded HttpCore to version 5.0-alpha4

Upgraded HttpCore to version 5.0-alpha4


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

Branch: refs/heads/master
Commit: 1eb221808f037b1c7242d0b4c092e5c3eea49edf
Parents: 272ea1f
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Tue Aug 29 16:12:38 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Fri Sep 1 17:39:24 2017 +0200

----------------------------------------------------------------------
 .../impl/cache/CachingHttpClientBuilder.java    |   2 +-
 .../http/impl/cache/TestCachingExecChain.java   |   9 +-
 ...taleWhileRevalidationReleasesConnection.java |   2 +-
 .../http/examples/fluent/FluentExecutor.java    |   6 +-
 .../http/examples/fluent/FluentRequests.java    |   6 +-
 .../examples/fluent/FluentResponseHandling.java |   4 +-
 .../apache/hc/client5/http/fluent/Async.java    |  10 +-
 .../http/fluent/ContentResponseHandler.java     |   4 +-
 .../apache/hc/client5/http/fluent/Request.java  |  10 +-
 .../apache/hc/client5/http/fluent/Response.java |   7 +-
 .../AbstractSimpleServerExchangeHandler.java    |   8 +-
 .../client5/testing/async/AsyncEchoHandler.java |   4 +-
 .../testing/async/AsyncRandomHandler.java       |   4 +-
 .../async/AuthenticatingAsyncDecorator.java     | 181 ++++++++
 .../hc/client5/testing/auth/Authenticator.java  |  38 ++
 .../testing/auth/BasicAuthTokenExtractor.java   |  29 +-
 .../client5/testing/auth/RequestBasicAuth.java  |  55 ---
 .../testing/auth/ResponseBasicUnauthorized.java |  54 ---
 .../classic/AuthenticatingDecorator.java        | 105 +++++
 .../client5/testing/BasicTestAuthenticator.java |  54 +++
 .../testing/async/IntegrationTestBase.java      |  22 +-
 .../testing/async/TestAsyncRedirects.java       |   4 +-
 .../testing/async/TestClientAuthentication.java | 228 ++++------
 .../testing/async/TestHttpAsyncMinimal.java     |   6 +-
 .../hc/client5/testing/fluent/TestFluent.java   |  11 +-
 .../testing/sync/LocalServerTestBase.java       | 115 +++--
 .../testing/sync/TestClientAuthentication.java  | 424 +++++++++++--------
 .../sync/TestClientAuthenticationFakeNTLM.java  |  10 +-
 .../sync/TestClientAuthenticationFallBack.java  | 148 -------
 .../sync/TestClientReauthentication.java        | 188 --------
 .../sync/TestClientRequestExecution.java        |  10 +-
 .../testing/sync/TestConnectionAutoRelease.java | 229 ----------
 .../testing/sync/TestConnectionReuse.java       |  33 +-
 .../testing/sync/TestContentCodings.java        |  24 +-
 .../testing/sync/TestCookieVirtualHost.java     |   2 +-
 .../sync/TestMalformedServerResponse.java       |  73 ++--
 .../sync/TestMinimalClientRequestExecution.java |   2 +-
 .../hc/client5/testing/sync/TestRedirects.java  | 200 +++++----
 .../client5/testing/sync/TestSPNegoScheme.java  |   4 +-
 .../sync/TestStatefulConnManagement.java        |   6 +-
 .../sync/TestWindowsNegotiateScheme.java        |  18 +-
 .../examples/AsyncClientConnectionEviction.java |   3 +-
 .../examples/AsyncClientHttp1Pipelining.java    |   4 +-
 .../examples/AsyncClientHttp2Multiplexing.java  |   4 +-
 .../examples/AsyncClientHttp2ServerPush.java    |   4 +-
 .../http/examples/AsyncClientHttpExchange.java  |   4 +-
 .../AsyncClientHttpExchangeStreaming.java       |   4 +-
 .../http/examples/AsyncClientInterceptors.java  |   4 +-
 .../examples/AsyncClientMessageTrailers.java    |   4 +-
 .../http/examples/ClientConfiguration.java      |   7 +-
 .../http/examples/ClientWithRequestFuture.java  |   6 +-
 .../examples/ClientWithResponseHandler.java     |   6 +-
 .../hc/client5/http/config/RequestConfig.java   |  44 +-
 .../hc/client5/http/impl/NamedElementChain.java | 212 ----------
 .../impl/async/AbstractHttpAsyncClientBase.java |  20 +-
 .../impl/async/BasicAsyncEntityProducer.java    |  94 ----
 .../impl/async/CloseableHttpAsyncClient.java    |   2 +-
 .../http/impl/async/HttpAsyncClientBuilder.java |  32 +-
 .../HttpAsyncClientEventHandlerFactory.java     |  39 +-
 .../http/impl/async/HttpAsyncClients.java       |  21 +-
 .../impl/async/InternalAsyncEntityProducer.java |  93 ++++
 .../impl/async/InternalHttpAsyncClient.java     |  10 +-
 .../http/impl/async/MinimalHttpAsyncClient.java | 122 +++---
 .../io/PoolingHttpClientConnectionManager.java  |  14 +-
 ...olingHttpClientConnectionManagerBuilder.java |  12 +-
 .../impl/nio/AsyncClientConnectionOperator.java |  35 +-
 .../impl/nio/ManagedAsyncClientConnection.java  |  16 +-
 .../PoolingAsyncClientConnectionManager.java    |  11 +-
 ...lingAsyncClientConnectionManagerBuilder.java |  18 +-
 .../sync/AbstractHttpClientResponseHandler.java |  79 ++++
 .../http/impl/sync/AbstractResponseHandler.java |  79 ----
 .../sync/BasicHttpClientResponseHandler.java    |  73 ++++
 .../http/impl/sync/BasicResponseHandler.java    |  73 ----
 .../http/impl/sync/CloseableHttpClient.java     |  36 +-
 .../sync/FutureRequestExecutionService.java     |  14 +-
 .../http/impl/sync/HttpClientBuilder.java       |   2 +-
 .../http/impl/sync/HttpRequestTaskCallable.java |   6 +-
 .../http/nio/AsyncClientConnectionManager.java  |   3 +-
 .../apache/hc/client5/http/sync/HttpClient.java |  26 +-
 .../apache/hc/client5/http/utils/URIUtils.java  |   2 +-
 .../client5/http/config/TestRequestConfig.java  |   7 +-
 .../TestAbstractHttpClientResponseHandler.java  |  89 ++++
 .../http/impl/TestAbstractResponseHandler.java  |  89 ----
 .../http/impl/TestBasicResponseHandler.java     |   8 +-
 .../http/impl/TestNamedElementChain.java        |  97 -----
 .../http/impl/sync/TestCloseableHttpClient.java |   8 +-
 .../sync/TestFutureRequestExecutionService.java |   6 +-
 pom.xml                                         |   2 +-
 88 files changed, 1651 insertions(+), 2242 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
index 052b6ff..e734523 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
@@ -33,10 +33,10 @@ import java.io.IOException;
 import org.apache.hc.client5.http.cache.HttpCacheInvalidator;
 import org.apache.hc.client5.http.cache.HttpCacheStorage;
 import org.apache.hc.client5.http.cache.ResourceFactory;
-import org.apache.hc.client5.http.impl.NamedElementChain;
 import org.apache.hc.client5.http.impl.sync.ChainElements;
 import org.apache.hc.client5.http.impl.sync.HttpClientBuilder;
 import org.apache.hc.client5.http.sync.ExecChainHandler;
+import org.apache.hc.core5.http.config.NamedElementChain;
 
 /**
  * Builder for {@link org.apache.hc.client5.http.impl.sync.CloseableHttpClient}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
index 00d3747..fcf05f2 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
@@ -47,7 +47,6 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
-import junit.framework.AssertionFailedError;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.cache.CacheResponseStatus;
 import org.apache.hc.client5.http.cache.HttpCacheContext;
@@ -71,7 +70,7 @@ import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.io.ResponseHandler;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.http.io.entity.InputStreamEntity;
 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
@@ -85,6 +84,8 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import junit.framework.AssertionFailedError;
+
 @SuppressWarnings("boxing") // test code
 public abstract class TestCachingExecChain {
 
@@ -100,7 +101,7 @@ public abstract class TestCachingExecChain {
     protected ResponseCachingPolicy mockResponsePolicy;
     protected HttpCacheEntry mockCacheEntry;
     protected CachedHttpResponseGenerator mockResponseGenerator;
-    private ResponseHandler<Object> mockHandler;
+    private HttpClientResponseHandler<Object> mockHandler;
     private ClassicHttpRequest mockUriRequest;
     private ClassicHttpResponse mockCachedResponse;
     protected ConditionalRequestBuilder mockConditionalRequestBuilder;
@@ -126,7 +127,7 @@ public abstract class TestCachingExecChain {
         mockCache = createNiceMock(HttpCache.class);
         mockSuitabilityChecker = createNiceMock(CachedResponseSuitabilityChecker.class);
         mockResponsePolicy = createNiceMock(ResponseCachingPolicy.class);
-        mockHandler = createNiceMock(ResponseHandler.class);
+        mockHandler = createNiceMock(HttpClientResponseHandler.class);
         mockUriRequest = createNiceMock(ClassicHttpRequest.class);
         mockCacheEntry = createNiceMock(HttpCacheEntry.class);
         mockResponseGenerator = createNiceMock(CachedHttpResponseGenerator.class);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestStaleWhileRevalidationReleasesConnection.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestStaleWhileRevalidationReleasesConnection.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestStaleWhileRevalidationReleasesConnection.java
index ee59498..83b06d7 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestStaleWhileRevalidationReleasesConnection.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestStaleWhileRevalidationReleasesConnection.java
@@ -81,7 +81,7 @@ public class TestStaleWhileRevalidationReleasesConnection {
                 .setSocketConfig(SocketConfig.custom()
                         .setSoTimeout(5, TimeUnit.SECONDS)
                         .build())
-                .registerHandler(url + "*", new EchoViaHeaderHandler())
+                .register(url + "*", new EchoViaHeaderHandler())
                 .create();
         this.localServer.start();
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentExecutor.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentExecutor.java b/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentExecutor.java
index 1a4e16a..c6ccccf 100644
--- a/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentExecutor.java
+++ b/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentExecutor.java
@@ -34,7 +34,7 @@ import org.apache.hc.client5.http.fluent.Request;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates how the he HttpClient fluent API can be used to execute multiple
@@ -52,8 +52,8 @@ public class FluentExecutor {
 
         // Execute a GET with timeout settings and return response content as String.
         executor.execute(Request.Get("http://somehost/")
-                .connectTimeout(TimeValue.ofSeconds(1))
-                .socketTimeout(TimeValue.ofSeconds(1))
+                .connectTimeout(Timeout.ofSeconds(1))
+                .socketTimeout(Timeout.ofSeconds(1))
                 ).returnContent().asString();
 
         // Execute a POST with the 'expect-continue' handshake, using HTTP/1.1,

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentRequests.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentRequests.java b/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentRequests.java
index b1aa399..520dd62 100644
--- a/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentRequests.java
+++ b/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentRequests.java
@@ -33,7 +33,7 @@ import org.apache.hc.client5.http.fluent.Request;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 
 /**
  * This example demonstrates basics of request execution with the HttpClient fluent API.
@@ -43,8 +43,8 @@ public class FluentRequests {
     public static void main(String[] args)throws Exception {
         // Execute a GET with timeout settings and return response content as String.
         Request.Get("http://somehost/")
-                .connectTimeout(TimeValue.ofSeconds(1))
-                .socketTimeout(TimeValue.ofSeconds(1))
+                .connectTimeout(Timeout.ofSeconds(1))
+                .socketTimeout(Timeout.ofSeconds(1))
                 .execute().returnContent().asString();
 
         // Execute a POST with the 'expect-continue' handshake, using HTTP/1.1,

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentResponseHandling.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentResponseHandling.java b/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentResponseHandling.java
index b989eaa..fe62aae 100644
--- a/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentResponseHandling.java
+++ b/httpclient5-fluent/src/examples/org/apache/hc/client5/http/examples/fluent/FluentResponseHandling.java
@@ -41,7 +41,7 @@ import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.io.ResponseHandler;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
@@ -54,7 +54,7 @@ public class FluentResponseHandling {
 
     public static void main(String[] args)throws Exception {
         Document result = Request.Get("http://somehost/content")
-                .execute().handleResponse(new ResponseHandler<Document>() {
+                .execute().handleResponse(new HttpClientResponseHandler<Document>() {
 
             @Override
             public Document handleResponse(final ClassicHttpResponse response) throws IOException {

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Async.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Async.java b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Async.java
index 7c6462d..beb710b 100644
--- a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Async.java
+++ b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Async.java
@@ -30,7 +30,7 @@ import java.util.concurrent.Future;
 
 import org.apache.hc.core5.concurrent.BasicFuture;
 import org.apache.hc.core5.concurrent.FutureCallback;
-import org.apache.hc.core5.http.io.ResponseHandler;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
 
 public class Async {
 
@@ -60,13 +60,13 @@ public class Async {
         private final BasicFuture<T> future;
         private final Request request;
         private final Executor executor;
-        private final ResponseHandler<T> handler;
+        private final HttpClientResponseHandler<T> handler;
 
         ExecRunnable(
                 final BasicFuture<T> future,
                 final Request request,
                 final Executor executor,
-                final ResponseHandler<T> handler) {
+                final HttpClientResponseHandler<T> handler) {
             super();
             this.future = future;
             this.request = request;
@@ -88,7 +88,7 @@ public class Async {
     }
 
     public <T> Future<T> execute(
-            final Request request, final ResponseHandler<T> handler, final FutureCallback<T> callback) {
+            final Request request, final HttpClientResponseHandler<T> handler, final FutureCallback<T> callback) {
         final BasicFuture<T> future = new BasicFuture<>(callback);
         final ExecRunnable<T> runnable = new ExecRunnable<>(
                 future,
@@ -105,7 +105,7 @@ public class Async {
         return future;
     }
 
-    public <T> Future<T> execute(final Request request, final ResponseHandler<T> handler) {
+    public <T> Future<T> execute(final Request request, final HttpClientResponseHandler<T> handler) {
         return execute(request, handler, null);
     }
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/ContentResponseHandler.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/ContentResponseHandler.java b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/ContentResponseHandler.java
index 77cde47..6954891 100644
--- a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/ContentResponseHandler.java
+++ b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/ContentResponseHandler.java
@@ -28,7 +28,7 @@ package org.apache.hc.client5.http.fluent;
 
 import java.io.IOException;
 
-import org.apache.hc.client5.http.impl.sync.AbstractResponseHandler;
+import org.apache.hc.client5.http.impl.sync.AbstractHttpClientResponseHandler;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 
@@ -41,7 +41,7 @@ import org.apache.hc.core5.http.io.entity.EntityUtils;
  *
  * @since 4.4
  */
-public class ContentResponseHandler extends AbstractResponseHandler<Content> {
+public class ContentResponseHandler extends AbstractHttpClientResponseHandler<Content> {
 
     @Override
     public Content handleEntity(final HttpEntity entity) throws IOException {

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Request.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Request.java b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Request.java
index 8d1b1f2..533f321 100644
--- a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Request.java
+++ b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Request.java
@@ -66,7 +66,7 @@ import org.apache.hc.core5.http.io.entity.FileEntity;
 import org.apache.hc.core5.http.io.entity.InputStreamEntity;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.net.URLEncodedUtils;
-import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 
 public class Request {
 
@@ -76,8 +76,8 @@ public class Request {
 
     private final HttpUriRequestBase request;
     private Boolean useExpectContinue;
-    private TimeValue socketTmeout;
-    private TimeValue connectTimeout;
+    private Timeout socketTmeout;
+    private Timeout connectTimeout;
     private HttpHost proxy;
 
     private SimpleDateFormat dateFormatter;
@@ -283,12 +283,12 @@ public class Request {
 
     //// HTTP connection parameter operations
 
-    public Request socketTimeout(final TimeValue timeout) {
+    public Request socketTimeout(final Timeout timeout) {
         this.socketTmeout = timeout;
         return this;
     }
 
-    public Request connectTimeout(final TimeValue timeout) {
+    public Request connectTimeout(final Timeout timeout) {
         this.connectTimeout = timeout;
         return this;
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Response.java
----------------------------------------------------------------------
diff --git a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Response.java b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Response.java
index 06a4f47..2cd74fa 100644
--- a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Response.java
+++ b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Response.java
@@ -39,7 +39,7 @@ import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.io.ResponseHandler;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
 import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 
@@ -83,10 +83,9 @@ public class Response {
     }
 
     /**
-     * Handles the response using the specified {@link ResponseHandler}
+     * Handles the response using the specified {@link HttpClientResponseHandler}
      */
-    public <T> T handleResponse(
-            final ResponseHandler<T> handler) throws IOException {
+    public <T> T handleResponse(final HttpClientResponseHandler<T> handler) throws IOException {
         assertNotConsumed();
         try {
             return handler.handleResponse(this.response);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
index cf3a8ef..5200e63 100644
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
@@ -34,12 +34,12 @@ import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
+import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
+import org.apache.hc.core5.http.nio.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.support.AbstractAsyncRequesterConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler;
-import org.apache.hc.core5.http.nio.support.BasicAsyncResponseProducer;
-import org.apache.hc.core5.http.nio.support.ResponseTrigger;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
 
@@ -67,10 +67,10 @@ public abstract class AbstractSimpleServerExchangeHandler extends AbstractServer
     @Override
     protected final void handle(
             final SimpleHttpRequest request,
-            final ResponseTrigger responseTrigger,
+            final AsyncServerRequestHandler.ResponseTrigger responseTrigger,
             final HttpContext context) throws HttpException, IOException {
         final SimpleHttpResponse response = handle(request, HttpCoreContext.adapt(context));
-        responseTrigger.submitResponse(new BasicAsyncResponseProducer(
+        responseTrigger.submitResponse(new BasicResponseProducer(
                 response,
                 response.getBody() != null ? new StringAsyncEntityProducer(response.getBody(), response.getContentType()) : null));
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncEchoHandler.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncEchoHandler.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncEchoHandler.java
index eb74c53..03bc189 100644
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncEchoHandler.java
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncEchoHandler.java
@@ -48,6 +48,7 @@ import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Asserts;
 
 /**
@@ -76,7 +77,8 @@ public class AsyncEchoHandler implements AsyncServerExchangeHandler {
     public void handleRequest(
             final HttpRequest request,
             final EntityDetails entityDetails,
-            final ResponseChannel responseChannel) throws HttpException, IOException {
+            final ResponseChannel responseChannel,
+            final HttpContext context) throws HttpException, IOException {
         final String method = request.getMethod();
         if (!"GET".equalsIgnoreCase(method) &&
                 !"HEAD".equalsIgnoreCase(method) &&

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncRandomHandler.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncRandomHandler.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncRandomHandler.java
index f7d9bc6..9e44db3 100644
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncRandomHandler.java
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AsyncRandomHandler.java
@@ -52,6 +52,7 @@ import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.nio.StreamChannel;
 import org.apache.hc.core5.http.nio.entity.AbstractBinAsyncEntityProducer;
+import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Asserts;
 
 /**
@@ -77,7 +78,8 @@ public class AsyncRandomHandler implements AsyncServerExchangeHandler {
     public void handleRequest(
             final HttpRequest request,
             final EntityDetails entityDetails,
-            final ResponseChannel responseChannel) throws HttpException, IOException {
+            final ResponseChannel responseChannel,
+            final HttpContext context) throws HttpException, IOException {
         final String method = request.getMethod();
         if (!"GET".equalsIgnoreCase(method) &&
                 !"HEAD".equalsIgnoreCase(method) &&

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AuthenticatingAsyncDecorator.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AuthenticatingAsyncDecorator.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AuthenticatingAsyncDecorator.java
new file mode 100644
index 0000000..d9cd69c
--- /dev/null
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AuthenticatingAsyncDecorator.java
@@ -0,0 +1,181 @@
+/*
+ * ====================================================================
+ * 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.testing.async;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.hc.client5.testing.auth.Authenticator;
+import org.apache.hc.client5.testing.auth.BasicAuthTokenExtractor;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
+import org.apache.hc.core5.http.nio.AsyncResponseProducer;
+import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
+import org.apache.hc.core5.http.nio.BasicResponseProducer;
+import org.apache.hc.core5.http.nio.CapacityChannel;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.apache.hc.core5.http.nio.ResponseChannel;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.util.Args;
+
+public class AuthenticatingAsyncDecorator implements AsyncServerExchangeHandler {
+
+    private final AsyncServerExchangeHandler exchangeHandler;
+    private final Authenticator authenticator;
+    private final AtomicReference<AsyncResponseProducer> responseProducerRef;
+    private final BasicAuthTokenExtractor authTokenExtractor;
+
+    public AuthenticatingAsyncDecorator(final AsyncServerExchangeHandler exchangeHandler, final Authenticator authenticator) {
+        this.exchangeHandler = Args.notNull(exchangeHandler, "Request handler");
+        this.authenticator = Args.notNull(authenticator, "Authenticator");
+        this.responseProducerRef = new AtomicReference<>(null);
+        this.authTokenExtractor = new BasicAuthTokenExtractor();
+    }
+
+    protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
+    }
+
+    @Override
+    public void handleRequest(
+            final HttpRequest request,
+            final EntityDetails entityDetails,
+            final ResponseChannel responseChannel,
+            final HttpContext context) throws HttpException, IOException {
+        final Header h = request.getFirstHeader(HttpHeaders.AUTHORIZATION);
+        final String challengeResponse = h != null ? authTokenExtractor.extract(h.getValue()) : null;
+
+        final URIAuthority authority = request.getAuthority();
+        final String requestUri = request.getRequestUri();
+
+        final boolean authenticated = authenticator.authenticate(authority, requestUri, challengeResponse);
+        final Header expect = request.getFirstHeader(HttpHeaders.EXPECT);
+        final boolean expectContinue = expect != null && "100-continue".equalsIgnoreCase(expect.getValue());
+
+        if (authenticated) {
+            if (expectContinue) {
+                responseChannel.sendInformation(new BasicClassicHttpResponse(HttpStatus.SC_CONTINUE));
+            }
+            exchangeHandler.handleRequest(request, entityDetails, responseChannel, context);
+        } else {
+            final HttpResponse unauthorized = new BasicHttpResponse(HttpStatus.SC_UNAUTHORIZED);
+            final String realm = authenticator.getRealm(authority, requestUri);
+            unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"" + realm + "\"");
+
+            customizeUnauthorizedResponse(unauthorized);
+
+            final AsyncResponseProducer responseProducer = new BasicResponseProducer(
+                    unauthorized,
+                    new BasicAsyncEntityProducer("Unauthorized", ContentType.TEXT_PLAIN));
+            responseProducerRef.set(responseProducer);
+            responseProducer.sendResponse(responseChannel);
+        }
+
+    }
+
+    @Override
+    public final void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
+        final AsyncResponseProducer responseProducer = responseProducerRef.get();
+        if (responseProducer == null) {
+            exchangeHandler.updateCapacity(capacityChannel);
+        } else {
+            capacityChannel.update(Integer.MAX_VALUE);
+        }
+    }
+
+    @Override
+    public final int consume(final ByteBuffer src) throws IOException {
+        final AsyncResponseProducer responseProducer = responseProducerRef.get();
+        if (responseProducer == null) {
+            return exchangeHandler.consume(src);
+        } else {
+            return Integer.MAX_VALUE;
+        }
+    }
+
+    @Override
+    public final void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
+        final AsyncResponseProducer responseProducer = responseProducerRef.get();
+        if (responseProducer == null) {
+            exchangeHandler.streamEnd(trailers);
+        }
+    }
+
+    @Override
+    public final int available() {
+        final AsyncResponseProducer responseProducer = responseProducerRef.get();
+        if (responseProducer == null) {
+            return exchangeHandler.available();
+        } else {
+            return responseProducer.available();
+        }
+    }
+
+    @Override
+    public final void produce(final DataStreamChannel channel) throws IOException {
+        final AsyncResponseProducer responseProducer = responseProducerRef.get();
+        if (responseProducer == null) {
+            exchangeHandler.produce(channel);
+        } else {
+            responseProducer.produce(channel);
+        }
+    }
+
+    @Override
+    public final void failed(final Exception cause) {
+        try {
+            exchangeHandler.failed(cause);
+            final AsyncResponseProducer dataProducer = responseProducerRef.getAndSet(null);
+            if (dataProducer != null) {
+                dataProducer.failed(cause);
+            }
+        } finally {
+            releaseResources();
+        }
+    }
+
+    @Override
+    public final void releaseResources() {
+        exchangeHandler.releaseResources();
+        final AsyncResponseProducer dataProducer = responseProducerRef.getAndSet(null);
+        if (dataProducer != null) {
+            dataProducer.releaseResources();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/Authenticator.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/Authenticator.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/Authenticator.java
new file mode 100644
index 0000000..911b3c4
--- /dev/null
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/Authenticator.java
@@ -0,0 +1,38 @@
+/*
+ * ====================================================================
+ * 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.testing.auth;
+
+import org.apache.hc.core5.net.URIAuthority;
+
+public interface Authenticator {
+
+    boolean authenticate(URIAuthority authority, String requestUri, String credentials);
+
+    String getRealm(URIAuthority authority, String requestUri);
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
index a29778f..5c5abfb 100644
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
@@ -32,43 +32,30 @@ import java.nio.charset.StandardCharsets;
 import org.apache.commons.codec.BinaryDecoder;
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Base64;
-import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.ProtocolException;
 
 public class BasicAuthTokenExtractor {
 
-    public String extract(final HttpRequest request) throws HttpException {
-        String auth = null;
-
-        final Header h = request.getFirstHeader(HttpHeaders.AUTHORIZATION);
-        if (h != null) {
-            final String s = h.getValue();
-            if (s != null) {
-                auth = s.trim();
-            }
-        }
-
-        if (auth != null) {
-            final int i = auth.indexOf(' ');
+    public String extract(final String challengeResponse) throws HttpException {
+        if (challengeResponse != null) {
+            final int i = challengeResponse.indexOf(' ');
             if (i == -1) {
-                throw new ProtocolException("Invalid Authorization header: " + auth);
+                throw new ProtocolException("Invalid challenge response: " + challengeResponse);
             }
-            final String authscheme = auth.substring(0, i);
+            final String authscheme = challengeResponse.substring(0, i);
             if (authscheme.equalsIgnoreCase("basic")) {
-                final String s = auth.substring(i + 1).trim();
+                final String s = challengeResponse.substring(i + 1).trim();
                 try {
                     final byte[] credsRaw = s.getBytes(StandardCharsets.US_ASCII);
                     final BinaryDecoder codec = new Base64();
-                    auth = new String(codec.decode(credsRaw), StandardCharsets.US_ASCII);
+                    return new String(codec.decode(credsRaw), StandardCharsets.US_ASCII);
                 } catch (final DecoderException ex) {
                     throw new ProtocolException("Malformed BASIC credentials");
                 }
             }
         }
-        return auth;
+        return null;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/RequestBasicAuth.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/RequestBasicAuth.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/RequestBasicAuth.java
deleted file mode 100644
index 5832b6d..0000000
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/RequestBasicAuth.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * ====================================================================
- * 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.testing.auth;
-
-import java.io.IOException;
-
-import org.apache.hc.core5.http.EntityDetails;
-import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.HttpRequestInterceptor;
-import org.apache.hc.core5.http.protocol.HttpContext;
-
-public class RequestBasicAuth implements HttpRequestInterceptor {
-
-    private final BasicAuthTokenExtractor authTokenExtractor;
-
-    public RequestBasicAuth() {
-        super();
-        this.authTokenExtractor = new BasicAuthTokenExtractor();
-    }
-
-    @Override
-    public void process(
-            final HttpRequest request,
-            final EntityDetails entityDetails,
-            final HttpContext context) throws HttpException, IOException {
-        context.setAttribute("creds", this.authTokenExtractor.extract(request));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/ResponseBasicUnauthorized.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/ResponseBasicUnauthorized.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/ResponseBasicUnauthorized.java
deleted file mode 100644
index cce7525..0000000
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/ResponseBasicUnauthorized.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * ====================================================================
- * 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.testing.auth;
-
-import java.io.IOException;
-
-import org.apache.hc.core5.http.EntityDetails;
-import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.HttpResponseInterceptor;
-import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.protocol.HttpContext;
-
-public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
-
-    @Override
-    public void process(
-            final HttpResponse response,
-            final EntityDetails entityDetails,
-            final HttpContext context) throws HttpException, IOException {
-        if (response.getCode() == HttpStatus.SC_UNAUTHORIZED) {
-            if (!response.containsHeader(HttpHeaders.WWW_AUTHENTICATE)) {
-                response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"test realm\"");
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/AuthenticatingDecorator.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/AuthenticatingDecorator.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/AuthenticatingDecorator.java
new file mode 100644
index 0000000..ddfa52c
--- /dev/null
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/AuthenticatingDecorator.java
@@ -0,0 +1,105 @@
+/*
+ * ====================================================================
+ * 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.testing.classic;
+
+import java.io.IOException;
+
+import org.apache.hc.client5.testing.auth.Authenticator;
+import org.apache.hc.client5.testing.auth.BasicAuthTokenExtractor;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.io.HttpServerRequestHandler;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.util.Args;
+
+public class AuthenticatingDecorator implements HttpServerRequestHandler {
+
+    private final HttpServerRequestHandler requestHandler;
+    private final Authenticator authenticator;
+    private final BasicAuthTokenExtractor authTokenExtractor;
+
+    public AuthenticatingDecorator(final HttpServerRequestHandler requestHandler, final Authenticator authenticator) {
+        this.requestHandler = Args.notNull(requestHandler, "Request handler");
+        this.authenticator = Args.notNull(authenticator, "Authenticator");
+        this.authTokenExtractor = new BasicAuthTokenExtractor();
+    }
+
+    protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) {
+    }
+
+    @Override
+    public void handle(
+            final ClassicHttpRequest request,
+            final ResponseTrigger responseTrigger,
+            final HttpContext context) throws HttpException, IOException {
+        final Header h = request.getFirstHeader(HttpHeaders.AUTHORIZATION);
+        final String challengeResponse = h != null ? authTokenExtractor.extract(h.getValue()) : null;
+
+        final URIAuthority authority = request.getAuthority();
+        final String requestUri = request.getRequestUri();
+
+        final boolean authenticated = authenticator.authenticate(authority, requestUri, challengeResponse);
+        final Header expect = request.getFirstHeader(HttpHeaders.EXPECT);
+        final boolean expectContinue = expect != null && "100-continue".equalsIgnoreCase(expect.getValue());
+
+        if (authenticated) {
+            if (expectContinue) {
+                responseTrigger.sendInformation(new BasicClassicHttpResponse(HttpStatus.SC_CONTINUE));
+            }
+            requestHandler.handle(request, responseTrigger, context);
+        } else {
+            final ClassicHttpResponse unauthorized = new BasicClassicHttpResponse(HttpStatus.SC_UNAUTHORIZED);
+            final String realm = authenticator.getRealm(authority, requestUri);
+            unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"" + realm + "\"");
+            customizeUnauthorizedResponse(unauthorized);
+            if (unauthorized.getEntity() == null) {
+                unauthorized.setEntity(new StringEntity("Unauthorized"));
+            }
+            if (expectContinue || request.getEntity() == null) {
+                // Respond immediately
+                responseTrigger.submitResponse(unauthorized);
+                // Consume request body later
+                EntityUtils.consume(request.getEntity());
+            } else {
+                // Consume request body first
+                EntityUtils.consume(request.getEntity());
+                // Respond later
+                responseTrigger.submitResponse(unauthorized);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/BasicTestAuthenticator.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/BasicTestAuthenticator.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/BasicTestAuthenticator.java
new file mode 100644
index 0000000..933071e
--- /dev/null
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/BasicTestAuthenticator.java
@@ -0,0 +1,54 @@
+/*
+ * ====================================================================
+ * 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.testing;
+
+import java.util.Objects;
+
+import org.apache.hc.client5.testing.auth.Authenticator;
+import org.apache.hc.core5.net.URIAuthority;
+
+public class BasicTestAuthenticator implements Authenticator {
+
+    private final String userToken;
+    private final String realm;
+
+    public BasicTestAuthenticator(final String userToken, final String realm) {
+        this.userToken = userToken;
+        this.realm = realm;
+    }
+
+    public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
+        return Objects.equals(userToken, credentials);
+    }
+
+    @Override
+    public String getRealm(final URIAuthority authority, final String requestUri) {
+        return realm;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/IntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/IntegrationTestBase.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/IntegrationTestBase.java
index 262eb82..4ba9ce1 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/IntegrationTestBase.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/IntegrationTestBase.java
@@ -28,13 +28,16 @@
 package org.apache.hc.client5.testing.async;
 
 import java.net.InetSocketAddress;
+import java.util.concurrent.Future;
 
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
+import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.H1Config;
 import org.apache.hc.core5.http.impl.HttpProcessors;
+import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
 import org.apache.hc.core5.io.ShutdownType;
 import org.apache.hc.core5.reactor.ListenerEndpoint;
@@ -72,16 +75,25 @@ public abstract class IntegrationTestBase extends LocalAsyncServerTestBase {
 
     };
 
-    public HttpHost start(final HttpProcessor httpProcessor, final H1Config h1Config) throws Exception {
-        server.start(httpProcessor, h1Config);
-        final ListenerEndpoint listener = server.listen(new InetSocketAddress(0));
+    public HttpHost start(
+            final HttpProcessor httpProcessor,
+            final Decorator<AsyncServerExchangeHandler> exchangeHandlerDecorator,
+            final H1Config h1Config) throws Exception {
+        server.start(httpProcessor, exchangeHandlerDecorator, h1Config);
+        final Future<ListenerEndpoint> endpointFuture = server.listen(new InetSocketAddress(0));
         httpclient = clientBuilder.build();
         httpclient.start();
-        listener.waitFor();
-        final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
+        final ListenerEndpoint endpoint = endpointFuture.get();
+        final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
         return new HttpHost("localhost", address.getPort(), scheme.name());
     }
 
+    public HttpHost start(
+            final HttpProcessor httpProcessor,
+            final H1Config h1Config) throws Exception {
+        return start(httpProcessor, null, h1Config);
+    }
+
     public HttpHost start() throws Exception {
         return start(HttpProcessors.server(), H1Config.DEFAULT);
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
index 27866ba..9bfc3b2 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
@@ -763,8 +763,8 @@ public class TestAsyncRedirects extends IntegrationTestBase {
             });
 
             secondServer.start();
-            final ListenerEndpoint endpoint2 = secondServer.listen(new InetSocketAddress(0));
-            endpoint2.waitFor();
+            final Future<ListenerEndpoint> endpointFuture = secondServer.listen(new InetSocketAddress(0));
+            final ListenerEndpoint endpoint2 = endpointFuture.get();
 
             final InetSocketAddress address2 = (InetSocketAddress) endpoint2.getAddress();
             final HttpHost initialTarget = new HttpHost("localhost", address2.getPort(), scheme.name());

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
index a1d2588..44eb1be 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
@@ -26,7 +26,6 @@
  */
 package org.apache.hc.client5.testing.async;
 
-import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -52,18 +51,16 @@ import org.apache.hc.client5.http.impl.protocol.DefaultAuthenticationStrategy;
 import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.sync.methods.HttpGet;
-import org.apache.hc.client5.testing.auth.RequestBasicAuth;
-import org.apache.hc.client5.testing.auth.ResponseBasicUnauthorized;
+import org.apache.hc.client5.testing.BasicTestAuthenticator;
+import org.apache.hc.client5.testing.auth.Authenticator;
+import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.ContentType;
-import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.HeaderElements;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.HttpResponseInterceptor;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.H1Config;
@@ -71,13 +68,10 @@ import org.apache.hc.core5.http.config.Registry;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.impl.HttpProcessors;
 import org.apache.hc.core5.http.message.BasicHeader;
-import org.apache.hc.core5.http.message.BasicHttpResponse;
-import org.apache.hc.core5.http.nio.AsyncResponseProducer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
-import org.apache.hc.core5.http.nio.support.BasicAsyncResponseProducer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.apache.hc.core5.net.URIAuthority;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -100,41 +94,17 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Override
     public HttpHost start() throws Exception {
-        return super.start(HttpProcessors.customServer(null)
-                .add(new RequestBasicAuth())
-                .add(new ResponseBasicUnauthorized())
-                .build(),
-                H1Config.DEFAULT);
-    }
-
-    static class AuthHandler extends AbstractSimpleServerExchangeHandler {
-
-        private final boolean keepAlive;
-
-        AuthHandler(final boolean keepAlive) {
-            super();
-            this.keepAlive = keepAlive;
-        }
-
-        AuthHandler() {
-            this(true);
-        }
+        return super.start(
+                HttpProcessors.server(),
+                new Decorator<AsyncServerExchangeHandler>() {
 
-        @Override
-        protected SimpleHttpResponse handle(
-                final SimpleHttpRequest request,
-                final HttpCoreContext context) throws HttpException {
-            final String creds = (String) context.getAttribute("creds");
-            final SimpleHttpResponse response;
-            if (creds == null || !creds.equals("test:test")) {
-                response = new SimpleHttpResponse(HttpStatus.SC_UNAUTHORIZED);
-            } else {
-                response = new SimpleHttpResponse(HttpStatus.SC_OK, "success", ContentType.TEXT_PLAIN);
-            }
-            response.setHeader(HttpHeaders.CONNECTION, this.keepAlive ? HeaderElements.KEEP_ALIVE : HeaderElements.CLOSE);
-            return response;
-        }
+                    @Override
+                    public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler requestHandler) {
+                        return new AuthenticatingAsyncDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm"));
+                    }
 
+                },
+                H1Config.DEFAULT);
     }
 
     static class TestCredentialsProvider implements CredentialsStore {
@@ -173,7 +143,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -199,7 +169,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -226,7 +196,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -253,11 +223,27 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler(false);
+                return new AsyncEchoHandler();
             }
 
         });
-        final HttpHost target = start();
+        final HttpHost target = start(
+                HttpProcessors.server(),
+                new Decorator<AsyncServerExchangeHandler>() {
+
+                    @Override
+                    public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
+                        return new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) {
+
+                            @Override
+                            protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
+                                unauthorized.addHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE);
+                            }
+                        };
+                    }
+
+                },
+                H1Config.DEFAULT);
 
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
                 new UsernamePasswordCredentials("test", "test".toCharArray()));
@@ -280,23 +266,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler() {
-
-                    @Override
-                    protected AsyncResponseProducer verify(
-                            final HttpRequest request,
-                            final HttpContext context) throws IOException, HttpException {
-
-                        final String creds = (String) context.getAttribute("creds");
-                        if (creds == null || !creds.equals("test:test")) {
-                            return new BasicAsyncResponseProducer(new BasicHttpResponse(HttpStatus.SC_UNAUTHORIZED),
-                                    new StringAsyncEntityProducer("Unauthorized"));
-                        } else {
-                            return null;
-                        }
-                    }
-
-                };
+                return new AsyncEchoHandler();
             }
 
         });
@@ -321,23 +291,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler() {
-
-                    @Override
-                    protected AsyncResponseProducer verify(
-                            final HttpRequest request,
-                            final HttpContext context) throws IOException, HttpException {
-
-                        final String creds = (String) context.getAttribute("creds");
-                        if (creds == null || !creds.equals("test:test")) {
-                            return new BasicAsyncResponseProducer(new BasicHttpResponse(HttpStatus.SC_UNAUTHORIZED),
-                                    new StringAsyncEntityProducer("Unauthorized"));
-                        } else {
-                            return null;
-                        }
-                    }
-
-                };
+                return new AsyncEchoHandler();
             }
 
         });
@@ -365,7 +319,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -409,7 +363,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -422,7 +376,6 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
         Assert.assertNotNull(response);
         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
-        Assert.assertEquals("success", response.getBody());
     }
 
     @Test
@@ -431,7 +384,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -452,7 +405,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
@@ -482,42 +435,18 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
         Assert.assertNotNull(response);
         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
-        Assert.assertEquals("success", response.getBody());
     }
 
     @Test
     public void testReauthentication() throws Exception {
-        final AtomicLong count = new AtomicLong(0);
-
         server.register("*", new Supplier<AsyncServerExchangeHandler>() {
 
             @Override
             public AsyncServerExchangeHandler get() {
-
-                return new AbstractSimpleServerExchangeHandler() {
-
-                    @Override
-                    protected SimpleHttpResponse handle(
-                            final SimpleHttpRequest request,
-                            final HttpCoreContext context) throws HttpException {
-                        final String creds = (String) context.getAttribute("creds");
-                        if (creds == null || !creds.equals("test:test")) {
-                            return new SimpleHttpResponse(HttpStatus.SC_UNAUTHORIZED);
-                        } else {
-                            // Make client re-authenticate on each fourth request
-                            if (count.incrementAndGet() % 4 == 0) {
-                                return new SimpleHttpResponse(HttpStatus.SC_UNAUTHORIZED);
-                            } else {
-                                return new SimpleHttpResponse(HttpStatus.SC_OK, "success", ContentType.TEXT_PLAIN);
-                            }
-                        }
-                    }
-
-                };
+                return new AsyncEchoHandler();
             }
 
         });
-
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
                 new UsernamePasswordCredentials("test", "test".toCharArray()));
 
@@ -540,23 +469,43 @@ public class TestClientAuthentication extends IntegrationTestBase {
                 .build();
         this.clientBuilder.setDefaultAuthSchemeRegistry(authSchemeRegistry);
 
-        final HttpHost target = start(HttpProcessors.customServer(null)
-                        .add(new RequestBasicAuth())
-                        .add(new HttpResponseInterceptor() {
+        final Authenticator authenticator = new BasicTestAuthenticator("test:test", "test realm") {
+
+            private final AtomicLong count = new AtomicLong(0);
+
+            @Override
+            public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
+                final boolean authenticated = super.authenticate(authority, requestUri, credentials);
+                if (authenticated) {
+                    if (this.count.incrementAndGet() % 4 != 0) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            }
+        };
+
+        final HttpHost target = start(
+                HttpProcessors.server(),
+                new Decorator<AsyncServerExchangeHandler>() {
+
+                    @Override
+                    public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
+                        return new AuthenticatingAsyncDecorator(exchangeHandler, authenticator) {
 
                             @Override
-                            public void process(
-                                    final HttpResponse response,
-                                    final EntityDetails entityDetails,
-                                    final HttpContext context) throws HttpException, IOException {
-                                if (response.getCode() == HttpStatus.SC_UNAUTHORIZED) {
-                                    response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\"");
-                                }
+                            protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
+                                unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE);
+                                unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\"");
                             }
 
-                        })
-                        .build(),
-                H1Config.DEFAULT);
+                        };
+                    }
+
+                }, H1Config.DEFAULT);
 
         final RequestConfig config = RequestConfig.custom()
                 .setTargetPreferredAuthSchemes(Arrays.asList("MyBasic"))
@@ -583,31 +532,27 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
             @Override
             public AsyncServerExchangeHandler get() {
-
-                return new AuthHandler();
+                return new AsyncEchoHandler();
             }
 
         });
+        final HttpHost target = start(
+                HttpProcessors.server(),
+                new Decorator<AsyncServerExchangeHandler>() {
 
-        final HttpHost target = start(HttpProcessors.customServer(null)
-                        .add(new RequestBasicAuth())
-                        .add(new HttpResponseInterceptor() {
+                    @Override
+                    public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
+                        return new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) {
 
                             @Override
-                            public void process(
-                                    final HttpResponse response,
-                                    final EntityDetails entityDetails,
-                                    final HttpContext context) throws HttpException, IOException {
-                                if (response.getCode() == HttpStatus.SC_UNAUTHORIZED) {
-                                    response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"test realm\" invalid");
-                                    response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"test realm\"");
-                                }
+                            protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
+                                unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"test realm\" invalid");
                             }
 
-                        })
-                        .build(),
-                H1Config.DEFAULT);
+                        };
+                    }
 
+                }, H1Config.DEFAULT);
 
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
                 new UsernamePasswordCredentials("test", "test".toCharArray()));
@@ -618,7 +563,6 @@ public class TestClientAuthentication extends IntegrationTestBase {
         final SimpleHttpResponse response = future.get();
         Assert.assertNotNull(response);
         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
-        Assert.assertEquals("success", response.getBody());
         final AuthScope authscope = credsProvider.getAuthScope();
         Assert.assertNotNull(authscope);
         Assert.assertEquals("test realm", authscope.getRealm());

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
index e5275cd..5ae7fe7 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
@@ -168,10 +168,10 @@ public class TestHttpAsyncMinimal {
         } else {
             server.start(H1Config.DEFAULT);
         }
-        final ListenerEndpoint listener = server.listen(new InetSocketAddress(0));
+        final Future<ListenerEndpoint> endpointFuture = server.listen(new InetSocketAddress(0));
         httpclient.start();
-        listener.waitFor();
-        final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
+        final ListenerEndpoint endpoint = endpointFuture.get();
+        final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
         return new HttpHost("localhost", address.getPort(), scheme.name());
     }
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java
index a5e6f29..a5df79c 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java
@@ -41,8 +41,8 @@ import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
 import org.apache.hc.core5.http.io.HttpRequestHandler;
-import org.apache.hc.core5.http.io.ResponseHandler;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.http.io.entity.StringEntity;
 import org.apache.hc.core5.http.protocol.HttpContext;
@@ -52,10 +52,9 @@ import org.junit.Test;
 
 public class TestFluent extends LocalServerTestBase {
 
-    @Before @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-        this.serverBootstrap.registerHandler("/", new HttpRequestHandler() {
+        this.server.registerHandler("/", new HttpRequestHandler() {
 
             @Override
             public void handle(
@@ -66,7 +65,7 @@ public class TestFluent extends LocalServerTestBase {
             }
 
         });
-        this.serverBootstrap.registerHandler("/echo", new HttpRequestHandler() {
+        this.server.registerHandler("/echo", new HttpRequestHandler() {
 
             @Override
             public void handle(
@@ -155,7 +154,7 @@ public class TestFluent extends LocalServerTestBase {
             Request.Get(baseURL + "/").execute().returnContent();
             Request.Get(baseURL + "/").execute().returnResponse();
             Request.Get(baseURL + "/").execute().discardContent();
-            Request.Get(baseURL + "/").execute().handleResponse(new ResponseHandler<Object>() {
+            Request.Get(baseURL + "/").execute().handleResponse(new HttpClientResponseHandler<Object>() {
 
                 @Override
                 public Object handleResponse(

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/1eb22180/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
index 3f710db..85f8ab2 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/LocalServerTestBase.java
@@ -27,35 +27,31 @@
 
 package org.apache.hc.client5.testing.sync;
 
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
 import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
 import org.apache.hc.client5.http.impl.sync.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.sync.HttpClientBuilder;
 import org.apache.hc.client5.testing.SSLTestContexts;
 import org.apache.hc.client5.testing.classic.EchoHandler;
 import org.apache.hc.client5.testing.classic.RandomHandler;
+import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.SocketConfig;
-import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
-import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
+import org.apache.hc.core5.http.io.HttpServerRequestHandler;
+import org.apache.hc.core5.http.protocol.HttpProcessor;
 import org.apache.hc.core5.io.ShutdownType;
-import org.apache.hc.core5.util.TimeValue;
-import org.junit.After;
-import org.junit.Before;
+import org.apache.hc.core5.testing.classic.ClassicTestServer;
+import org.junit.Rule;
+import org.junit.rules.ExternalResource;
 
 /**
  * Base class for tests using local test server. The server will not be started per default.
  */
 public abstract class LocalServerTestBase {
 
-    protected final URIScheme scheme;
-
-    protected ServerBootstrap serverBootstrap;
-    protected HttpServer server;
-    protected PoolingHttpClientConnectionManager connManager;
-    protected HttpClientBuilder clientBuilder;
-    protected CloseableHttpClient httpclient;
-
     public LocalServerTestBase(final URIScheme scheme) {
         this.scheme = scheme;
     }
@@ -64,48 +60,81 @@ public abstract class LocalServerTestBase {
         this(URIScheme.HTTP);
     }
 
-    public String getSchemeName() {
-        return this.scheme.name();
-    }
+    protected final URIScheme scheme;
+
+    protected ClassicTestServer server;
 
-    @Before
-    public void setUp() throws Exception {
-        final SocketConfig socketConfig = SocketConfig.custom()
-                .setSoTimeout(TimeValue.ofSeconds(15))
-                .build();
-        this.serverBootstrap = ServerBootstrap.bootstrap()
-                .setSocketConfig(socketConfig)
-                .registerHandler("/echo/*", new EchoHandler())
-                .registerHandler("/random/*", new RandomHandler());
-        if (this.scheme.equals(URIScheme.HTTPS)) {
-            this.serverBootstrap.setSslContext(SSLTestContexts.createServerSSLContext());
+    @Rule
+    public ExternalResource serverResource = new ExternalResource() {
+
+        @Override
+        protected void before() throws Throwable {
+            server = new ClassicTestServer(
+                    scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null,
+                    SocketConfig.custom()
+                            .setSoTimeout(5, TimeUnit.SECONDS)
+                            .build());
+            server.registerHandler("/echo/*", new EchoHandler());
+            server.registerHandler("/random/*", new RandomHandler());
         }
 
-        this.connManager = new PoolingHttpClientConnectionManager();
-        this.connManager.setDefaultSocketConfig(socketConfig);
-        this.clientBuilder = HttpClientBuilder.create()
-                .setConnectionManager(this.connManager);
-    }
+        @Override
+        protected void after() {
+            if (server != null) {
+                try {
+                    server.shutdown(ShutdownType.IMMEDIATE);
+                    server = null;
+                } catch (final Exception ignore) {
+                }
+            }
+        }
 
-    @After
-    public void shutDown() throws Exception {
-        if (this.httpclient != null) {
-            this.httpclient.close();
+    };
+
+    protected PoolingHttpClientConnectionManager connManager;
+    protected HttpClientBuilder clientBuilder;
+    protected CloseableHttpClient httpclient;
+
+    @Rule
+    public ExternalResource clientResource = new ExternalResource() {
+
+        @Override
+        protected void before() throws Throwable {
+            connManager = new PoolingHttpClientConnectionManager();
+            connManager.setDefaultSocketConfig(SocketConfig.custom()
+                    .setSoTimeout(5, TimeUnit.SECONDS)
+                    .build());
+            clientBuilder = HttpClientBuilder.create()
+                    .setConnectionManager(connManager);
         }
-        if (this.server != null) {
-            this.server.shutdown(ShutdownType.IMMEDIATE);
+
+        @Override
+        protected void after() {
+            if (httpclient != null) {
+                try {
+                    httpclient.close();
+                    httpclient = null;
+                } catch (final Exception ignore) {
+                }
+            }
         }
-    }
 
-    public HttpHost start() throws Exception {
-        this.server = this.serverBootstrap.create();
-        this.server.start();
+    };
+
+    public HttpHost start(
+            final HttpProcessor httpProcessor,
+            final Decorator<HttpServerRequestHandler> handlerDecorator) throws IOException {
+        this.server.start(httpProcessor, handlerDecorator);
 
         if (this.httpclient == null) {
             this.httpclient = this.clientBuilder.build();
         }
 
-        return new HttpHost("localhost", this.server.getLocalPort(), this.scheme.name());
+        return new HttpHost("localhost", this.server.getPort(), this.scheme.name());
+    }
+
+    public HttpHost start() throws Exception {
+        return start(null, null);
     }
 
 }