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 2019/05/31 17:51:08 UTC

[httpcomponents-core] 05/06: Classic and async message builders

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch message-support
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit fe6d9ca66debd3a66d1b96990417eb23f3413d9e
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Fri May 31 14:34:01 2019 +0200

    Classic and async message builders
---
 .../Http2ConscriptRequestExecutionExample.java     |   4 +-
 .../http2/examples/Http2FileServerExample.java     |  33 +-
 .../examples/Http2FullDuplexClientExample.java     |  12 +-
 .../examples/Http2MultiStreamExecutionExample.java |   4 +-
 .../examples/Http2RequestExecutionExample.java     |   4 +-
 .../Http2TlsAlpnRequestExecutionExample.java       |   4 +-
 .../examples/ReactiveFullDuplexClientExample.java  |  13 +-
 .../hc/core5/benchmark/BenchmarkToolTest.java      |  10 +-
 .../http2/Http2CompatibilityTest.java              |   4 +-
 .../core5/testing/nio/Http1AuthenticationTest.java |   4 +-
 .../hc/core5/testing/nio/Http1IntegrationTest.java |   8 +-
 .../testing/nio/Http1ServerAndRequesterTest.java   |   4 +-
 .../apache/hc/core5/testing/nio/Http2AlpnTest.java |   4 +-
 .../hc/core5/testing/nio/Http2IntegrationTest.java |  20 +-
 .../testing/nio/Http2ProtocolNegotiationTest.java  |   4 +-
 .../Http2ServerAndMultiplexingRequesterTest.java   |   4 +-
 .../testing/nio/Http2ServerAndRequesterTest.java   |   4 +-
 .../core5/testing/nio/MessageExchangeHandler.java  |   2 +-
 .../testing/nio/MultiLineResponseHandler.java      |  15 +-
 .../testing/nio/SingleLineResponseHandler.java     |  12 +-
 .../core5/testing/reactive/ReactiveClientTest.java |   2 +-
 .../hc/core5/http/impl/nio/ServerSupport.java      |   2 +-
 .../http/io/support/ClassicRequestBuilder.java     | 419 ++++++++++++++++++++
 .../http/io/support/ClassicResponseBuilder.java    | 203 ++++++++++
 .../nio/support/AbstractServerExchangeHandler.java |   6 +-
 .../core5/http/nio/support/AsyncPushBuilder.java   | 187 +++++++++
 .../http/nio/support/AsyncRequestBuilder.java      | 424 +++++++++++++++++++++
 .../http/nio/support/AsyncResponseBuilder.java     | 203 ++++++++++
 ...yncServerFilterChainExchangeHandlerFactory.java |   1 -
 .../http/nio/{ => support}/BasicPushProducer.java  |   6 +-
 .../nio/{ => support}/BasicRequestConsumer.java    |   5 +-
 .../nio/{ => support}/BasicRequestProducer.java    |   6 +-
 .../nio/{ => support}/BasicResponseConsumer.java   |   5 +-
 .../nio/{ => support}/BasicResponseProducer.java   |   6 +-
 .../support/ImmediateResponseExchangeHandler.java  |   1 -
 .../http/examples/AsyncFileServerExample.java      |  34 +-
 .../examples/AsyncFullDuplexClientExample.java     |  12 +-
 .../AsyncPipelinedRequestExecutionExample.java     |   4 +-
 .../examples/AsyncRequestExecutionExample.java     |   4 +-
 .../http/examples/AsyncServerFilterExample.java    |   8 +-
 .../http/examples/ClassicPostExecutionExample.java |   2 +-
 41 files changed, 1589 insertions(+), 120 deletions(-)

diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2ConscriptRequestExecutionExample.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2ConscriptRequestExecutionExample.java
index 05bf3c4..fa2a825 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2ConscriptRequestExecutionExample.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2ConscriptRequestExecutionExample.java
@@ -41,9 +41,9 @@ import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.http2.frame.RawFrame;
 import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FileServerExample.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FileServerExample.java
index 7d1929e..c829b83 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FileServerExample.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FileServerExample.java
@@ -49,10 +49,10 @@ import org.apache.hc.core5.http.ProtocolException;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
-import org.apache.hc.core5.http.nio.entity.FileEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
@@ -149,19 +149,21 @@ public class Http2FileServerExample {
                         if (!file.exists()) {
 
                             System.out.println("File " + file.getPath() + " not found");
-                            responseTrigger.submitResponse(new BasicResponseProducer(
-                                    HttpStatus.SC_NOT_FOUND,
-                                    "<html><body><h1>File" + file.getPath() +
-                                            " not found</h1></body></html>",
-                                    ContentType.TEXT_HTML), context);
+                            responseTrigger.submitResponse(
+                                    AsyncResponseBuilder.create(HttpStatus.SC_NOT_FOUND)
+                                            .setEntity("<html><body><h1>File" + file.getPath() +
+                                                    " not found</h1></body></html>", ContentType.TEXT_HTML)
+                                            .build(),
+                                    context);
 
                         } else if (!file.canRead() || file.isDirectory()) {
 
                             System.out.println("Cannot read file " + file.getPath());
-                            responseTrigger.submitResponse(new BasicResponseProducer(
-                                    HttpStatus.SC_FORBIDDEN,
-                                    "<html><body><h1>Access denied</h1></body></html>",
-                                    ContentType.TEXT_HTML), context);
+                            responseTrigger.submitResponse(
+                                    AsyncResponseBuilder.create(HttpStatus.SC_FORBIDDEN)
+                                            .setEntity("<html><body><h1>Access denied</h1></body></html>", ContentType.TEXT_HTML)
+                                            .build(),
+                                    context);
 
                         } else {
 
@@ -180,8 +182,11 @@ public class Http2FileServerExample {
                             final HttpCoreContext coreContext = HttpCoreContext.adapt(context);
                             final EndpointDetails endpoint = coreContext.getEndpointDetails();
                             System.out.println(endpoint + ": serving file " + file.getPath());
-                            responseTrigger.submitResponse(new BasicResponseProducer(
-                                    HttpStatus.SC_OK, new FileEntityProducer(file, contentType)), context);
+                            responseTrigger.submitResponse(
+                                    AsyncResponseBuilder.create(HttpStatus.SC_OK)
+                                            .setEntity(AsyncEntityProducers.create(file, contentType))
+                                            .build(),
+                                    context);
                         }
                     }
 
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FullDuplexClientExample.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FullDuplexClientExample.java
index fcf2ce1..31c79c5 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FullDuplexClientExample.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2FullDuplexClientExample.java
@@ -38,16 +38,15 @@ import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpConnection;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.AsyncRequestProducer;
 import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.RequestChannel;
-import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
@@ -124,8 +123,9 @@ public class Http2FullDuplexClientExample {
         requester.start();
 
         final URI requestUri = new URI("http://nghttp2.org/httpbin/post");
-        final BasicRequestProducer requestProducer = new BasicRequestProducer(
-                Methods.POST.name(), requestUri, AsyncEntityProducers.create("stuff"));
+        final AsyncRequestProducer requestProducer = AsyncRequestBuilder.post(requestUri)
+                .setEntity("stuff")
+                .build();
         final BasicResponseConsumer<String> responseConsumer = new BasicResponseConsumer<>(
                 new StringAsyncEntityConsumer());
 
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2MultiStreamExecutionExample.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2MultiStreamExecutionExample.java
index 1dce851..aa2f101 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2MultiStreamExecutionExample.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2MultiStreamExecutionExample.java
@@ -40,9 +40,9 @@ import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.http2.frame.RawFrame;
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2RequestExecutionExample.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2RequestExecutionExample.java
index 725f629..222c25a 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2RequestExecutionExample.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2RequestExecutionExample.java
@@ -39,9 +39,9 @@ import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.http2.frame.RawFrame;
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2TlsAlpnRequestExecutionExample.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2TlsAlpnRequestExecutionExample.java
index bf9e7c5..0a254b1 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2TlsAlpnRequestExecutionExample.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/examples/Http2TlsAlpnRequestExecutionExample.java
@@ -42,9 +42,9 @@ import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.http2.frame.RawFrame;
 import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
diff --git a/httpcore5-reactive/src/test/java/org/apache/hc/core5/reactive/examples/ReactiveFullDuplexClientExample.java b/httpcore5-reactive/src/test/java/org/apache/hc/core5/reactive/examples/ReactiveFullDuplexClientExample.java
index 1d79201..d632ba7 100644
--- a/httpcore5-reactive/src/test/java/org/apache/hc/core5/reactive/examples/ReactiveFullDuplexClientExample.java
+++ b/httpcore5-reactive/src/test/java/org/apache/hc/core5/reactive/examples/ReactiveFullDuplexClientExample.java
@@ -40,14 +40,13 @@ import org.apache.hc.core5.http.HttpConnection;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.Message;
-import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.impl.bootstrap.AsyncRequesterBootstrap;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.http.message.StatusLine;
-import org.apache.hc.core5.http.nio.AsyncEntityProducer;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.AsyncRequestProducer;
+import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactive.ReactiveEntityProducer;
 import org.apache.hc.core5.reactive.ReactiveResponseConsumer;
@@ -119,11 +118,9 @@ public class ReactiveFullDuplexClientExample {
                     return ByteBuffer.wrap(str.getBytes(UTF_8));
                 }
             });
-        final AsyncEntityProducer reactiveEntityProducer = new ReactiveEntityProducer(publisher, -1,
-            ContentType.TEXT_PLAIN, null);
-        final URI requestUri = new URI(endpoint);
-        final BasicRequestProducer requestProducer = new BasicRequestProducer(
-            Methods.POST.name(), requestUri, reactiveEntityProducer);
+        final AsyncRequestProducer requestProducer = AsyncRequestBuilder.post(new URI(endpoint))
+                .setEntity(new ReactiveEntityProducer(publisher, -1, ContentType.TEXT_PLAIN, null))
+                .build();
 
         final ReactiveResponseConsumer consumer = new ReactiveResponseConsumer();
         final Future<Void> responseComplete = requester.execute(requestProducer, consumer, Timeout.ofSeconds(30), null);
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/BenchmarkToolTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/BenchmarkToolTest.java
index eb618e6..185cfff 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/BenchmarkToolTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/BenchmarkToolTest.java
@@ -32,7 +32,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.concurrent.Future;
 
-import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
@@ -44,9 +43,9 @@ import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.impl.nio.bootstrap.H2ServerBootstrap;
@@ -98,7 +97,10 @@ public class BenchmarkToolTest {
                             final ResponseTrigger responseTrigger,
                             final HttpContext context) throws HttpException, IOException {
                         responseTrigger.submitResponse(
-                                new BasicResponseProducer(HttpStatus.SC_OK, "0123456789ABCDEF", ContentType.TEXT_PLAIN), context);
+                                AsyncResponseBuilder.create(HttpStatus.SC_OK)
+                                        .setEntity("0123456789ABCDEF")
+                                        .build(),
+                                context);
                     }
 
                 })
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/Http2CompatibilityTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/Http2CompatibilityTest.java
index de3051e..8c8dd47 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/Http2CompatibilityTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/compatibility/http2/Http2CompatibilityTest.java
@@ -50,11 +50,11 @@ import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractAsyncPushHandler;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.testing.nio.ClientSessionEndpoint;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java
index 61d9dfe..741b795 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java
@@ -53,8 +53,8 @@ import org.apache.hc.core5.http.impl.bootstrap.StandardFilters;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractAsyncServerAuthFilter;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
index c633ded..1d5f613 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
@@ -94,10 +94,10 @@ import org.apache.hc.core5.http.nio.AsyncRequestProducer;
 import org.apache.hc.core5.http.nio.AsyncResponseProducer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.nio.ContentEncoder;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
index cd6ce76..5a15180 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
@@ -61,8 +61,8 @@ import org.apache.hc.core5.http.nio.AsyncFilterChain;
 import org.apache.hc.core5.http.nio.AsyncFilterHandler;
 import org.apache.hc.core5.http.nio.AsyncPushProducer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 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.ssl.BasicClientTlsStrategy;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2AlpnTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2AlpnTest.java
index 660eda0..fbea0f3 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2AlpnTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2AlpnTest.java
@@ -43,8 +43,8 @@ import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 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.ssl.BasicServerTlsStrategy;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2IntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2IntegrationTest.java
index 0403259..df1aee9 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2IntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2IntegrationTest.java
@@ -85,11 +85,12 @@ import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncResponseProducer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicPushProducer;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicPushProducer;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.HandlerFactory;
@@ -591,10 +592,11 @@ public class Http2IntegrationTest extends InternalHttp2ServerTestBase {
                             final HttpContext context) throws IOException, HttpException {
                         responseTrigger.pushPromise(
                                 new BasicHttpRequest(Methods.GET, createRequestURI(serverEndpoint, "/stuff")),
-                                context, new BasicPushProducer(new MultiLineEntityProducer("Pushing lots of stuff", 500)));
-                        responseTrigger.submitResponse(new BasicResponseProducer(
-                                HttpStatus.SC_OK,
-                                AsyncEntityProducers.create("Hi there")), context);
+                                context,
+                                new BasicPushProducer(new MultiLineEntityProducer("Pushing lots of stuff", 500)));
+                        responseTrigger.submitResponse(
+                                AsyncResponseBuilder.create(HttpStatus.SC_OK).setEntity("Hi there", ContentType.TEXT_PLAIN).build(),
+                                context);
                     }
                 };
             }
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ProtocolNegotiationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ProtocolNegotiationTest.java
index 0ac28f6..2391cb4 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ProtocolNegotiationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ProtocolNegotiationTest.java
@@ -43,8 +43,8 @@ import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndMultiplexingRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndMultiplexingRequesterTest.java
index c1c19b4..e547878 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndMultiplexingRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndMultiplexingRequesterTest.java
@@ -48,8 +48,8 @@ import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 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.BasicClientExchangeHandler;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndRequesterTest.java
index a35a4e8..9bcd1b6 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ServerAndRequesterTest.java
@@ -47,8 +47,8 @@ import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.http.protocol.UriPatternMatcher;
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MessageExchangeHandler.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MessageExchangeHandler.java
index 8031412..ae7a823 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MessageExchangeHandler.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MessageExchangeHandler.java
@@ -33,7 +33,7 @@ import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineResponseHandler.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineResponseHandler.java
index f3767a7..8a59f56 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineResponseHandler.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineResponseHandler.java
@@ -31,15 +31,13 @@ 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.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.Message;
-import org.apache.hc.core5.http.message.BasicHttpResponse;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
@@ -61,10 +59,11 @@ public class MultiLineResponseHandler extends BasicServerExchangeHandler<Message
                           final Message<HttpRequest, String> requestMessage,
                           final ResponseTrigger responseTrigger,
                           final HttpContext context) throws HttpException, IOException {
-                      final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
-                      responseTrigger.submitResponse(new BasicResponseProducer(
-                              response,
-                              new MultiLineEntityProducer(message, count)), context);
+                      responseTrigger.submitResponse(
+                              AsyncResponseBuilder.create(HttpStatus.SC_OK)
+                                      .setEntity(new MultiLineEntityProducer(message, count))
+                                      .build(),
+                              context);
                   }
               }
         );
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/SingleLineResponseHandler.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/SingleLineResponseHandler.java
index 5282a3a..dd4d6ee 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/SingleLineResponseHandler.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/SingleLineResponseHandler.java
@@ -35,10 +35,9 @@ import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
-import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
@@ -60,8 +59,11 @@ public class SingleLineResponseHandler extends BasicServerExchangeHandler<Messag
                           final Message<HttpRequest, String> requestMessage,
                           final ResponseTrigger responseTrigger,
                           final HttpContext context) throws HttpException, IOException {
-                      responseTrigger.submitResponse(new BasicResponseProducer(
-                              HttpStatus.SC_OK, AsyncEntityProducers.create(message)), context);
+                      responseTrigger.submitResponse(
+                              AsyncResponseBuilder.create(HttpStatus.SC_OK)
+                                      .setEntity(message)
+                                      .build(),
+                              context);
                   }
               }
         );
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/reactive/ReactiveClientTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/reactive/ReactiveClientTest.java
index 37c6bdc..9128648 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/reactive/ReactiveClientTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/reactive/ReactiveClientTest.java
@@ -67,7 +67,7 @@ import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
 import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerSupport.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerSupport.java
index c6d0c56..db20285 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerSupport.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerSupport.java
@@ -36,7 +36,7 @@ import org.apache.hc.core5.http.NotImplementedException;
 import org.apache.hc.core5.http.ProtocolException;
 import org.apache.hc.core5.http.UnsupportedHttpVersionException;
 import org.apache.hc.core5.http.nio.AsyncResponseProducer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseProducer;
 
 /**
  * HTTP Server support methods.
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
new file mode 100644
index 0000000..3a185be
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
@@ -0,0 +1,419 @@
+/*
+ * ====================================================================
+ * 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.core5.http.io.support;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.Methods;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
+import org.apache.hc.core5.http.io.entity.HttpEntities;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.BasicNameValuePair;
+import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.net.URIBuilder;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Builder for {@link ClassicHttpRequest} instances.
+ * <p>
+ * Please note that this class treats parameters differently depending on composition
+ * of the request: if the request has a content entity explicitly set with
+ * {@link #setEntity(HttpEntity)} or it is not an entity enclosing method
+ * (such as POST or PUT), parameters will be added to the query component
+ * of the request URI. Otherwise, parameters will be added as a URL encoded entity.
+ * </p>
+ *
+ * @since 5.0
+ */
+public class ClassicRequestBuilder {
+
+    private String method;
+    private URI uri;
+    private Charset charset;
+    private ProtocolVersion version;
+    private HeaderGroup headerGroup;
+    private HttpEntity entity;
+    private List<NameValuePair> parameters;
+
+    ClassicRequestBuilder() {
+    }
+
+    ClassicRequestBuilder(final String method) {
+        super();
+        this.method = method;
+    }
+
+    ClassicRequestBuilder(final Methods method) {
+        this(method.name());
+    }
+
+    ClassicRequestBuilder(final String method, final URI uri) {
+        super();
+        this.method = method;
+        this.uri = uri;
+    }
+
+    ClassicRequestBuilder(final Methods method, final URI uri) {
+        this(method.name(), uri);
+    }
+
+    ClassicRequestBuilder(final Methods method, final String uri) {
+        this(method.name(), uri != null ? URI.create(uri) : null);
+    }
+
+    ClassicRequestBuilder(final String method, final String uri) {
+        this(method, uri != null ? URI.create(uri) : null);
+    }
+
+    public static ClassicRequestBuilder create(final String method) {
+        Args.notBlank(method, "HTTP method");
+        return new ClassicRequestBuilder(method);
+    }
+
+    public static ClassicRequestBuilder get() {
+        return new ClassicRequestBuilder(Methods.GET);
+    }
+
+    public static ClassicRequestBuilder get(final URI uri) {
+        return new ClassicRequestBuilder(Methods.GET, uri);
+    }
+
+    public static ClassicRequestBuilder get(final String uri) {
+        return new ClassicRequestBuilder(Methods.GET, uri);
+    }
+
+    public static ClassicRequestBuilder head() {
+        return new ClassicRequestBuilder(Methods.HEAD);
+    }
+
+    public static ClassicRequestBuilder head(final URI uri) {
+        return new ClassicRequestBuilder(Methods.HEAD, uri);
+    }
+
+    public static ClassicRequestBuilder head(final String uri) {
+        return new ClassicRequestBuilder(Methods.HEAD, uri);
+    }
+
+    public static ClassicRequestBuilder patch() {
+        return new ClassicRequestBuilder(Methods.PATCH);
+    }
+
+    public static ClassicRequestBuilder patch(final URI uri) {
+        return new ClassicRequestBuilder(Methods.PATCH, uri);
+    }
+
+    public static ClassicRequestBuilder patch(final String uri) {
+        return new ClassicRequestBuilder(Methods.PATCH, uri);
+    }
+
+    public static ClassicRequestBuilder post() {
+        return new ClassicRequestBuilder(Methods.POST);
+    }
+
+    public static ClassicRequestBuilder post(final URI uri) {
+        return new ClassicRequestBuilder(Methods.POST, uri);
+    }
+
+    public static ClassicRequestBuilder post(final String uri) {
+        return new ClassicRequestBuilder(Methods.POST, uri);
+    }
+
+    public static ClassicRequestBuilder put() {
+        return new ClassicRequestBuilder(Methods.PUT);
+    }
+
+    public static ClassicRequestBuilder put(final URI uri) {
+        return new ClassicRequestBuilder(Methods.PUT, uri);
+    }
+
+    public static ClassicRequestBuilder put(final String uri) {
+        return new ClassicRequestBuilder(Methods.PUT, uri);
+    }
+
+    public static ClassicRequestBuilder delete() {
+        return new ClassicRequestBuilder(Methods.DELETE);
+    }
+
+    public static ClassicRequestBuilder delete(final URI uri) {
+        return new ClassicRequestBuilder(Methods.DELETE, uri);
+    }
+
+    public static ClassicRequestBuilder delete(final String uri) {
+        return new ClassicRequestBuilder(Methods.DELETE, uri);
+    }
+
+    public static ClassicRequestBuilder trace() {
+        return new ClassicRequestBuilder(Methods.TRACE);
+    }
+
+    public static ClassicRequestBuilder trace(final URI uri) {
+        return new ClassicRequestBuilder(Methods.TRACE, uri);
+    }
+
+    public static ClassicRequestBuilder trace(final String uri) {
+        return new ClassicRequestBuilder(Methods.TRACE, uri);
+    }
+
+    public static ClassicRequestBuilder options() {
+        return new ClassicRequestBuilder(Methods.OPTIONS);
+    }
+
+    public static ClassicRequestBuilder options(final URI uri) {
+        return new ClassicRequestBuilder(Methods.OPTIONS, uri);
+    }
+
+    public static ClassicRequestBuilder options(final String uri) {
+        return new ClassicRequestBuilder(Methods.OPTIONS, uri);
+    }
+
+    public ClassicRequestBuilder setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    public Charset getCharset() {
+        return charset;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public ProtocolVersion getVersion() {
+        return version;
+    }
+
+    public ClassicRequestBuilder setVersion(final ProtocolVersion version) {
+        this.version = version;
+        return this;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    public ClassicRequestBuilder setUri(final URI uri) {
+        this.uri = uri;
+        return this;
+    }
+
+    public ClassicRequestBuilder setUri(final String uri) {
+        this.uri = uri != null ? URI.create(uri) : null;
+        return this;
+    }
+
+    public Header[] getHeaders(final String name) {
+        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    }
+
+    public ClassicRequestBuilder setHeaders(final Header... headers) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeaders(headers);
+        return this;
+    }
+
+    public Header getFirstHeader(final String name) {
+        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
+    }
+
+    public Header getLastHeader(final String name) {
+        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
+    }
+
+    public ClassicRequestBuilder addHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(header);
+        return this;
+    }
+
+    public ClassicRequestBuilder addHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.addHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public ClassicRequestBuilder removeHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.removeHeader(header);
+        return this;
+    }
+
+    public ClassicRequestBuilder removeHeaders(final String name) {
+        if (name == null || headerGroup == null) {
+            return this;
+        }
+        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
+            final Header header = i.next();
+            if (name.equalsIgnoreCase(header.getName())) {
+                i.remove();
+            }
+        }
+        return this;
+    }
+
+    public ClassicRequestBuilder setHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(header);
+        return this;
+    }
+
+    public ClassicRequestBuilder setHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public HttpEntity getEntity() {
+        return entity;
+    }
+
+    public ClassicRequestBuilder setEntity(final HttpEntity entity) {
+        this.entity = entity;
+        return this;
+    }
+
+    public ClassicRequestBuilder setEntity(final String content, final ContentType contentType) {
+        this.entity = new StringEntity(content, contentType);
+        return this;
+    }
+
+    public ClassicRequestBuilder setEntity(final String content) {
+        this.entity = new StringEntity(content);
+        return this;
+    }
+
+    public ClassicRequestBuilder setEntity(final byte[] content, final ContentType contentType) {
+        this.entity = new ByteArrayEntity(content, contentType);
+        return this;
+    }
+
+    public List<NameValuePair> getParameters() {
+        return parameters != null ? new ArrayList<>(parameters) :
+                new ArrayList<NameValuePair>();
+    }
+
+    public ClassicRequestBuilder addParameter(final NameValuePair nvp) {
+        Args.notNull(nvp, "Name value pair");
+        if (parameters == null) {
+            parameters = new LinkedList<>();
+        }
+        parameters.add(nvp);
+        return this;
+    }
+
+    public ClassicRequestBuilder addParameter(final String name, final String value) {
+        return addParameter(new BasicNameValuePair(name, value));
+    }
+
+    public ClassicRequestBuilder addParameters(final NameValuePair... nvps) {
+        for (final NameValuePair nvp : nvps) {
+            addParameter(nvp);
+        }
+        return this;
+    }
+
+    public ClassicHttpRequest build() {
+        URI uriCopy = this.uri != null ? this.uri : URI.create("/");
+        HttpEntity entityCopy = this.entity;
+        if (parameters != null && !parameters.isEmpty()) {
+            if (entityCopy == null && (Methods.POST.isSame(method) || Methods.PUT.isSame(method))) {
+                entityCopy = HttpEntities.createUrlEncoded(parameters, charset);
+            } else {
+                try {
+                    uriCopy = new URIBuilder(uriCopy)
+                            .setCharset(this.charset)
+                            .addParameters(parameters)
+                            .build();
+                } catch (final URISyntaxException ex) {
+                    // should never happen
+                }
+            }
+        }
+
+        if (entityCopy != null && Methods.TRACE.isSame(method)) {
+            throw new IllegalStateException(Methods.TRACE + " requests may not include an entity");
+        }
+
+        final ClassicHttpRequest result = new BasicClassicHttpRequest(method, uriCopy);
+        result.setVersion(this.version != null ? this.version : HttpVersion.HTTP_1_1);
+        if (this.headerGroup != null) {
+            result.setHeaders(this.headerGroup.getHeaders());
+        }
+        result.setEntity(entityCopy);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("ClassicRequestBuilder [method=");
+        builder.append(method);
+        builder.append(", charset=");
+        builder.append(charset);
+        builder.append(", version=");
+        builder.append(version);
+        builder.append(", uri=");
+        builder.append(uri);
+        builder.append(", headerGroup=");
+        builder.append(headerGroup);
+        builder.append(", entity=");
+        builder.append(entity != null ? entity.getClass() : null);
+        builder.append(", parameters=");
+        builder.append(parameters);
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
new file mode 100644
index 0000000..c8b583d
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
@@ -0,0 +1,203 @@
+/*
+ * ====================================================================
+ * 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.core5.http.io.support;
+
+import java.util.Iterator;
+
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Builder for {@link ClassicHttpResponse} instances.
+ *
+ * @since 5.0
+ */
+public class ClassicResponseBuilder {
+
+    private int status;
+    private ProtocolVersion version;
+    private HeaderGroup headerGroup;
+    private HttpEntity entity;
+
+    ClassicResponseBuilder() {
+    }
+
+    ClassicResponseBuilder(final int status) {
+        super();
+        this.status = status;
+    }
+
+    public static ClassicResponseBuilder create(final int status) {
+        Args.checkRange(status, 100, 599, "HTTP status code");
+        return new ClassicResponseBuilder(status);
+    }
+
+    public ProtocolVersion getVersion() {
+        return version;
+    }
+
+    public ClassicResponseBuilder setVersion(final ProtocolVersion version) {
+        this.version = version;
+        return this;
+    }
+
+    public Header[] getHeaders(final String name) {
+        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    }
+
+    public ClassicResponseBuilder setHeaders(final Header... headers) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeaders(headers);
+        return this;
+    }
+
+    public Header getFirstHeader(final String name) {
+        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
+    }
+
+    public Header getLastHeader(final String name) {
+        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
+    }
+
+    public ClassicResponseBuilder addHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(header);
+        return this;
+    }
+
+    public ClassicResponseBuilder addHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.addHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public ClassicResponseBuilder removeHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.removeHeader(header);
+        return this;
+    }
+
+    public ClassicResponseBuilder removeHeaders(final String name) {
+        if (name == null || headerGroup == null) {
+            return this;
+        }
+        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
+            final Header header = i.next();
+            if (name.equalsIgnoreCase(header.getName())) {
+                i.remove();
+            }
+        }
+        return this;
+    }
+
+    public ClassicResponseBuilder setHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(header);
+        return this;
+    }
+
+    public ClassicResponseBuilder setHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public HttpEntity getEntity() {
+        return entity;
+    }
+
+    public ClassicResponseBuilder setEntity(final HttpEntity entity) {
+        this.entity = entity;
+        return this;
+    }
+
+    public ClassicResponseBuilder setEntity(final String content, final ContentType contentType) {
+        this.entity = new StringEntity(content, contentType);
+        return this;
+    }
+
+    public ClassicResponseBuilder setEntity(final String content) {
+        this.entity = new StringEntity(content);
+        return this;
+    }
+
+    public ClassicResponseBuilder setEntity(final byte[] content, final ContentType contentType) {
+        this.entity = new ByteArrayEntity(content, contentType);
+        return this;
+    }
+
+    public ClassicHttpResponse build() {
+        final ClassicHttpResponse result = new BasicClassicHttpResponse(status);
+        result.setVersion(this.version != null ? this.version : HttpVersion.HTTP_1_1);
+        if (this.headerGroup != null) {
+            result.setHeaders(this.headerGroup.getHeaders());
+        }
+        result.setEntity(entity);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("ClassicResponseBuilder [method=");
+        builder.append(status);
+        builder.append(", status=");
+        builder.append(status);
+        builder.append(", version=");
+        builder.append(version);
+        builder.append(", headerGroup=");
+        builder.append(headerGroup);
+        builder.append(", entity=");
+        builder.append(entity != null ? entity.getClass() : null);
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java
index db1de9f..160182e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java
@@ -43,7 +43,6 @@ import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncResponseProducer;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-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;
@@ -140,7 +139,10 @@ public abstract class AbstractServerExchangeHandler<T> implements AsyncServerExc
                 } catch (final HttpException ex) {
                     try {
                         responseTrigger.submitResponse(
-                                new BasicResponseProducer(HttpStatus.SC_INTERNAL_SERVER_ERROR, ex.getMessage()), context);
+                                AsyncResponseBuilder.create(HttpStatus.SC_INTERNAL_SERVER_ERROR)
+                                        .setEntity(ex.getMessage())
+                                        .build(),
+                                context);
                     } catch (final HttpException | IOException ex2) {
                         failed(ex2);
                     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
new file mode 100644
index 0000000..66af20a
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
@@ -0,0 +1,187 @@
+/*
+ * ====================================================================
+ * 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.core5.http.nio.support;
+
+import java.util.Iterator;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
+import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.AsyncPushProducer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Builder for {@link AsyncPushProducer} instances.
+ *
+ * @since 5.0
+ */
+public class AsyncPushBuilder {
+
+    private int status;
+    private HeaderGroup headerGroup;
+    private AsyncEntityProducer entityProducer;
+
+    AsyncPushBuilder() {
+    }
+
+    AsyncPushBuilder(final int status) {
+        super();
+        this.status = status;
+    }
+
+    public static AsyncPushBuilder create(final int status) {
+        Args.checkRange(status, 100, 599, "HTTP status code");
+        return new AsyncPushBuilder(status);
+    }
+
+    public Header[] getHeaders(final String name) {
+        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    }
+
+    public AsyncPushBuilder setHeaders(final Header... headers) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeaders(headers);
+        return this;
+    }
+
+    public Header getFirstHeader(final String name) {
+        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
+    }
+
+    public Header getLastHeader(final String name) {
+        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
+    }
+
+    public AsyncPushBuilder addHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(header);
+        return this;
+    }
+
+    public AsyncPushBuilder addHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.addHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public AsyncPushBuilder removeHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.removeHeader(header);
+        return this;
+    }
+
+    public AsyncPushBuilder removeHeaders(final String name) {
+        if (name == null || headerGroup == null) {
+            return this;
+        }
+        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
+            final Header header = i.next();
+            if (name.equalsIgnoreCase(header.getName())) {
+                i.remove();
+            }
+        }
+        return this;
+    }
+
+    public AsyncPushBuilder setHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(header);
+        return this;
+    }
+
+    public AsyncPushBuilder setHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public AsyncEntityProducer getEntity() {
+        return entityProducer;
+    }
+
+    public AsyncPushBuilder setEntity(final AsyncEntityProducer entityProducer) {
+        this.entityProducer = entityProducer;
+        return this;
+    }
+
+    public AsyncPushBuilder setEntity(final String content, final ContentType contentType) {
+        this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
+        return this;
+    }
+
+    public AsyncPushBuilder setEntity(final String content) {
+        this.entityProducer = new BasicAsyncEntityProducer(content);
+        return this;
+    }
+
+    public AsyncPushBuilder setEntity(final byte[] content, final ContentType contentType) {
+        this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
+        return this;
+    }
+
+    public AsyncPushProducer build() {
+        final HttpResponse response = new BasicHttpResponse(status);
+        if (this.headerGroup != null) {
+            response.setHeaders(this.headerGroup.getHeaders());
+        }
+        return new BasicPushProducer(response, entityProducer);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("AsyncPushProducer [method=");
+        builder.append(status);
+        builder.append(", status=");
+        builder.append(status);
+        builder.append(", headerGroup=");
+        builder.append(headerGroup);
+        builder.append(", entity=");
+        builder.append(entityProducer != null ? entityProducer.getClass() : null);
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
new file mode 100644
index 0000000..b5d59b6
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
@@ -0,0 +1,424 @@
+/*
+ * ====================================================================
+ * 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.core5.http.nio.support;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.Methods;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.http.message.BasicNameValuePair;
+import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.AsyncRequestProducer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
+import org.apache.hc.core5.net.URIBuilder;
+import org.apache.hc.core5.net.URLEncodedUtils;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Builder for {@link AsyncRequestProducer} instances.
+ * <p>
+ * Please note that this class treats parameters differently depending on composition
+ * of the request: if the request has a content entity explicitly set with
+ * {@link #setEntity(AsyncEntityProducer)} or it is not an entity enclosing method
+ * (such as POST or PUT), parameters will be added to the query component of the request URI.
+ * Otherwise, parameters will be added as a URL encoded entity.
+ * </p>
+ *
+ * @since 5.0
+ */
+public class AsyncRequestBuilder {
+
+    private String method;
+    private URI uri;
+    private Charset charset;
+    private ProtocolVersion version;
+    private HeaderGroup headerGroup;
+    private AsyncEntityProducer entityProducer;
+    private List<NameValuePair> parameters;
+
+    AsyncRequestBuilder() {
+    }
+
+    AsyncRequestBuilder(final String method) {
+        super();
+        this.method = method;
+    }
+
+    AsyncRequestBuilder(final Methods method) {
+        this(method.name());
+    }
+
+    AsyncRequestBuilder(final String method, final URI uri) {
+        super();
+        this.method = method;
+        this.uri = uri;
+    }
+
+    AsyncRequestBuilder(final Methods method, final URI uri) {
+        this(method.name(), uri);
+    }
+
+    AsyncRequestBuilder(final Methods method, final String uri) {
+        this(method.name(), uri != null ? URI.create(uri) : null);
+    }
+
+    AsyncRequestBuilder(final String method, final String uri) {
+        this(method, uri != null ? URI.create(uri) : null);
+    }
+
+    public static AsyncRequestBuilder create(final String method) {
+        Args.notBlank(method, "HTTP method");
+        return new AsyncRequestBuilder(method);
+    }
+
+    public static AsyncRequestBuilder get() {
+        return new AsyncRequestBuilder(Methods.GET);
+    }
+
+    public static AsyncRequestBuilder get(final URI uri) {
+        return new AsyncRequestBuilder(Methods.GET, uri);
+    }
+
+    public static AsyncRequestBuilder get(final String uri) {
+        return new AsyncRequestBuilder(Methods.GET, uri);
+    }
+
+    public static AsyncRequestBuilder head() {
+        return new AsyncRequestBuilder(Methods.HEAD);
+    }
+
+    public static AsyncRequestBuilder head(final URI uri) {
+        return new AsyncRequestBuilder(Methods.HEAD, uri);
+    }
+
+    public static AsyncRequestBuilder head(final String uri) {
+        return new AsyncRequestBuilder(Methods.HEAD, uri);
+    }
+
+    public static AsyncRequestBuilder patch() {
+        return new AsyncRequestBuilder(Methods.PATCH);
+    }
+
+    public static AsyncRequestBuilder patch(final URI uri) {
+        return new AsyncRequestBuilder(Methods.PATCH, uri);
+    }
+
+    public static AsyncRequestBuilder patch(final String uri) {
+        return new AsyncRequestBuilder(Methods.PATCH, uri);
+    }
+
+    public static AsyncRequestBuilder post() {
+        return new AsyncRequestBuilder(Methods.POST);
+    }
+
+    public static AsyncRequestBuilder post(final URI uri) {
+        return new AsyncRequestBuilder(Methods.POST, uri);
+    }
+
+    public static AsyncRequestBuilder post(final String uri) {
+        return new AsyncRequestBuilder(Methods.POST, uri);
+    }
+
+    public static AsyncRequestBuilder put() {
+        return new AsyncRequestBuilder(Methods.PUT);
+    }
+
+    public static AsyncRequestBuilder put(final URI uri) {
+        return new AsyncRequestBuilder(Methods.PUT, uri);
+    }
+
+    public static AsyncRequestBuilder put(final String uri) {
+        return new AsyncRequestBuilder(Methods.PUT, uri);
+    }
+
+    public static AsyncRequestBuilder delete() {
+        return new AsyncRequestBuilder(Methods.DELETE);
+    }
+
+    public static AsyncRequestBuilder delete(final URI uri) {
+        return new AsyncRequestBuilder(Methods.DELETE, uri);
+    }
+
+    public static AsyncRequestBuilder delete(final String uri) {
+        return new AsyncRequestBuilder(Methods.DELETE, uri);
+    }
+
+    public static AsyncRequestBuilder trace() {
+        return new AsyncRequestBuilder(Methods.TRACE);
+    }
+
+    public static AsyncRequestBuilder trace(final URI uri) {
+        return new AsyncRequestBuilder(Methods.TRACE, uri);
+    }
+
+    public static AsyncRequestBuilder trace(final String uri) {
+        return new AsyncRequestBuilder(Methods.TRACE, uri);
+    }
+
+    public static AsyncRequestBuilder options() {
+        return new AsyncRequestBuilder(Methods.OPTIONS);
+    }
+
+    public static AsyncRequestBuilder options(final URI uri) {
+        return new AsyncRequestBuilder(Methods.OPTIONS, uri);
+    }
+
+    public static AsyncRequestBuilder options(final String uri) {
+        return new AsyncRequestBuilder(Methods.OPTIONS, uri);
+    }
+
+    public AsyncRequestBuilder setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    public Charset getCharset() {
+        return charset;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    public AsyncRequestBuilder setUri(final URI uri) {
+        this.uri = uri;
+        return this;
+    }
+
+    public AsyncRequestBuilder setUri(final String uri) {
+        this.uri = uri != null ? URI.create(uri) : null;
+        return this;
+    }
+
+    public ProtocolVersion getVersion() {
+        return version;
+    }
+
+    public AsyncRequestBuilder setVersion(final ProtocolVersion version) {
+        this.version = version;
+        return this;
+    }
+
+    public Header[] getHeaders(final String name) {
+        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    }
+
+    public AsyncRequestBuilder setHeaders(final Header... headers) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeaders(headers);
+        return this;
+    }
+
+    public Header getFirstHeader(final String name) {
+        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
+    }
+
+    public Header getLastHeader(final String name) {
+        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
+    }
+
+    public AsyncRequestBuilder addHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(header);
+        return this;
+    }
+
+    public AsyncRequestBuilder addHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.addHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public AsyncRequestBuilder removeHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.removeHeader(header);
+        return this;
+    }
+
+    public AsyncRequestBuilder removeHeaders(final String name) {
+        if (name == null || headerGroup == null) {
+            return this;
+        }
+        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
+            final Header header = i.next();
+            if (name.equalsIgnoreCase(header.getName())) {
+                i.remove();
+            }
+        }
+        return this;
+    }
+
+    public AsyncRequestBuilder setHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(header);
+        return this;
+    }
+
+    public AsyncRequestBuilder setHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public List<NameValuePair> getParameters() {
+        return parameters != null ? new ArrayList<>(parameters) : new ArrayList<NameValuePair>();
+    }
+
+    public AsyncRequestBuilder addParameter(final NameValuePair nvp) {
+        Args.notNull(nvp, "Name value pair");
+        if (parameters == null) {
+            parameters = new LinkedList<>();
+        }
+        parameters.add(nvp);
+        return this;
+    }
+
+    public AsyncRequestBuilder addParameter(final String name, final String value) {
+        return addParameter(new BasicNameValuePair(name, value));
+    }
+
+    public AsyncRequestBuilder addParameters(final NameValuePair... nvps) {
+        for (final NameValuePair nvp: nvps) {
+            addParameter(nvp);
+        }
+        return this;
+    }
+
+    public AsyncEntityProducer getEntity() {
+        return entityProducer;
+    }
+
+    public AsyncRequestBuilder setEntity(final AsyncEntityProducer entityProducer) {
+        this.entityProducer = entityProducer;
+        return this;
+    }
+
+    public AsyncRequestBuilder setEntity(final String content, final ContentType contentType) {
+        this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
+        return this;
+    }
+
+    public AsyncRequestBuilder setEntity(final String content) {
+        this.entityProducer = new BasicAsyncEntityProducer(content);
+        return this;
+    }
+
+    public AsyncRequestBuilder setEntity(final byte[] content, final ContentType contentType) {
+        this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
+        return this;
+    }
+
+    public AsyncRequestProducer build() {
+        URI uriCopy = uri != null ? uri : URI.create("/");
+        AsyncEntityProducer entityProducerCopy = entityProducer;
+        if (parameters != null && !parameters.isEmpty()) {
+            if (entityProducerCopy == null && (Methods.POST.isSame(method) || Methods.PUT.isSame(method))) {
+                final String content = URLEncodedUtils.format(
+                        parameters,
+                        charset != null ? charset : ContentType.APPLICATION_FORM_URLENCODED.getCharset());
+                entityProducerCopy = new StringAsyncEntityProducer(
+                        content,
+                        ContentType.APPLICATION_FORM_URLENCODED);
+            } else {
+                try {
+                    uriCopy = new URIBuilder(uriCopy)
+                      .setCharset(this.charset)
+                      .addParameters(parameters)
+                      .build();
+                } catch (final URISyntaxException ex) {
+                    // should never happen
+                }
+            }
+        }
+
+        if (entityProducerCopy != null && Methods.TRACE.isSame(method)) {
+            throw new IllegalStateException(Methods.TRACE + " requests may not include an entity.");
+        }
+
+        final HttpRequest request = new BasicHttpRequest(method, uriCopy);
+        if (this.headerGroup != null) {
+            request.setHeaders(this.headerGroup.getHeaders());
+        }
+        if (version != null) {
+            request.setVersion(version);
+        }
+        return new BasicRequestProducer(request, entityProducerCopy);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("AsyncRequestBuilder [method=");
+        builder.append(method);
+        builder.append(", charset=");
+        builder.append(charset);
+        builder.append(", version=");
+        builder.append(version);
+        builder.append(", uri=");
+        builder.append(uri);
+        builder.append(", headerGroup=");
+        builder.append(headerGroup);
+        builder.append(", entity=");
+        builder.append(entityProducer != null ? entityProducer.getClass() : null);
+        builder.append(", parameters=");
+        builder.append(parameters);
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
new file mode 100644
index 0000000..abb2294
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
@@ -0,0 +1,203 @@
+/*
+ * ====================================================================
+ * 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.core5.http.nio.support;
+
+import java.util.Iterator;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
+import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.AsyncResponseProducer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Builder for {@link AsyncResponseProducer} instances.
+ *
+ * @since 5.0
+ */
+public class AsyncResponseBuilder {
+
+    private int status;
+    private ProtocolVersion version;
+    private HeaderGroup headerGroup;
+    private AsyncEntityProducer entityProducer;
+
+    AsyncResponseBuilder() {
+    }
+
+    AsyncResponseBuilder(final int status) {
+        super();
+        this.status = status;
+    }
+
+    public static AsyncResponseBuilder create(final int status) {
+        Args.checkRange(status, 100, 599, "HTTP status code");
+        return new AsyncResponseBuilder(status);
+    }
+
+    public ProtocolVersion getVersion() {
+        return version;
+    }
+
+    public AsyncResponseBuilder setVersion(final ProtocolVersion version) {
+        this.version = version;
+        return this;
+    }
+
+    public Header[] getHeaders(final String name) {
+        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    }
+
+    public AsyncResponseBuilder setHeaders(final Header... headers) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeaders(headers);
+        return this;
+    }
+
+    public Header getFirstHeader(final String name) {
+        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
+    }
+
+    public Header getLastHeader(final String name) {
+        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
+    }
+
+    public AsyncResponseBuilder addHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(header);
+        return this;
+    }
+
+    public AsyncResponseBuilder addHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.addHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public AsyncResponseBuilder removeHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.removeHeader(header);
+        return this;
+    }
+
+    public AsyncResponseBuilder removeHeaders(final String name) {
+        if (name == null || headerGroup == null) {
+            return this;
+        }
+        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
+            final Header header = i.next();
+            if (name.equalsIgnoreCase(header.getName())) {
+                i.remove();
+            }
+        }
+        return this;
+    }
+
+    public AsyncResponseBuilder setHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(header);
+        return this;
+    }
+
+    public AsyncResponseBuilder setHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        this.headerGroup.setHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public AsyncEntityProducer getEntity() {
+        return entityProducer;
+    }
+
+    public AsyncResponseBuilder setEntity(final AsyncEntityProducer entityProducer) {
+        this.entityProducer = entityProducer;
+        return this;
+    }
+
+    public AsyncResponseBuilder setEntity(final String content, final ContentType contentType) {
+        this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
+        return this;
+    }
+
+    public AsyncResponseBuilder setEntity(final String content) {
+        this.entityProducer = new BasicAsyncEntityProducer(content);
+        return this;
+    }
+
+    public AsyncResponseBuilder setEntity(final byte[] content, final ContentType contentType) {
+        this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
+        return this;
+    }
+
+    public AsyncResponseProducer build() {
+        final HttpResponse response = new BasicHttpResponse(status);
+        if (this.headerGroup != null) {
+            response.setHeaders(this.headerGroup.getHeaders());
+        }
+        if (version != null) {
+            response.setVersion(version);
+        }
+        return new BasicResponseProducer(response, entityProducer);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("AsyncResponseBuilder [method=");
+        builder.append(status);
+        builder.append(", status=");
+        builder.append(status);
+        builder.append(", version=");
+        builder.append(version);
+        builder.append(", headerGroup=");
+        builder.append(headerGroup);
+        builder.append(", entity=");
+        builder.append(entityProducer != null ? entityProducer.getClass() : null);
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncServerFilterChainExchangeHandlerFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncServerFilterChainExchangeHandlerFactory.java
index 71b93ad..216426e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncServerFilterChainExchangeHandlerFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncServerFilterChainExchangeHandlerFactory.java
@@ -43,7 +43,6 @@ import org.apache.hc.core5.http.nio.AsyncFilterChain;
 import org.apache.hc.core5.http.nio.AsyncPushProducer;
 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.HandlerFactory;
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicPushProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicPushProducer.java
similarity index 92%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicPushProducer.java
rename to httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicPushProducer.java
index 09077b4..8ce2280 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicPushProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicPushProducer.java
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http.nio;
+package org.apache.hc.core5.http.nio.support;
 
 import java.io.IOException;
 
@@ -32,6 +32,10 @@ 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.message.BasicHttpResponse;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.AsyncPushProducer;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicRequestConsumer.java
similarity index 96%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java
rename to httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicRequestConsumer.java
index 7be827f..bec2232 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicRequestConsumer.java
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http.nio;
+package org.apache.hc.core5.http.nio.support;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -38,6 +38,9 @@ import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Message;
+import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
+import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicRequestProducer.java
similarity index 94%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestProducer.java
rename to httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicRequestProducer.java
index 28cde62..6435f71 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicRequestProducer.java
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http.nio;
+package org.apache.hc.core5.http.nio.support;
 
 import java.io.IOException;
 import java.net.URI;
@@ -34,6 +34,10 @@ import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.AsyncRequestProducer;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.apache.hc.core5.http.nio.RequestChannel;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
 /**
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicResponseConsumer.java
similarity index 96%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java
rename to httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicResponseConsumer.java
index 2501985..5c24793 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicResponseConsumer.java
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http.nio;
+package org.apache.hc.core5.http.nio.support;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -38,6 +38,9 @@ import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.Message;
+import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.AsyncResponseConsumer;
+import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicResponseProducer.java
similarity index 93%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseProducer.java
rename to httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicResponseProducer.java
index 087ebae..56e73f6 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicResponseProducer.java
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http.nio;
+package org.apache.hc.core5.http.nio.support;
 
 import java.io.IOException;
 
@@ -33,6 +33,10 @@ 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.message.BasicHttpResponse;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.AsyncResponseProducer;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java
index 9903af5..cc5e214 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java
@@ -38,7 +38,6 @@ import org.apache.hc.core5.http.HttpResponse;
 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;
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFileServerExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFileServerExample.java
index 024dbc5..a8b776c 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFileServerExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFileServerExample.java
@@ -47,10 +47,10 @@ import org.apache.hc.core5.http.impl.bootstrap.AsyncServerBootstrap;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
-import org.apache.hc.core5.http.nio.entity.FileEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
 import org.apache.hc.core5.http.protocol.HttpDateGenerator;
@@ -64,7 +64,9 @@ import org.apache.hc.core5.util.TimeValue;
  */
 public class AsyncFileServerExample {
 
-    /** Example command line args: {@code "c:\temp" 8080} */
+    /**
+     * Example command line args: {@code "c:\temp" 8080}
+     */
     public static void main(final String[] args) throws Exception {
         if (args.length < 1) {
             System.err.println("Please specify document root directory");
@@ -112,19 +114,20 @@ public class AsyncFileServerExample {
 
                             final String msg = "File " + file.getPath() + " not found";
                             println(msg);
-                            responseTrigger.submitResponse(new BasicResponseProducer(
-                                    HttpStatus.SC_NOT_FOUND,
-                                    "<html><body><h1>" + msg + "</h1></body></html>",
-                                    ContentType.TEXT_HTML), context);
+                            responseTrigger.submitResponse(
+                                    AsyncResponseBuilder.create(HttpStatus.SC_NOT_FOUND)
+                                            .setEntity("<html><body><h1>" + msg + "</h1></body></html>", ContentType.TEXT_HTML)
+                                            .build(),
+                                    context);
 
                         } else if (!file.canRead() || file.isDirectory()) {
 
                             final String msg = "Cannot read file " + file.getPath();
                             println(msg);
-                            responseTrigger.submitResponse(new BasicResponseProducer(
-                                    HttpStatus.SC_FORBIDDEN,
-                                    "<html><body><h1>" + msg + "</h1></body></html>",
-                                    ContentType.TEXT_HTML), context);
+                            responseTrigger.submitResponse(AsyncResponseBuilder.create(HttpStatus.SC_FORBIDDEN)
+                                            .setEntity("<html><body><h1>" + msg + "</h1></body></html>", ContentType.TEXT_HTML)
+                                            .build(),
+                                    context);
 
                         } else {
 
@@ -145,8 +148,11 @@ public class AsyncFileServerExample {
 
                             println(endpoint + " | serving file " + file.getPath());
 
-                            responseTrigger.submitResponse(new BasicResponseProducer(
-                                    HttpStatus.SC_OK, new FileEntityProducer(file, contentType)), context);
+                            responseTrigger.submitResponse(
+                                    AsyncResponseBuilder.create(HttpStatus.SC_OK)
+                                            .setEntity(AsyncEntityProducers.create(file, contentType))
+                                            .build(),
+                                    context);
                         }
                     }
 
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFullDuplexClientExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFullDuplexClientExample.java
index 6da0fc6..b1aa26b 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFullDuplexClientExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncFullDuplexClientExample.java
@@ -41,7 +41,6 @@ import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpRequestInterceptor;
 import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.impl.HttpProcessors;
 import org.apache.hc.core5.http.impl.bootstrap.AsyncRequesterBootstrap;
@@ -49,13 +48,13 @@ import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.AsyncRequestProducer;
 import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.RequestChannel;
-import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
 import org.apache.hc.core5.io.CloseMode;
@@ -121,8 +120,9 @@ public class AsyncFullDuplexClientExample {
         requester.start();
 
         final URI requestUri = new URI("http://httpbin.org/post");
-        final BasicRequestProducer requestProducer = new BasicRequestProducer(
-                Methods.POST.name(), requestUri, AsyncEntityProducers.create("stuff"));
+        final AsyncRequestProducer requestProducer = AsyncRequestBuilder.post(requestUri)
+                .setEntity("stuff")
+                .build();
         final BasicResponseConsumer<String> responseConsumer = new BasicResponseConsumer<>(
                 new StringAsyncEntityConsumer());
 
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
index 9517bf0..8afca1c 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
@@ -43,9 +43,9 @@ import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.util.Timeout;
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncRequestExecutionExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncRequestExecutionExample.java
index 7e3b392..5564432 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncRequestExecutionExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncRequestExecutionExample.java
@@ -41,9 +41,9 @@ import org.apache.hc.core5.http.impl.bootstrap.AsyncRequesterBootstrap;
 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.http.message.StatusLine;
-import org.apache.hc.core5.http.nio.BasicRequestProducer;
-import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.util.Timeout;
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncServerFilterExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncServerFilterExample.java
index 828f849..8cce0da 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncServerFilterExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/AsyncServerFilterExample.java
@@ -48,11 +48,11 @@ import org.apache.hc.core5.http.nio.AsyncFilterHandler;
 import org.apache.hc.core5.http.nio.AsyncPushProducer;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
-import org.apache.hc.core5.http.nio.BasicRequestConsumer;
-import org.apache.hc.core5.http.nio.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractAsyncServerAuthFilter;
+import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.net.URIAuthority;
@@ -171,7 +171,9 @@ public class AsyncServerFilterExample {
                             final HttpContext context) throws HttpException, IOException {
                         // do something useful
                         responseTrigger.submitResponse(
-                                new BasicResponseProducer(HttpStatus.SC_OK, AsyncEntityProducers.create("Hello")),
+                                AsyncResponseBuilder.create(HttpStatus.SC_OK)
+                                        .setEntity("Hello")
+                                        .build(),
                                 context);
                     }
                 })
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
index 5430bfc..d36d06e 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
@@ -117,7 +117,7 @@ public class ClassicPostExecutionExample {
 
         final String requestUri = "/post";
         for (int i = 0; i < requestBodies.length; i++) {
-            final ClassicHttpRequest request = new BasicClassicHttpRequest(Methods.POST, target,requestUri);
+            final ClassicHttpRequest request = new BasicClassicHttpRequest(Methods.POST, target, requestUri);
             request.setEntity(requestBodies[i]);
             try (ClassicHttpResponse response = httpRequester.execute(target, request, Timeout.ofSeconds(5), coreContext)) {
                 System.out.println(requestUri + "->" + response.getCode());