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:03 UTC

[httpcomponents-core] branch message-support updated (d31f4ff -> 1a3aff6)

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

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


 discard d31f4ff  Basic message consumer simplifications and improvements
     add 5b52519  [HTTPCORE-578] Incorrect serialization of HeaderGroup #127.
     new ecdebe1  Code formatting (no functional changes)
     new 8ddd7dc  Escape DEL character when tracing
     new 44a82e9  Basic message consumer simplifications and improvements
     new 0e96b7d  Improved classic and async entity factory methods
     new fe6d9ca  Classic and async message builders
     new 1a3aff6  Fixed parameter inconsistency in server side push APIs

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (d31f4ff)
            \
             N -- N -- N   refs/heads/message-support (1a3aff6)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 RELEASE_NOTES.txt                                  |   4 +
 .../http2/impl/nio/ServerHttp2StreamHandler.java   |   2 +-
 .../impl/nio/ServerPushHttp2StreamHandler.java     |   2 +-
 .../Http2ConscriptRequestExecutionExample.java     |   4 +-
 .../http2/examples/Http2FileServerExample.java     |  33 +-
 .../examples/Http2FullDuplexClientExample.java     |  13 +-
 .../examples/Http2MultiStreamExecutionExample.java |   4 +-
 .../examples/Http2RequestExecutionExample.java     |   4 +-
 .../Http2TlsAlpnRequestExecutionExample.java       |   4 +-
 .../examples/ReactiveFullDuplexClientExample.java  |  13 +-
 .../org/apache/hc/core5/testing/classic/Wire.java  |  13 +-
 .../hc/core5/benchmark/BenchmarkToolTest.java      |  10 +-
 .../http2/Http2CompatibilityTest.java              |   4 +-
 .../core5/testing/nio/Http1AuthenticationTest.java |  16 +-
 .../hc/core5/testing/nio/Http1IntegrationTest.java |  38 +-
 .../testing/nio/Http1ServerAndRequesterTest.java   |   4 +-
 .../apache/hc/core5/testing/nio/Http2AlpnTest.java |   4 +-
 .../hc/core5/testing/nio/Http2IntegrationTest.java |  30 +-
 .../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 +-
 .../http/impl/nio/ServerHttp1StreamHandler.java    |   2 +-
 .../hc/core5/http/impl/nio/ServerSupport.java      |   2 +-
 .../hc/core5/http/io/entity/EntityTemplate.java    |  12 +-
 .../hc/core5/http/io/entity/EntityUtils.java       |   2 +-
 .../core5/http/io/entity/HttpContentProducer.java  |  44 ---
 .../hc/core5/http/io/entity/HttpEntities.java      | 224 +++++++++++
 .../hc/core5/http/io/entity/HttpEntityWrapper.java |   8 +-
 .../http/io/support/ClassicRequestBuilder.java     | 419 ++++++++++++++++++++
 .../http/io/support/ClassicResponseBuilder.java    | 203 ++++++++++
 .../apache/hc/core5/http/nio/ResponseChannel.java  |   4 +-
 .../entity/AsyncEntityProducerWrapper.java}        |  74 ++--
 .../http/nio/entity/AsyncEntityProducers.java      | 235 ++++++++++++
 .../nio/support/AbstractAsyncServerAuthFilter.java |   4 +-
 .../nio/support/AbstractServerExchangeHandler.java |   8 +-
 .../core5/http/nio/support/AsyncPushBuilder.java   | 187 +++++++++
 .../http/nio/support/AsyncRequestBuilder.java      | 424 +++++++++++++++++++++
 .../http/nio/support/AsyncResponseBuilder.java     | 203 ++++++++++
 ...yncServerFilterChainExchangeHandlerFactory.java |   3 +-
 .../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   |  10 +-
 .../support/ImmediateResponseExchangeHandler.java  |   6 +-
 .../nio/support/TerminalAsyncServerFilter.java     |   6 +-
 .../core5/io/{CloseMode.java => IOCallback.java}   |   8 +-
 .../org/apache/hc/core5/net/URLEncodedUtils.java   |   5 -
 .../http/examples/AsyncFileServerExample.java      |  34 +-
 .../examples/AsyncFullDuplexClientExample.java     |  13 +-
 .../AsyncPipelinedRequestExecutionExample.java     |   4 +-
 .../examples/AsyncRequestExecutionExample.java     |   4 +-
 .../http/examples/AsyncServerFilterExample.java    |  17 +-
 .../http/examples/ClassicPostExecutionExample.java |  36 +-
 .../ClassicPostWithTrailersExecutionExample.java   |  78 ----
 .../hc/core5/http/io/entity/TestEntityUtils.java   |   2 +-
 .../hc/core5/http/message/TestMessageSupport.java  |  10 +-
 .../http/protocol/TestStandardInterceptors.java    |   6 +-
 62 files changed, 2178 insertions(+), 386 deletions(-)
 delete mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpContentProducer.java
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntities.java
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
 rename httpcore5/src/main/java/org/apache/hc/core5/http/{io/entity/HttpEntityWithTrailers.java => nio/entity/AsyncEntityProducerWrapper.java} (52%)
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducers.java
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
 create mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
 rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ => support}/BasicPushProducer.java (92%)
 rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ => support}/BasicRequestConsumer.java (96%)
 rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ => support}/BasicRequestProducer.java (94%)
 rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ => support}/BasicResponseConsumer.java (96%)
 rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ => support}/BasicResponseProducer.java (90%)
 copy httpcore5/src/main/java/org/apache/hc/core5/io/{CloseMode.java => IOCallback.java} (90%)
 delete mode 100644 httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostWithTrailersExecutionExample.java


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

Posted by ol...@apache.org.
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());


[httpcomponents-core] 01/06: Code formatting (no functional changes)

Posted by ol...@apache.org.
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 ecdebe19df5fe77abb493bd701823dcac55b1861
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Thu May 30 11:58:07 2019 +0200

    Code formatting (no functional changes)
---
 .../main/java/org/apache/hc/core5/testing/classic/Wire.java   | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java
index aebe608..6f20a4b 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java
@@ -30,6 +30,7 @@ package org.apache.hc.core5.testing.classic;
 import java.nio.ByteBuffer;
 
 import org.slf4j.Logger;
+
 public class Wire {
 
     private final Logger log;
@@ -48,11 +49,11 @@ public class Wire {
             if (ch == 13) {
                 buffer.append("[\\r]");
             } else if (ch == 10) {
-                    buffer.append("[\\n]\"");
-                    buffer.insert(0, "\"");
-                    buffer.insert(0, header);
-                    this.log.debug(this.id + " " + buffer.toString());
-                    buffer.setLength(0);
+                buffer.append("[\\n]\"");
+                buffer.insert(0, "\"");
+                buffer.insert(0, header);
+                this.log.debug(this.id + " " + buffer.toString());
+                buffer.setLength(0);
             } else if ((ch < 32) || (ch > 127)) {
                 buffer.append("[0x");
                 buffer.append(Integer.toHexString(ch));


Re: [httpcomponents-core] branch message-support updated (d31f4ff -> 1a3aff6)

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Fri, 2019-05-31 at 14:16 -0400, Gary Gregory wrote:
> Unless I am missing something, this kind of large change set tells me
> we
> are not quite ready for 5.0 but at least one or two more betas will
> be a
> good thing.
> 

This is likely to be my last large change-set for HttpCore 5.0 GA. It
is mostly support code anyway. 

As far as I am concerned I am done.

Oleg


> Gary
> 
> On Fri, May 31, 2019 at 1:51 PM <ol...@apache.org> wrote:
> 
> > This is an automated email from the ASF dual-hosted git repository.
> > 
> > olegk pushed a change to branch message-support
> > in repository 
> > https://gitbox.apache.org/repos/asf/httpcomponents-core.git.
> > 
> > 
> >  discard d31f4ff  Basic message consumer simplifications and
> > improvements
> >      add 5b52519  [HTTPCORE-578] Incorrect serialization of
> > HeaderGroup
> > #127.
> >      new ecdebe1  Code formatting (no functional changes)
> >      new 8ddd7dc  Escape DEL character when tracing
> >      new 44a82e9  Basic message consumer simplifications and
> > improvements
> >      new 0e96b7d  Improved classic and async entity factory methods
> >      new fe6d9ca  Classic and async message builders
> >      new 1a3aff6  Fixed parameter inconsistency in server side push
> > APIs
> > 
> > This update added new revisions after undoing existing revisions.
> > That is to say, some revisions that were in the old version of the
> > branch are not in the new version.  This situation occurs
> > when a user --force pushes a change and generates a repository
> > containing something like this:
> > 
> >  * -- * -- B -- O -- O -- O   (d31f4ff)
> >             \
> >              N -- N -- N   refs/heads/message-support (1a3aff6)
> > 
> > You should already have received notification emails for all of the
> > O
> > revisions, and so the following emails describe only the N
> > revisions
> > from the common base, B.
> > 
> > Any revisions marked "omit" are not gone; other references still
> > refer to them.  Any revisions marked "discard" are gone forever.
> > 
> > The 6 revisions listed above as "new" are entirely new to this
> > repository and will be described in separate emails.  The revisions
> > listed as "add" were already present in the repository and have
> > only
> > been added to this reference.
> > 
> > 
> > Summary of changes:
> >  RELEASE_NOTES.txt                                  |   4 +
> >  .../http2/impl/nio/ServerHttp2StreamHandler.java   |   2 +-
> >  .../impl/nio/ServerPushHttp2StreamHandler.java     |   2 +-
> >  .../Http2ConscriptRequestExecutionExample.java     |   4 +-
> >  .../http2/examples/Http2FileServerExample.java     |  33 +-
> >  .../examples/Http2FullDuplexClientExample.java     |  13 +-
> >  .../examples/Http2MultiStreamExecutionExample.java |   4 +-
> >  .../examples/Http2RequestExecutionExample.java     |   4 +-
> >  .../Http2TlsAlpnRequestExecutionExample.java       |   4 +-
> >  .../examples/ReactiveFullDuplexClientExample.java  |  13 +-
> >  .../org/apache/hc/core5/testing/classic/Wire.java  |  13 +-
> >  .../hc/core5/benchmark/BenchmarkToolTest.java      |  10 +-
> >  .../http2/Http2CompatibilityTest.java              |   4 +-
> >  .../core5/testing/nio/Http1AuthenticationTest.java |  16 +-
> >  .../hc/core5/testing/nio/Http1IntegrationTest.java |  38 +-
> >  .../testing/nio/Http1ServerAndRequesterTest.java   |   4 +-
> >  .../apache/hc/core5/testing/nio/Http2AlpnTest.java |   4 +-
> >  .../hc/core5/testing/nio/Http2IntegrationTest.java |  30 +-
> >  .../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 +-
> >  .../http/impl/nio/ServerHttp1StreamHandler.java    |   2 +-
> >  .../hc/core5/http/impl/nio/ServerSupport.java      |   2 +-
> >  .../hc/core5/http/io/entity/EntityTemplate.java    |  12 +-
> >  .../hc/core5/http/io/entity/EntityUtils.java       |   2 +-
> >  .../core5/http/io/entity/HttpContentProducer.java  |  44 ---
> >  .../hc/core5/http/io/entity/HttpEntities.java      | 224
> > +++++++++++
> >  .../hc/core5/http/io/entity/HttpEntityWrapper.java |   8 +-
> >  .../http/io/support/ClassicRequestBuilder.java     | 419
> > ++++++++++++++++++++
> >  .../http/io/support/ClassicResponseBuilder.java    | 203
> > ++++++++++
> >  .../apache/hc/core5/http/nio/ResponseChannel.java  |   4 +-
> >  .../entity/AsyncEntityProducerWrapper.java}        |  74 ++--
> >  .../http/nio/entity/AsyncEntityProducers.java      | 235
> > ++++++++++++
> >  .../nio/support/AbstractAsyncServerAuthFilter.java |   4 +-
> >  .../nio/support/AbstractServerExchangeHandler.java |   8 +-
> >  .../core5/http/nio/support/AsyncPushBuilder.java   | 187 +++++++++
> >  .../http/nio/support/AsyncRequestBuilder.java      | 424
> > +++++++++++++++++++++
> >  .../http/nio/support/AsyncResponseBuilder.java     | 203
> > ++++++++++
> >  ...yncServerFilterChainExchangeHandlerFactory.java |   3 +-
> >  .../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   |  10 +-
> >  .../support/ImmediateResponseExchangeHandler.java  |   6 +-
> >  .../nio/support/TerminalAsyncServerFilter.java     |   6 +-
> >  .../core5/io/{CloseMode.java => IOCallback.java}   |   8 +-
> >  .../org/apache/hc/core5/net/URLEncodedUtils.java   |   5 -
> >  .../http/examples/AsyncFileServerExample.java      |  34 +-
> >  .../examples/AsyncFullDuplexClientExample.java     |  13 +-
> >  .../AsyncPipelinedRequestExecutionExample.java     |   4 +-
> >  .../examples/AsyncRequestExecutionExample.java     |   4 +-
> >  .../http/examples/AsyncServerFilterExample.java    |  17 +-
> >  .../http/examples/ClassicPostExecutionExample.java |  36 +-
> >  .../ClassicPostWithTrailersExecutionExample.java   |  78 ----
> >  .../hc/core5/http/io/entity/TestEntityUtils.java   |   2 +-
> >  .../hc/core5/http/message/TestMessageSupport.java  |  10 +-
> >  .../http/protocol/TestStandardInterceptors.java    |   6 +-
> >  62 files changed, 2178 insertions(+), 386 deletions(-)
> >  delete mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpCont
> > entProducer.java
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEnti
> > ties.java
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/io/support/Classic
> > RequestBuilder.java
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/io/support/Classic
> > ResponseBuilder.java
> >  rename
> > httpcore5/src/main/java/org/apache/hc/core5/http/{io/entity/HttpEnt
> > ityWithTrailers.java
> > => nio/entity/AsyncEntityProducerWrapper.java} (52%)
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEn
> > tityProducers.java
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncP
> > ushBuilder.java
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncR
> > equestBuilder.java
> >  create mode 100644
> > httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncR
> > esponseBuilder.java
> >  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> > support}/BasicPushProducer.java (92%)
> >  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> > support}/BasicRequestConsumer.java (96%)
> >  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> > support}/BasicRequestProducer.java (94%)
> >  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> > support}/BasicResponseConsumer.java (96%)
> >  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> > support}/BasicResponseProducer.java (90%)
> >  copy
> > httpcore5/src/main/java/org/apache/hc/core5/io/{CloseMode.java =>
> > IOCallback.java} (90%)
> >  delete mode 100644
> > httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPo
> > stWithTrailersExecutionExample.java
> > 
> > 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org


Re: [httpcomponents-core] branch message-support updated (d31f4ff -> 1a3aff6)

Posted by Gary Gregory <ga...@gmail.com>.
Unless I am missing something, this kind of large change set tells me we
are not quite ready for 5.0 but at least one or two more betas will be a
good thing.

Gary

On Fri, May 31, 2019 at 1:51 PM <ol...@apache.org> wrote:

> This is an automated email from the ASF dual-hosted git repository.
>
> olegk pushed a change to branch message-support
> in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git.
>
>
>  discard d31f4ff  Basic message consumer simplifications and improvements
>      add 5b52519  [HTTPCORE-578] Incorrect serialization of HeaderGroup
> #127.
>      new ecdebe1  Code formatting (no functional changes)
>      new 8ddd7dc  Escape DEL character when tracing
>      new 44a82e9  Basic message consumer simplifications and improvements
>      new 0e96b7d  Improved classic and async entity factory methods
>      new fe6d9ca  Classic and async message builders
>      new 1a3aff6  Fixed parameter inconsistency in server side push APIs
>
> This update added new revisions after undoing existing revisions.
> That is to say, some revisions that were in the old version of the
> branch are not in the new version.  This situation occurs
> when a user --force pushes a change and generates a repository
> containing something like this:
>
>  * -- * -- B -- O -- O -- O   (d31f4ff)
>             \
>              N -- N -- N   refs/heads/message-support (1a3aff6)
>
> You should already have received notification emails for all of the O
> revisions, and so the following emails describe only the N revisions
> from the common base, B.
>
> Any revisions marked "omit" are not gone; other references still
> refer to them.  Any revisions marked "discard" are gone forever.
>
> The 6 revisions listed above as "new" are entirely new to this
> repository and will be described in separate emails.  The revisions
> listed as "add" were already present in the repository and have only
> been added to this reference.
>
>
> Summary of changes:
>  RELEASE_NOTES.txt                                  |   4 +
>  .../http2/impl/nio/ServerHttp2StreamHandler.java   |   2 +-
>  .../impl/nio/ServerPushHttp2StreamHandler.java     |   2 +-
>  .../Http2ConscriptRequestExecutionExample.java     |   4 +-
>  .../http2/examples/Http2FileServerExample.java     |  33 +-
>  .../examples/Http2FullDuplexClientExample.java     |  13 +-
>  .../examples/Http2MultiStreamExecutionExample.java |   4 +-
>  .../examples/Http2RequestExecutionExample.java     |   4 +-
>  .../Http2TlsAlpnRequestExecutionExample.java       |   4 +-
>  .../examples/ReactiveFullDuplexClientExample.java  |  13 +-
>  .../org/apache/hc/core5/testing/classic/Wire.java  |  13 +-
>  .../hc/core5/benchmark/BenchmarkToolTest.java      |  10 +-
>  .../http2/Http2CompatibilityTest.java              |   4 +-
>  .../core5/testing/nio/Http1AuthenticationTest.java |  16 +-
>  .../hc/core5/testing/nio/Http1IntegrationTest.java |  38 +-
>  .../testing/nio/Http1ServerAndRequesterTest.java   |   4 +-
>  .../apache/hc/core5/testing/nio/Http2AlpnTest.java |   4 +-
>  .../hc/core5/testing/nio/Http2IntegrationTest.java |  30 +-
>  .../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 +-
>  .../http/impl/nio/ServerHttp1StreamHandler.java    |   2 +-
>  .../hc/core5/http/impl/nio/ServerSupport.java      |   2 +-
>  .../hc/core5/http/io/entity/EntityTemplate.java    |  12 +-
>  .../hc/core5/http/io/entity/EntityUtils.java       |   2 +-
>  .../core5/http/io/entity/HttpContentProducer.java  |  44 ---
>  .../hc/core5/http/io/entity/HttpEntities.java      | 224 +++++++++++
>  .../hc/core5/http/io/entity/HttpEntityWrapper.java |   8 +-
>  .../http/io/support/ClassicRequestBuilder.java     | 419
> ++++++++++++++++++++
>  .../http/io/support/ClassicResponseBuilder.java    | 203 ++++++++++
>  .../apache/hc/core5/http/nio/ResponseChannel.java  |   4 +-
>  .../entity/AsyncEntityProducerWrapper.java}        |  74 ++--
>  .../http/nio/entity/AsyncEntityProducers.java      | 235 ++++++++++++
>  .../nio/support/AbstractAsyncServerAuthFilter.java |   4 +-
>  .../nio/support/AbstractServerExchangeHandler.java |   8 +-
>  .../core5/http/nio/support/AsyncPushBuilder.java   | 187 +++++++++
>  .../http/nio/support/AsyncRequestBuilder.java      | 424
> +++++++++++++++++++++
>  .../http/nio/support/AsyncResponseBuilder.java     | 203 ++++++++++
>  ...yncServerFilterChainExchangeHandlerFactory.java |   3 +-
>  .../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   |  10 +-
>  .../support/ImmediateResponseExchangeHandler.java  |   6 +-
>  .../nio/support/TerminalAsyncServerFilter.java     |   6 +-
>  .../core5/io/{CloseMode.java => IOCallback.java}   |   8 +-
>  .../org/apache/hc/core5/net/URLEncodedUtils.java   |   5 -
>  .../http/examples/AsyncFileServerExample.java      |  34 +-
>  .../examples/AsyncFullDuplexClientExample.java     |  13 +-
>  .../AsyncPipelinedRequestExecutionExample.java     |   4 +-
>  .../examples/AsyncRequestExecutionExample.java     |   4 +-
>  .../http/examples/AsyncServerFilterExample.java    |  17 +-
>  .../http/examples/ClassicPostExecutionExample.java |  36 +-
>  .../ClassicPostWithTrailersExecutionExample.java   |  78 ----
>  .../hc/core5/http/io/entity/TestEntityUtils.java   |   2 +-
>  .../hc/core5/http/message/TestMessageSupport.java  |  10 +-
>  .../http/protocol/TestStandardInterceptors.java    |   6 +-
>  62 files changed, 2178 insertions(+), 386 deletions(-)
>  delete mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpContentProducer.java
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntities.java
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
>  rename
> httpcore5/src/main/java/org/apache/hc/core5/http/{io/entity/HttpEntityWithTrailers.java
> => nio/entity/AsyncEntityProducerWrapper.java} (52%)
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducers.java
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
>  create mode 100644
> httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
>  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> support}/BasicPushProducer.java (92%)
>  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> support}/BasicRequestConsumer.java (96%)
>  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> support}/BasicRequestProducer.java (94%)
>  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> support}/BasicResponseConsumer.java (96%)
>  rename httpcore5/src/main/java/org/apache/hc/core5/http/nio/{ =>
> support}/BasicResponseProducer.java (90%)
>  copy httpcore5/src/main/java/org/apache/hc/core5/io/{CloseMode.java =>
> IOCallback.java} (90%)
>  delete mode 100644
> httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostWithTrailersExecutionExample.java
>
>

[httpcomponents-core] 03/06: Basic message consumer simplifications and improvements

Posted by ol...@apache.org.
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 44a82e916bf85d6215aacf7c462a562a90f0e792
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Wed May 22 16:12:16 2019 +0200

    Basic message consumer simplifications and improvements
---
 .../core5/reactive/ReactiveResponseConsumer.java   |  5 --
 .../apache/hc/core5/benchmark/BenchmarkWorker.java |  5 --
 .../core5/testing/nio/MessageExchangeHandler.java  |  5 ++
 .../hc/core5/http/nio/AsyncRequestConsumer.java    |  8 ---
 .../hc/core5/http/nio/AsyncResponseConsumer.java   |  8 ---
 .../hc/core5/http/nio/BasicRequestConsumer.java    | 47 ++++++++++-------
 .../hc/core5/http/nio/BasicResponseConsumer.java   | 43 ++++++++++-----
 .../support/AbstractAsyncRequesterConsumer.java    | 51 ++++++++++++------
 .../nio/support/AbstractAsyncResponseConsumer.java | 61 ++++++++++++----------
 9 files changed, 130 insertions(+), 103 deletions(-)

diff --git a/httpcore5-reactive/src/main/java/org/apache/hc/core5/reactive/ReactiveResponseConsumer.java b/httpcore5-reactive/src/main/java/org/apache/hc/core5/reactive/ReactiveResponseConsumer.java
index 4300e3d..980194a 100644
--- a/httpcore5-reactive/src/main/java/org/apache/hc/core5/reactive/ReactiveResponseConsumer.java
+++ b/httpcore5-reactive/src/main/java/org/apache/hc/core5/reactive/ReactiveResponseConsumer.java
@@ -142,11 +142,6 @@ public final class ReactiveResponseConsumer implements AsyncResponseConsumer<Voi
     }
 
     @Override
-    public Void getResult() {
-        return null;
-    }
-
-    @Override
     public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
         reactiveDataConsumer.updateCapacity(capacityChannel);
     }
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/BenchmarkWorker.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/BenchmarkWorker.java
index a254653..ce10276 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/BenchmarkWorker.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/BenchmarkWorker.java
@@ -255,11 +255,6 @@ class BenchmarkWorker implements ResourceHolder {
             }
 
             @Override
-            public Void getResult() {
-                return null;
-            }
-
-            @Override
             public void failed(final Exception cause) {
                 stats.incFailureCount();
                 final FutureCallback<Void> resultCallback = resultCallbackRef.getAndSet(null);
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 0e7565e..8031412 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
@@ -26,6 +26,7 @@
  */
 package org.apache.hc.core5.testing.nio;
 
+import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
@@ -48,6 +49,10 @@ public abstract class MessageExchangeHandler<T> extends AbstractServerExchangeHa
         this.requestConsumer = requestConsumer;
     }
 
+    public MessageExchangeHandler(final Supplier<AsyncEntityConsumer<T>> dataConsumerSupplier) {
+        this(new BasicRequestConsumer<>(dataConsumerSupplier));
+    }
+
     public MessageExchangeHandler(final AsyncEntityConsumer<T> entityConsumer) {
         this(new BasicRequestConsumer<>(entityConsumer));
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncRequestConsumer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncRequestConsumer.java
index c4220f4..89f58a4 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncRequestConsumer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncRequestConsumer.java
@@ -63,12 +63,4 @@ public interface AsyncRequestConsumer<T> extends AsyncDataConsumer {
      */
     void failed(Exception cause);
 
-    /**
-     * Returns the result of request processing when it becomes available or {@code null}
-     * if the request is still being received.
-     *
-     * @return the request processing result.
-     */
-    T getResult();
-
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncResponseConsumer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncResponseConsumer.java
index 9c14b3d..e5a0be6 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncResponseConsumer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncResponseConsumer.java
@@ -71,12 +71,4 @@ public interface AsyncResponseConsumer<T> extends AsyncDataConsumer {
      */
     void failed(Exception cause);
 
-    /**
-     * Returns the result of response processing when it becomes available or {@code null}
-     * if the response is still being received.
-     *
-     * @return the response processing result.
-     */
-    T getResult();
-
 }
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/BasicRequestConsumer.java
index 052b67d..7be827f 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/BasicRequestConsumer.java
@@ -29,8 +29,10 @@ package org.apache.hc.core5.http.nio;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
@@ -38,7 +40,6 @@ import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
-import org.apache.hc.core5.util.Asserts;
 
 /**
  * Basic implementation of {@link AsyncRequestConsumer} that represents the request message as
@@ -48,12 +49,23 @@ import org.apache.hc.core5.util.Asserts;
  */
 public class BasicRequestConsumer<T> implements AsyncRequestConsumer<Message<HttpRequest, T>> {
 
-    private final AsyncEntityConsumer<T> dataConsumer;
+    private final Supplier<AsyncEntityConsumer<T>> dataConsumerSupplier;
+    private final AtomicReference<AsyncEntityConsumer<T>> dataConsumerRef;
 
-    private volatile Message<HttpRequest, T> result;
+    public BasicRequestConsumer(final Supplier<AsyncEntityConsumer<T>> dataConsumerSupplier) {
+        this.dataConsumerSupplier = Args.notNull(dataConsumerSupplier, "Data consumer supplier");
+        this.dataConsumerRef = new AtomicReference<>(null);
+    }
 
     public BasicRequestConsumer(final AsyncEntityConsumer<T> dataConsumer) {
-        this.dataConsumer = dataConsumer;
+        this(new Supplier<AsyncEntityConsumer<T>>() {
+
+            @Override
+            public AsyncEntityConsumer<T> get() {
+                return dataConsumer;
+            }
+
+        });
     }
 
     @Override
@@ -64,16 +76,20 @@ public class BasicRequestConsumer<T> implements AsyncRequestConsumer<Message<Htt
             final FutureCallback<Message<HttpRequest, T>> resultCallback) throws HttpException, IOException {
         Args.notNull(request, "Request");
         if (entityDetails != null) {
-            Asserts.notNull(dataConsumer, "Data consumer");
+            final AsyncEntityConsumer<T> dataConsumer = dataConsumerSupplier.get();
+            if (dataConsumer == null) {
+                throw new HttpException("Supplied data consumer is null");
+            }
+            dataConsumerRef.set(dataConsumer);
+
             dataConsumer.streamStart(entityDetails, new FutureCallback<T>() {
 
                 @Override
                 public void completed(final T body) {
-                    result = new Message<>(request, body);
+                    final Message<HttpRequest, T> result = new Message<>(request, body);
                     if (resultCallback != null) {
                         resultCallback.completed(result);
                     }
-                    dataConsumer.releaseResources();
                 }
 
                 @Override
@@ -81,7 +97,6 @@ public class BasicRequestConsumer<T> implements AsyncRequestConsumer<Message<Htt
                     if (resultCallback != null) {
                         resultCallback.failed(ex);
                     }
-                    dataConsumer.releaseResources();
                 }
 
                 @Override
@@ -89,34 +104,32 @@ public class BasicRequestConsumer<T> implements AsyncRequestConsumer<Message<Htt
                     if (resultCallback != null) {
                         resultCallback.cancelled();
                     }
-                    dataConsumer.releaseResources();
                 }
 
             });
         } else {
-            result = new Message<>(request, null);
+            final Message<HttpRequest, T> result = new Message<>(request, null);
             if (resultCallback != null) {
                 resultCallback.completed(result);
             }
-            releaseResources();
         }
     }
 
     @Override
     public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
-        Asserts.notNull(dataConsumer, "Data consumer");
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.get();
         dataConsumer.updateCapacity(capacityChannel);
     }
 
     @Override
     public void consume(final ByteBuffer src) throws IOException {
-        Asserts.notNull(dataConsumer, "Data consumer");
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.get();
         dataConsumer.consume(src);
     }
 
     @Override
     public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
-        Asserts.notNull(dataConsumer, "Data consumer");
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.get();
         dataConsumer.streamEnd(trailers);
     }
 
@@ -126,12 +139,8 @@ public class BasicRequestConsumer<T> implements AsyncRequestConsumer<Message<Htt
     }
 
     @Override
-    public Message<HttpRequest, T> getResult() {
-        return result;
-    }
-
-    @Override
     public void releaseResources() {
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.getAndSet(null);
         if (dataConsumer != null) {
             dataConsumer.releaseResources();
         }
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/BasicResponseConsumer.java
index 1aa31b8..2501985 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/BasicResponseConsumer.java
@@ -29,8 +29,10 @@ package org.apache.hc.core5.http.nio;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
@@ -48,12 +50,23 @@ import org.apache.hc.core5.util.Args;
  */
 public class BasicResponseConsumer<T> implements AsyncResponseConsumer<Message<HttpResponse, T>> {
 
-    private final AsyncEntityConsumer<T> dataConsumer;
+    private final Supplier<AsyncEntityConsumer<T>> dataConsumerSupplier;
+    private final AtomicReference<AsyncEntityConsumer<T>> dataConsumerRef;
 
-    private volatile Message<HttpResponse, T> result;
+    public BasicResponseConsumer(final Supplier<AsyncEntityConsumer<T>> dataConsumerSupplier) {
+        this.dataConsumerSupplier = Args.notNull(dataConsumerSupplier, "Data consumer supplier");
+        this.dataConsumerRef = new AtomicReference<>(null);
+    }
 
     public BasicResponseConsumer(final AsyncEntityConsumer<T> dataConsumer) {
-        this.dataConsumer = Args.notNull(dataConsumer, "Consumer");
+        this(new Supplier<AsyncEntityConsumer<T>>() {
+
+            @Override
+            public AsyncEntityConsumer<T> get() {
+                return dataConsumer;
+            }
+
+        });
     }
 
     @Override
@@ -64,15 +77,19 @@ public class BasicResponseConsumer<T> implements AsyncResponseConsumer<Message<H
         Args.notNull(response, "Response");
 
         if (entityDetails != null) {
+            final AsyncEntityConsumer<T> dataConsumer = dataConsumerSupplier.get();
+            if (dataConsumer == null) {
+                throw new HttpException("Supplied data consumer is null");
+            }
+            dataConsumerRef.set(dataConsumer);
             dataConsumer.streamStart(entityDetails, new FutureCallback<T>() {
 
                 @Override
                 public void completed(final T body) {
-                    result = new Message<>(response, body);
+                    final Message<HttpResponse, T> result = new Message<>(response, body);
                     if (resultCallback != null) {
                         resultCallback.completed(result);
                     }
-                    dataConsumer.releaseResources();
                 }
 
                 @Override
@@ -91,11 +108,10 @@ public class BasicResponseConsumer<T> implements AsyncResponseConsumer<Message<H
 
             });
         } else {
-            result = new Message<>(response, null);
+            final Message<HttpResponse, T> result = new Message<>(response, null);
             if (resultCallback != null) {
                 resultCallback.completed(result);
             }
-            dataConsumer.releaseResources();
         }
     }
 
@@ -105,16 +121,19 @@ public class BasicResponseConsumer<T> implements AsyncResponseConsumer<Message<H
 
     @Override
     public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.get();
         dataConsumer.updateCapacity(capacityChannel);
     }
 
     @Override
     public void consume(final ByteBuffer src) throws IOException {
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.get();
         dataConsumer.consume(src);
     }
 
     @Override
     public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.get();
         dataConsumer.streamEnd(trailers);
     }
 
@@ -124,13 +143,11 @@ public class BasicResponseConsumer<T> implements AsyncResponseConsumer<Message<H
     }
 
     @Override
-    public Message<HttpResponse, T> getResult() {
-        return result;
-    }
-
-    @Override
     public void releaseResources() {
-        dataConsumer.releaseResources();
+        final AsyncEntityConsumer<T> dataConsumer = dataConsumerRef.getAndSet(null);
+        if (dataConsumer != null) {
+            dataConsumer.releaseResources();
+        }
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncRequesterConsumer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncRequesterConsumer.java
index 3864a08..da6b861 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncRequesterConsumer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncRequesterConsumer.java
@@ -30,8 +30,10 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
@@ -54,13 +56,23 @@ import org.apache.hc.core5.util.Args;
  */
 public abstract class AbstractAsyncRequesterConsumer<T, E> implements AsyncRequestConsumer<T> {
 
-    private final AsyncEntityConsumer<E> entityConsumer;
+    private final Supplier<AsyncEntityConsumer<E>> dataConsumerSupplier;
+    private final AtomicReference<AsyncEntityConsumer<E>> dataConsumerRef;
 
-    private volatile T result;
+    public AbstractAsyncRequesterConsumer(final Supplier<AsyncEntityConsumer<E>> dataConsumerSupplier) {
+        this.dataConsumerSupplier = Args.notNull(dataConsumerSupplier, "Data consumer supplier");
+        this.dataConsumerRef = new AtomicReference<>(null);
+    }
+
+    public AbstractAsyncRequesterConsumer(final AsyncEntityConsumer<E> dataConsumer) {
+        this(new Supplier<AsyncEntityConsumer<E>>() {
 
-    public AbstractAsyncRequesterConsumer(final AsyncEntityConsumer<E> entityConsumer) {
-        Args.notNull(entityConsumer, "Entity consumer");
-        this.entityConsumer = entityConsumer;
+            @Override
+            public AsyncEntityConsumer<E> get() {
+                return dataConsumer;
+            }
+
+        });
     }
 
     /**
@@ -78,14 +90,19 @@ public abstract class AbstractAsyncRequesterConsumer<T, E> implements AsyncReque
             final EntityDetails entityDetails,
             final HttpContext httpContext, final FutureCallback<T> resultCallback) throws HttpException, IOException {
         if (entityDetails != null) {
-            entityConsumer.streamStart(entityDetails, new FutureCallback<E>() {
+            final AsyncEntityConsumer<E> dataConsumer = dataConsumerSupplier.get();
+            if (dataConsumer == null) {
+                throw new HttpException("Supplied data consumer is null");
+            }
+            dataConsumerRef.set(dataConsumer);
+            dataConsumer.streamStart(entityDetails, new FutureCallback<E>() {
 
                 @Override
                 public void completed(final E entity) {
                     final ContentType contentType;
                     try {
                         contentType = ContentType.parse(entityDetails.getContentType());
-                        result = buildResult(request, entity, contentType);
+                        final T result = buildResult(request, entity, contentType);
                         resultCallback.completed(result);
                     } catch (final UnsupportedCharsetException ex) {
                         resultCallback.failed(ex);
@@ -105,29 +122,26 @@ public abstract class AbstractAsyncRequesterConsumer<T, E> implements AsyncReque
             });
         } else {
             resultCallback.completed(buildResult(request, null, null));
-            entityConsumer.releaseResources();
         }
 
     }
 
     @Override
     public final void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
-        entityConsumer.updateCapacity(capacityChannel);
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.get();
+        dataConsumer.updateCapacity(capacityChannel);
     }
 
     @Override
     public final void consume(final ByteBuffer src) throws IOException {
-        entityConsumer.consume(src);
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.get();
+        dataConsumer.consume(src);
     }
 
     @Override
     public final void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
-        entityConsumer.streamEnd(trailers);
-    }
-
-    @Override
-    public T getResult() {
-        return result;
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.get();
+        dataConsumer.streamEnd(trailers);
     }
 
     @Override
@@ -137,7 +151,10 @@ public abstract class AbstractAsyncRequesterConsumer<T, E> implements AsyncReque
 
     @Override
     public final void releaseResources() {
-        entityConsumer.releaseResources();
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.getAndSet(null);
+        if (dataConsumer != null) {
+            dataConsumer.releaseResources();
+        }
     }
 
 }
\ No newline at end of file
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncResponseConsumer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncResponseConsumer.java
index 0472f8f..9012ee2 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncResponseConsumer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncResponseConsumer.java
@@ -33,6 +33,7 @@ import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
@@ -55,15 +56,23 @@ import org.apache.hc.core5.util.Args;
  */
 public abstract class AbstractAsyncResponseConsumer<T, E> implements AsyncResponseConsumer<T> {
 
-    private final AsyncEntityConsumer<E> entityConsumer;
-    private final AtomicReference<T> resultRef;
-    private final AtomicReference<Exception> exceptionRef;
+    private final Supplier<AsyncEntityConsumer<E>> dataConsumerSupplier;
+    private final AtomicReference<AsyncEntityConsumer<E>> dataConsumerRef;
 
-    public AbstractAsyncResponseConsumer(final AsyncEntityConsumer<E> entityConsumer) {
-        Args.notNull(entityConsumer, "Entity consumer");
-        this.entityConsumer = entityConsumer;
-        this.resultRef = new AtomicReference<>(null);
-        this.exceptionRef = new AtomicReference<>(null);
+    public AbstractAsyncResponseConsumer(final Supplier<AsyncEntityConsumer<E>> dataConsumerSupplier) {
+        this.dataConsumerSupplier = Args.notNull(dataConsumerSupplier, "Data consumer supplier");
+        this.dataConsumerRef = new AtomicReference<>(null);
+    }
+
+    public AbstractAsyncResponseConsumer(final AsyncEntityConsumer<E> dataConsumer) {
+        this(new Supplier<AsyncEntityConsumer<E>>() {
+
+            @Override
+            public AsyncEntityConsumer<E> get() {
+                return dataConsumer;
+            }
+
+        });
     }
 
     /**
@@ -81,7 +90,12 @@ public abstract class AbstractAsyncResponseConsumer<T, E> implements AsyncRespon
             final EntityDetails entityDetails,
             final HttpContext httpContext, final FutureCallback<T> resultCallback) throws HttpException, IOException {
         if (entityDetails != null) {
-            entityConsumer.streamStart(entityDetails, new FutureCallback<E>() {
+            final AsyncEntityConsumer<E> dataConsumer = dataConsumerSupplier.get();
+            if (dataConsumer == null) {
+                throw new HttpException("Supplied data consumer is null");
+            }
+            dataConsumerRef.set(dataConsumer);
+            dataConsumer.streamStart(entityDetails, new FutureCallback<E>() {
 
                 @Override
                 public void completed(final E entity) {
@@ -89,12 +103,10 @@ public abstract class AbstractAsyncResponseConsumer<T, E> implements AsyncRespon
                     try {
                         contentType = ContentType.parse(entityDetails.getContentType());
                         final T result = buildResult(response, entity, contentType);
-                        resultRef.compareAndSet(null, result);
                         if (resultCallback != null) {
                             resultCallback.completed(result);
                         }
                     } catch (final UnsupportedCharsetException ex) {
-                        exceptionRef.compareAndSet(null, ex);
                         if (resultCallback != null) {
                             resultCallback.failed(ex);
                         }
@@ -103,7 +115,6 @@ public abstract class AbstractAsyncResponseConsumer<T, E> implements AsyncRespon
 
                 @Override
                 public void failed(final Exception ex) {
-                    exceptionRef.compareAndSet(null, ex);
                     if (resultCallback != null) {
                         resultCallback.failed(ex);
                     }
@@ -119,48 +130,42 @@ public abstract class AbstractAsyncResponseConsumer<T, E> implements AsyncRespon
             });
         } else {
             final T result = buildResult(response, null, null);
-            resultRef.compareAndSet(null, result);
             if (resultCallback != null) {
                 resultCallback.completed(result);
             }
-            entityConsumer.releaseResources();
         }
 
     }
 
     @Override
     public final void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
-        entityConsumer.updateCapacity(capacityChannel);
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.get();
+        dataConsumer.updateCapacity(capacityChannel);
     }
 
     @Override
     public final void consume(final ByteBuffer src) throws IOException {
-        entityConsumer.consume(src);
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.get();
+        dataConsumer.consume(src);
     }
 
     @Override
     public final void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
-        entityConsumer.streamEnd(trailers);
-    }
-
-    @Override
-    public T getResult() {
-        return resultRef.get();
-    }
-
-    public Exception getException() {
-        return exceptionRef.get();
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.get();
+        dataConsumer.streamEnd(trailers);
     }
 
     @Override
     public final void failed(final Exception cause) {
-        exceptionRef.compareAndSet(null, cause);
         releaseResources();
     }
 
     @Override
     public final void releaseResources() {
-        entityConsumer.releaseResources();
+        final AsyncEntityConsumer<E> dataConsumer = dataConsumerRef.getAndSet(null);
+        if (dataConsumer != null) {
+            dataConsumer.releaseResources();
+        }
     }
 
 }
\ No newline at end of file


[httpcomponents-core] 02/06: Escape DEL character when tracing

Posted by ol...@apache.org.
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 8ddd7dcefbaec9af970ad948647154c73cbd2c4f
Author: dowy <11...@users.noreply.github.com>
AuthorDate: Thu May 30 11:58:40 2019 +0200

    Escape DEL character when tracing
    
    DEL characters should be converted to [0x7f] in Wire traces otherwise they are difficult to see in logs.
---
 .../src/main/java/org/apache/hc/core5/testing/classic/Wire.java         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java
index 6f20a4b..55045cb 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/Wire.java
@@ -54,7 +54,7 @@ public class Wire {
                 buffer.insert(0, header);
                 this.log.debug(this.id + " " + buffer.toString());
                 buffer.setLength(0);
-            } else if ((ch < 32) || (ch > 127)) {
+            } else if ((ch < 32) || (ch >= 127)) {
                 buffer.append("[0x");
                 buffer.append(Integer.toHexString(ch));
                 buffer.append("]");


[httpcomponents-core] 06/06: Fixed parameter inconsistency in server side push APIs

Posted by ol...@apache.org.
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 1a3aff635fa20101373412d1b56ae1b4bd96de1f
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Fri May 31 19:45:16 2019 +0200

    Fixed parameter inconsistency in server side push APIs
---
 .../org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java  | 2 +-
 .../apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java  | 2 +-
 .../org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java   | 2 +-
 .../src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java   | 4 ++--
 .../hc/core5/http/nio/support/AbstractServerExchangeHandler.java      | 2 +-
 .../nio/support/AsyncServerFilterChainExchangeHandlerFactory.java     | 2 +-
 .../apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java   | 2 +-
 7 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java
index 6e5c7ec..70f02fb 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java
@@ -227,7 +227,7 @@ public class ServerHttp2StreamHandler implements Http2StreamHandler {
 
                     @Override
                     public void pushPromise(
-                            final HttpRequest promise, final HttpContext httpContext, final AsyncPushProducer pushProducer) throws HttpException, IOException {
+                            final HttpRequest promise, final AsyncPushProducer pushProducer, final HttpContext httpContext) throws HttpException, IOException {
                         commitPromise(promise, pushProducer);
                     }
 
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java
index 9af9c34..374441e 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java
@@ -215,7 +215,7 @@ class ServerPushHttp2StreamHandler implements Http2StreamHandler {
 
                     @Override
                     public void pushPromise(
-                            final HttpRequest promise, final HttpContext httpContext, final AsyncPushProducer pushProducer) throws HttpException, IOException {
+                            final HttpRequest promise, final AsyncPushProducer pushProducer, final HttpContext httpContext) throws HttpException, IOException {
                         commitPromise(promise, pushProducer);
                     }
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
index 12c986d..b9f8146 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
@@ -237,7 +237,7 @@ class ServerHttp1StreamHandler implements ResourceHolder {
 
             @Override
             public void pushPromise(
-                    final HttpRequest promise, final HttpContext httpContext, final AsyncPushProducer pushProducer) throws HttpException, IOException {
+                    final HttpRequest promise, final AsyncPushProducer pushProducer, final HttpContext httpContext) throws HttpException, IOException {
                 commitPromise();
             }
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java
index c18a8e6..930f20e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java
@@ -71,9 +71,9 @@ public interface ResponseChannel {
      * a response message.
      *
      * @param promise the request message header used as a promise.
-     * @param context the actual execution context.
      * @param responseProducer the push response message producer.
+     * @param context the actual execution context.
      */
-    void pushPromise(HttpRequest promise, HttpContext context, AsyncPushProducer responseProducer) throws HttpException, IOException;
+    void pushPromise(HttpRequest promise, AsyncPushProducer responseProducer, HttpContext context) throws HttpException, IOException;
 
 }
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 160182e..0e2c3c4 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
@@ -121,7 +121,7 @@ public abstract class AbstractServerExchangeHandler<T> implements AsyncServerExc
             @Override
             public void pushPromise(
                     final HttpRequest promise, final HttpContext httpContext, final AsyncPushProducer pushProducer) throws HttpException, IOException {
-                responseChannel.pushPromise(promise, httpContext, pushProducer);
+                responseChannel.pushPromise(promise, pushProducer, httpContext);
             }
 
             @Override
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 216426e..faaa6ff 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
@@ -97,7 +97,7 @@ public final class AsyncServerFilterChainExchangeHandlerFactory implements Handl
 
                     @Override
                     public void pushPromise(final HttpRequest promise, final AsyncPushProducer responseProducer) throws HttpException, IOException {
-                        responseChannel.pushPromise(promise, context, responseProducer);
+                        responseChannel.pushPromise(promise, responseProducer, context);
                     }
 
                 }));
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
index 04ba5c3..3ce1196 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
@@ -140,7 +140,7 @@ public final class TerminalAsyncServerFilter implements AsyncFilterHandler {
                 }
 
                 @Override
-                public void pushPromise(final HttpRequest promise, final HttpContext httpContext, final AsyncPushProducer pushProducer) throws HttpException, IOException {
+                public void pushPromise(final HttpRequest promise, final AsyncPushProducer pushProducer, final HttpContext httpContext) throws HttpException, IOException {
                     responseTrigger.pushPromise(promise, pushProducer);
                 }
 


[httpcomponents-core] 04/06: Improved classic and async entity factory methods

Posted by ol...@apache.org.
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 0e96b7d8940ddbb850cc9fa6c3599afb6f53720b
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue May 28 11:10:28 2019 +0200

    Improved classic and async entity factory methods
---
 .../examples/Http2FullDuplexClientExample.java     |   5 +-
 .../core5/testing/nio/Http1AuthenticationTest.java |  12 +-
 .../hc/core5/testing/nio/Http1IntegrationTest.java |  30 +--
 .../hc/core5/testing/nio/Http2IntegrationTest.java |  12 +-
 .../testing/nio/SingleLineResponseHandler.java     |   4 +-
 .../hc/core5/http/io/entity/EntityTemplate.java    |  12 +-
 .../hc/core5/http/io/entity/EntityUtils.java       |   2 +-
 .../hc/core5/http/io/entity/HttpEntities.java      | 224 ++++++++++++++++++++
 .../hc/core5/http/io/entity/HttpEntityWrapper.java |   8 +-
 .../hc/core5/http/nio/BasicResponseProducer.java   |   4 +-
 .../entity/AsyncEntityProducerWrapper.java}        |  74 +++----
 .../http/nio/entity/AsyncEntityProducers.java      | 235 +++++++++++++++++++++
 .../nio/support/AbstractAsyncServerAuthFilter.java |   4 +-
 .../support/ImmediateResponseExchangeHandler.java  |   5 +-
 .../nio/support/TerminalAsyncServerFilter.java     |   4 +-
 .../IOCallback.java}                               |  11 +-
 .../org/apache/hc/core5/net/URLEncodedUtils.java   |   5 -
 .../examples/AsyncFullDuplexClientExample.java     |   5 +-
 .../http/examples/AsyncServerFilterExample.java    |  11 +-
 .../http/examples/ClassicPostExecutionExample.java |  34 +--
 .../ClassicPostWithTrailersExecutionExample.java   |  78 -------
 .../hc/core5/http/io/entity/TestEntityUtils.java   |   2 +-
 .../hc/core5/http/message/TestMessageSupport.java  |  10 +-
 .../http/protocol/TestStandardInterceptors.java    |   6 +-
 24 files changed, 577 insertions(+), 220 deletions(-)

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 5810a44..fcf2ce1 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
@@ -33,7 +33,6 @@ import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpConnection;
@@ -47,7 +46,7 @@ import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 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.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
@@ -126,7 +125,7 @@ public class Http2FullDuplexClientExample {
 
         final URI requestUri = new URI("http://nghttp2.org/httpbin/post");
         final BasicRequestProducer requestProducer = new BasicRequestProducer(
-                Methods.POST.name(), requestUri, new BasicAsyncEntityProducer("stuff", ContentType.TEXT_PLAIN));
+                Methods.POST.name(), requestUri, AsyncEntityProducers.create("stuff"));
         final BasicResponseConsumer<String> responseConsumer = new BasicResponseConsumer<>(
                 new StringAsyncEntityConsumer());
 
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 b9a47f4..61d9dfe 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
@@ -55,7 +55,7 @@ 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.entity.BasicAsyncEntityProducer;
+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.protocol.HttpContext;
@@ -145,7 +145,7 @@ public class Http1AuthenticationTest {
 
                         @Override
                         protected AsyncEntityProducer generateResponseContent(final HttpResponse unauthorized) {
-                            return new BasicAsyncEntityProducer("You shall not pass!!!");
+                            return AsyncEntityProducers.create("You shall not pass!!!");
                         }
                     })
                     .setIOSessionListener(LoggingIOSessionListener.INSTANCE)
@@ -251,7 +251,7 @@ public class Http1AuthenticationTest {
         }
         final HttpRequest request1 = new BasicHttpRequest(Methods.POST, target, "/stuff");
         final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
-                new BasicRequestProducer(request1, new BasicAsyncEntityProducer(stuff, ContentType.TEXT_PLAIN)),
+                new BasicRequestProducer(request1, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
         Assert.assertThat(message1, CoreMatchers.notNullValue());
@@ -263,7 +263,7 @@ public class Http1AuthenticationTest {
         final HttpRequest request2 = new BasicHttpRequest(Methods.POST, target, "/stuff");
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
         final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
-                new BasicRequestProducer(request2, new BasicAsyncEntityProducer(stuff, ContentType.TEXT_PLAIN)),
+                new BasicRequestProducer(request2, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
         Assert.assertThat(message2, CoreMatchers.notNullValue());
@@ -291,7 +291,7 @@ public class Http1AuthenticationTest {
         final HttpRequest request1 = new BasicHttpRequest(Methods.POST, target, "/stuff");
         request1.setVersion(HttpVersion.HTTP_1_0);
         final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
-                new BasicRequestProducer(request1, new BasicAsyncEntityProducer(stuff, ContentType.TEXT_PLAIN)),
+                new BasicRequestProducer(request1, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
         Assert.assertThat(message1, CoreMatchers.notNullValue());
@@ -304,7 +304,7 @@ public class Http1AuthenticationTest {
         request2.setVersion(HttpVersion.HTTP_1_0);
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
         final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
-                new BasicRequestProducer(request2, new BasicAsyncEntityProducer(stuff, ContentType.TEXT_PLAIN)),
+                new BasicRequestProducer(request2, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
         Assert.assertThat(message2, CoreMatchers.notNullValue());
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 2020c14..c633ded 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
@@ -106,7 +106,7 @@ import org.apache.hc.core5.http.nio.NHttpMessageParser;
 import org.apache.hc.core5.http.nio.NHttpMessageWriter;
 import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.nio.SessionOutputBuffer;
-import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.DigestingEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.DigestingEntityProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
@@ -401,7 +401,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
         for (int i = 0; i < 5; i++) {
             final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
                     new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello"),
-                            new BasicAsyncEntityProducer("Hi there")),
+                            AsyncEntityProducers.create("Hi there")),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
             Assert.assertNotNull(result);
@@ -434,7 +434,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
         for (int i = 0; i < 5; i++) {
             queue.add(streamEndpoint.execute(
                     new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello"),
-                            new BasicAsyncEntityProducer("Hi there")),
+                            AsyncEntityProducers.create("Hi there")),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null));
         }
         while (!queue.isEmpty()) {
@@ -470,7 +470,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
             final HttpRequest request = new BasicHttpRequest(Methods.POST, createRequestURI(serverEndpoint, "/hello"));
             request.setVersion(HttpVersion.HTTP_1_0);
             final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
-                    new BasicRequestProducer(request, new BasicAsyncEntityProducer("Hi there")),
+                    new BasicRequestProducer(request, AsyncEntityProducers.create("Hi there")),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
             Assert.assertNotNull(result);
@@ -571,7 +571,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
         for (int i = 0; i < 2; i++) {
             queue.add(streamEndpoint.execute(
                     new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/"),
-                            new BasicAsyncEntityProducer("Hi there")),
+                            AsyncEntityProducers.create("Hi there")),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null));
         }
         while (!queue.isEmpty()) {
@@ -785,7 +785,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
 
         final HttpRequest request4 = new BasicHttpRequest(Methods.POST, createRequestURI(serverEndpoint, "/echo"));
         final Future<Message<HttpResponse, String>> future4 = streamEndpoint.execute(
-                new BasicRequestProducer(request4, new BasicAsyncEntityProducer("blah")),
+                new BasicRequestProducer(request4, AsyncEntityProducers.create("blah")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final Message<HttpResponse, String> result4 = future4.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
         Assert.assertNotNull(result4);
@@ -806,7 +806,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
                 return new AsyncServerExchangeHandler() {
 
                     private final Random random = new Random(System.currentTimeMillis());
-                    private final AsyncEntityProducer entityProducer = new BasicAsyncEntityProducer(
+                    private final AsyncEntityProducer entityProducer = AsyncEntityProducers.create(
                             "All is well");
 
                     @Override
@@ -889,7 +889,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
         for (int i = 0; i < 5; i++) {
             queue.add(streamEndpoint.execute(
                     new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/"),
-                            new BasicAsyncEntityProducer("Some important message")),
+                            AsyncEntityProducers.create("Some important message")),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null));
         }
         while (!queue.isEmpty()) {
@@ -1205,17 +1205,17 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
 
         final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
                 new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello-1"),
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final HttpRequest request2 = new BasicHttpRequest(Methods.POST, createRequestURI(serverEndpoint, "/hello-2"));
         request2.addHeader(HttpHeaders.CONNECTION, "close");
         final Future<Message<HttpResponse, String>> future2 = streamEndpoint.execute(
                 new BasicRequestProducer(request2,
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final Future<Message<HttpResponse, String>> future3 = streamEndpoint.execute(
                 new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello-3"),
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
 
         final Message<HttpResponse, String> result1 = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
@@ -1242,7 +1242,7 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
 
         final Future<Message<HttpResponse, String>> future4 = streamEndpoint.execute(
                 new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello-3"),
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         try {
             future4.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
@@ -1272,17 +1272,17 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
 
         final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
                 new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello-1"),
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final HttpRequest request2 = new BasicHttpRequest(Methods.POST, createRequestURI(serverEndpoint, "/hello-2"));
         request2.addHeader(HttpHeaders.HOST, "blah:blah");
         final Future<Message<HttpResponse, String>> future2 = streamEndpoint.execute(
                 new BasicRequestProducer(request2,
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final Future<Message<HttpResponse, String>> future3 = streamEndpoint.execute(
                 new BasicRequestProducer(Methods.POST, createRequestURI(serverEndpoint, "/hello-3"),
-                        new BasicAsyncEntityProducer("Hi there")),
+                        AsyncEntityProducers.create("Hi there")),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
 
         final Message<HttpResponse, String> result1 = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
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 d7fc2a6..0403259 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
@@ -94,7 +94,7 @@ import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.HandlerFactory;
 import org.apache.hc.core5.http.nio.ResponseChannel;
-import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.DigestingEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.DigestingEntityProducer;
 import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
@@ -594,7 +594,7 @@ public class Http2IntegrationTest extends InternalHttp2ServerTestBase {
                                 context, new BasicPushProducer(new MultiLineEntityProducer("Pushing lots of stuff", 500)));
                         responseTrigger.submitResponse(new BasicResponseProducer(
                                 HttpStatus.SC_OK,
-                                new BasicAsyncEntityProducer("Hi there")), context);
+                                AsyncEntityProducers.create("Hi there")), context);
                     }
                 };
             }
@@ -674,7 +674,7 @@ public class Http2IntegrationTest extends InternalHttp2ServerTestBase {
 
                         responseTrigger.pushPromise(
                                 new BasicHttpRequest(Methods.GET, createRequestURI(serverEndpoint, "/stuff")),
-                                context, new BasicPushProducer(new BasicAsyncEntityProducer("Pushing all sorts of stuff")) {
+                                context, new BasicPushProducer(AsyncEntityProducers.create("Pushing all sorts of stuff")) {
 
                             @Override
                             public void failed(final Exception cause) {
@@ -694,9 +694,9 @@ public class Http2IntegrationTest extends InternalHttp2ServerTestBase {
                             }
 
                         });
-                        responseTrigger.submitResponse(new BasicResponseProducer(
-                                HttpStatus.SC_OK,
-                                new BasicAsyncEntityProducer("Hi there")), context);
+                        responseTrigger.submitResponse(
+                                new BasicResponseProducer(HttpStatus.SC_OK, AsyncEntityProducers.create("Hi there")),
+                                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 9ecc6af..5282a3a 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
@@ -37,7 +37,7 @@ 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.BasicAsyncEntityProducer;
+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.BasicServerExchangeHandler;
 import org.apache.hc.core5.http.protocol.HttpContext;
@@ -61,7 +61,7 @@ public class SingleLineResponseHandler extends BasicServerExchangeHandler<Messag
                           final ResponseTrigger responseTrigger,
                           final HttpContext context) throws HttpException, IOException {
                       responseTrigger.submitResponse(new BasicResponseProducer(
-                              HttpStatus.SC_OK, new BasicAsyncEntityProducer(message)), context);
+                              HttpStatus.SC_OK, AsyncEntityProducers.create(message)), context);
                   }
               }
         );
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityTemplate.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityTemplate.java
index c76fcd9..2abfa15 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityTemplate.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityTemplate.java
@@ -36,10 +36,12 @@ import java.io.OutputStream;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.io.IOCallback;
 import org.apache.hc.core5.util.Args;
 
 /**
- * Entity that delegates the process of content generation to a {@link HttpContentProducer}.
+ * Entity that delegates the process of content generation to a {@link IOCallback}
+ * with {@link OutputStream} as output sink.
  *
  * @since 4.0
  */
@@ -47,14 +49,14 @@ import org.apache.hc.core5.util.Args;
 public final class EntityTemplate extends AbstractHttpEntity {
 
     private final long contentLength;
-    private final HttpContentProducer contentProducer;
+    private final IOCallback<OutputStream> callback;
 
     public EntityTemplate(
             final long contentLength, final ContentType contentType, final String contentEncoding,
-            final HttpContentProducer contentProducer) {
+            final IOCallback<OutputStream> callback) {
         super(contentType, contentEncoding);
         this.contentLength = contentLength;
-        this.contentProducer = Args.notNull(contentProducer, "Content producer");
+        this.callback = Args.notNull(callback, "I/O callback");
     }
 
     @Override
@@ -77,7 +79,7 @@ public final class EntityTemplate extends AbstractHttpEntity {
     @Override
     public void writeTo(final OutputStream outStream) throws IOException {
         Args.notNull(outStream, "Output stream");
-        this.contentProducer.writeTo(outStream);
+        this.callback.execute(outStream);
     }
 
     @Override
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityUtils.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityUtils.java
index 5dd89da..ca37f5f 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityUtils.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/EntityUtils.java
@@ -244,7 +244,7 @@ public final class EntityUtils {
     public static List<NameValuePair> parse(final HttpEntity entity) throws IOException {
         Args.notNull(entity, "HTTP entity");
         final ContentType contentType = ContentType.parse(entity.getContentType());
-        if (contentType == null || !contentType.getMimeType().equalsIgnoreCase(URLEncodedUtils.CONTENT_TYPE)) {
+        if (!ContentType.APPLICATION_FORM_URLENCODED.isSameMimeType(contentType)) {
             return Collections.emptyList();
         }
         final long len = entity.getContentLength();
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntities.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntities.java
new file mode 100644
index 0000000..5f5a29f
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntities.java
@@ -0,0 +1,224 @@
+/*
+ * ====================================================================
+ * 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.entity;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.hc.core5.function.Supplier;
+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.NameValuePair;
+import org.apache.hc.core5.io.IOCallback;
+import org.apache.hc.core5.net.URLEncodedUtils;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * {HttpEntity} factory methods.
+ *
+ * @since 5.0
+ */
+public final class HttpEntities {
+
+    private HttpEntities() {
+    }
+
+    public static HttpEntity create(final String content, final ContentType contentType) {
+        return new StringEntity(content, contentType);
+    }
+
+    public static HttpEntity create(final String content, final Charset charset) {
+        return new StringEntity(content, ContentType.TEXT_PLAIN.withCharset(charset));
+    }
+
+    public static HttpEntity create(final String content) {
+        return new StringEntity(content, ContentType.TEXT_PLAIN);
+    }
+
+    public static HttpEntity create(final byte[] content, final ContentType contentType) {
+        return new ByteArrayEntity(content, contentType);
+    }
+
+    public static HttpEntity create(final File content, final ContentType contentType) {
+        return new FileEntity(content, contentType);
+    }
+
+    public static HttpEntity create(final Serializable serializable, final ContentType contentType) {
+        return new SerializableEntity(serializable, contentType);
+    }
+
+    public static HttpEntity createUrlEncoded(
+            final Iterable <? extends NameValuePair> parameters, final Charset charset) {
+        final ContentType contentType = charset != null ?
+                ContentType.APPLICATION_FORM_URLENCODED.withCharset(charset) :
+                ContentType.APPLICATION_FORM_URLENCODED;
+        return create(URLEncodedUtils.format(parameters, contentType.getCharset()), contentType);
+    }
+
+    public static HttpEntity create(final IOCallback<OutputStream> callback, final ContentType contentType) {
+        return new EntityTemplate(-1, contentType, null, callback);
+    }
+
+    public static HttpEntity gzip(final HttpEntity entity) {
+        return new HttpEntityWrapper(entity) {
+
+            @Override
+            public String getContentEncoding() {
+                return "gzip";
+            }
+
+            @Override
+            public long getContentLength() {
+                return -1;
+            }
+
+            @Override
+            public InputStream getContent() throws IOException {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public void writeTo(final OutputStream outStream) throws IOException {
+                Args.notNull(outStream, "Output stream");
+                final GZIPOutputStream gzip = new GZIPOutputStream(outStream);
+                super.writeTo(gzip);
+                // Only close output stream if the wrapped entity has been
+                // successfully written out
+                gzip.close();
+            }
+
+        };
+    }
+
+    public static HttpEntity createGzipped(final String content, final ContentType contentType) {
+        return gzip(create(content, contentType));
+    }
+
+    public static HttpEntity createGzipped(final String content, final Charset charset) {
+        return gzip(create(content, charset));
+    }
+
+    public static HttpEntity createGzipped(final String content) {
+        return gzip(create(content));
+    }
+
+    public static HttpEntity createGzipped(final byte[] content, final ContentType contentType) {
+        return gzip(create(content, contentType));
+    }
+
+    public static HttpEntity createGzipped(final File content, final ContentType contentType) {
+        return gzip(create(content, contentType));
+    }
+
+    public static HttpEntity createGzipped(final Serializable serializable, final ContentType contentType) {
+        return gzip(create(serializable, contentType));
+    }
+
+    public static HttpEntity createGzipped(final IOCallback<OutputStream> callback, final ContentType contentType) {
+        return gzip(create(callback, contentType));
+    }
+
+    public static HttpEntity withTrailers(final HttpEntity entity, final Header... trailers) {
+        return new HttpEntityWrapper(entity) {
+
+            @Override
+            public boolean isChunked() {
+                // Must be chunk coded
+                return true;
+            }
+
+            @Override
+            public long getContentLength() {
+                return -1;
+            }
+
+            @Override
+            public Supplier<List<? extends Header>> getTrailers() {
+                return new Supplier<List<? extends Header>>() {
+
+                    @Override
+                    public List<? extends Header> get() {
+                        return Arrays.asList(trailers);
+                    }
+
+                };
+            }
+
+            @Override
+            public Set<String> getTrailerNames() {
+                final Set<String> names = new LinkedHashSet<>();
+                for (final Header trailer: trailers) {
+                    names.add(trailer.getName());
+                }
+                return names;
+            }
+
+        };
+    }
+
+    public static HttpEntity create(final String content, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(content, contentType), trailers);
+    }
+
+    public static HttpEntity create(final String content, final Charset charset, final Header... trailers) {
+        return withTrailers(create(content, charset), trailers);
+    }
+
+    public static HttpEntity create(final String content, final Header... trailers) {
+        return withTrailers(create(content), trailers);
+    }
+
+    public static HttpEntity create(final byte[] content, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(content, contentType), trailers);
+    }
+
+    public static HttpEntity create(final File content, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(content, contentType), trailers);
+    }
+
+    public static HttpEntity create(
+            final Serializable serializable, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(serializable, contentType), trailers);
+    }
+
+    public static HttpEntity create(
+            final IOCallback<OutputStream> callback, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(callback, contentType), trailers);
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java
index a3ede51..4873eaf 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java
@@ -41,10 +41,8 @@ import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.util.Args;
 
 /**
- * Base class for wrapping entities.
- * Keeps a {@link #wrappedEntity wrappedEntity} and delegates all
- * calls to it. Implementations of wrapping entities can derive
- * from this class and need to override only those methods that
+ * Base class for wrapping entities that delegates all calls to the wrapped entity.
+ * Implementations can derive from this class and override only those methods that
  * should not be delegated to the wrapped entity.
  *
  * @since 4.0
@@ -124,7 +122,7 @@ public class HttpEntityWrapper implements HttpEntity {
 
     @Override
     public String toString() {
-        return super.toString() + "[" + wrappedEntity + "]";
+        return "Wrapper [" + wrappedEntity + "]";
     }
 
 }
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/BasicResponseProducer.java
index c98b9ee..087ebae 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/BasicResponseProducer.java
@@ -33,7 +33,7 @@ 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.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 
@@ -63,7 +63,7 @@ public class BasicResponseProducer implements AsyncResponseProducer {
     }
 
     public BasicResponseProducer(final HttpResponse response, final String message, final ContentType contentType) {
-        this(response, new BasicAsyncEntityProducer(message, contentType));
+        this(response, AsyncEntityProducers.create(message, contentType));
     }
 
     public BasicResponseProducer(final HttpResponse response, final String message) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducerWrapper.java
similarity index 52%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java
rename to httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducerWrapper.java
index 4775451..834669d 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducerWrapper.java
@@ -25,107 +25,87 @@
  *
  */
 
-package org.apache.hc.core5.http.io.entity;
+package org.apache.hc.core5.http.nio.entity;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Set;
 
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.function.Supplier;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.util.Args;
 
 /**
- * Wrapping entity that also includes trailers.
+ * Base class for wrapping entity producers that delegates all calls to the wrapped producer.
+ * Implementations can derive from this class and override only those methods that
+ * should not be delegated to the wrapped producer.
  *
  * @since 5.0
  */
 @Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
-public class HttpEntityWithTrailers implements HttpEntity {
+public class AsyncEntityProducerWrapper implements AsyncEntityProducer {
 
-    private final HttpEntity wrappedEntity;
-    private final List<Header> trailers;
+    private final AsyncEntityProducer wrappedEntityProducer;
 
-    /**
-     * Creates a new entity wrapper.
-     */
-    public HttpEntityWithTrailers(final HttpEntity wrappedEntity, final Header... trailers) {
+    public AsyncEntityProducerWrapper(final AsyncEntityProducer wrappedEntityProducer) {
         super();
-        this.wrappedEntity = Args.notNull(wrappedEntity, "Wrapped entity");
-        this.trailers = Arrays.asList(trailers);
+        this.wrappedEntityProducer = Args.notNull(wrappedEntityProducer, "Wrapped entity producer");
     }
 
     @Override
     public boolean isRepeatable() {
-        return wrappedEntity.isRepeatable();
+        return wrappedEntityProducer.isRepeatable();
     }
 
     @Override
     public boolean isChunked() {
-        return true;
+        return wrappedEntityProducer.isChunked();
     }
 
     @Override
     public long getContentLength() {
-        return wrappedEntity.getContentLength();
+        return wrappedEntityProducer.getContentLength();
     }
 
     @Override
     public String getContentType() {
-        return wrappedEntity.getContentType();
+        return wrappedEntityProducer.getContentType();
     }
 
     @Override
     public String getContentEncoding() {
-        return wrappedEntity.getContentEncoding();
+        return wrappedEntityProducer.getContentEncoding();
     }
 
     @Override
-    public InputStream getContent()
-        throws IOException {
-        return wrappedEntity.getContent();
+    public Set<String> getTrailerNames() {
+        return wrappedEntityProducer.getTrailerNames();
     }
 
     @Override
-    public void writeTo(final OutputStream outStream)
-        throws IOException {
-        wrappedEntity.writeTo(outStream);
+    public int available() {
+        return wrappedEntityProducer.available();
     }
 
     @Override
-    public boolean isStreaming() {
-        return wrappedEntity.isStreaming();
+    public void produce(final DataStreamChannel channel) throws IOException {
+        wrappedEntityProducer.produce(channel);
     }
 
     @Override
-    public Supplier<List<? extends Header>> getTrailers() {
-        return new Supplier<List<? extends Header>>() {
-            @Override
-            public List<? extends Header> get() {
-                return trailers;
-            }
-        };
+    public void failed(final Exception cause) {
+        wrappedEntityProducer.failed(cause);
     }
 
     @Override
-    public Set<String> getTrailerNames() {
-        final Set<String> names = new LinkedHashSet<>();
-        for (final Header trailer: trailers) {
-            names.add(trailer.getName());
-        }
-        return names;
+    public void releaseResources() {
+        wrappedEntityProducer.releaseResources();
     }
 
     @Override
-    public void close() throws IOException {
-        wrappedEntity.close();
+    public String toString() {
+        return "Wrapper [" + wrappedEntityProducer + "]";
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducers.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducers.java
new file mode 100644
index 0000000..4fca51d
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AsyncEntityProducers.java
@@ -0,0 +1,235 @@
+/*
+ * ====================================================================
+ * 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.entity;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hc.core5.function.Callback;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.apache.hc.core5.http.nio.StreamChannel;
+import org.apache.hc.core5.net.URLEncodedUtils;
+
+/**
+ * {AsyncEntityProducer} factory methods.
+ *
+ * @since 5.0
+ */
+public final class AsyncEntityProducers {
+
+    private AsyncEntityProducers() {
+    }
+
+    public static AsyncEntityProducer create(final String content, final ContentType contentType) {
+        return new BasicAsyncEntityProducer(content, contentType);
+    }
+
+    public static AsyncEntityProducer create(final String content, final Charset charset) {
+        return new BasicAsyncEntityProducer(content, ContentType.TEXT_PLAIN.withCharset(charset));
+    }
+
+    public static AsyncEntityProducer create(final String content) {
+        return new BasicAsyncEntityProducer(content, ContentType.TEXT_PLAIN);
+    }
+
+    public static AsyncEntityProducer create(final byte[] content, final ContentType contentType) {
+        return new BasicAsyncEntityProducer(content, contentType);
+    }
+
+    public static AsyncEntityProducer create(final File content, final ContentType contentType) {
+        return new FileEntityProducer(content, contentType);
+    }
+
+    public static AsyncEntityProducer createUrlEncoded(
+            final Iterable <? extends NameValuePair> parameters, final Charset charset) {
+        final ContentType contentType = charset != null ?
+                ContentType.APPLICATION_FORM_URLENCODED.withCharset(charset) :
+                ContentType.APPLICATION_FORM_URLENCODED;
+        return create(URLEncodedUtils.format(parameters, contentType.getCharset()), contentType);
+    }
+
+    public static AsyncEntityProducer createBinary(
+            final Callback<StreamChannel<ByteBuffer>> callback,
+            final ContentType contentType) {
+        return new AbstractBinAsyncEntityProducer(0, contentType) {
+
+            @Override
+            protected int availableData() {
+                return Integer.MAX_VALUE;
+            }
+
+            @Override
+            protected void produceData(final StreamChannel<ByteBuffer> channel) throws IOException {
+                callback.execute(channel);
+            }
+
+            @Override
+            public boolean isRepeatable() {
+                return false;
+            }
+
+            @Override
+            public void failed(final Exception cause) {
+            }
+
+        };
+    }
+
+    public static AsyncEntityProducer createText(
+            final Callback<StreamChannel<CharBuffer>> callback,
+            final ContentType contentType) {
+        return new AbstractCharAsyncEntityProducer(0, 4096, contentType) {
+
+            @Override
+            protected int availableData() {
+                return Integer.MAX_VALUE;
+            }
+
+            @Override
+            protected void produceData(final StreamChannel<CharBuffer> channel) throws IOException {
+                callback.execute(channel);
+            }
+
+            @Override
+            public boolean isRepeatable() {
+                return false;
+            }
+
+            @Override
+            public void failed(final Exception cause) {
+            }
+
+        };
+    }
+
+    public static AsyncEntityProducer withTrailers(final AsyncEntityProducer entity, final Header... trailers) {
+        return new AsyncEntityProducerWrapper(entity) {
+
+            @Override
+            public boolean isChunked() {
+                // Must be chunk coded
+                return true;
+            }
+
+            @Override
+            public long getContentLength() {
+                return -1;
+            }
+
+            @Override
+            public Set<String> getTrailerNames() {
+                final Set<String> names = new LinkedHashSet<>();
+                for (final Header trailer: trailers) {
+                    names.add(trailer.getName());
+                }
+                return names;
+            }
+
+            @Override
+            public void produce(final DataStreamChannel channel) throws IOException {
+                super.produce(new DataStreamChannel() {
+
+                    @Override
+                    public void requestOutput() {
+                        channel.requestOutput();
+                    }
+
+                    @Override
+                    public int write(final ByteBuffer src) throws IOException {
+                        return channel.write(src);
+                    }
+
+                    @Override
+                    public void endStream(final List<? extends Header> p) throws IOException {
+                        final List<Header> allTrailers;
+                        if (p != null && !p.isEmpty()) {
+                            allTrailers = new ArrayList<>(p);
+                            allTrailers.addAll(Arrays.asList(trailers));
+                        } else {
+                            allTrailers = Arrays.asList(trailers);
+                        }
+                        channel.endStream(allTrailers);
+                    }
+
+                    @Override
+                    public void endStream() throws IOException {
+                        channel.endStream();
+                    }
+
+                });
+            }
+        };
+    }
+
+    public static AsyncEntityProducer create(final String content, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(content, contentType), trailers);
+    }
+
+    public static AsyncEntityProducer create(final String content, final Charset charset, final Header... trailers) {
+        return withTrailers(create(content, charset), trailers);
+    }
+
+    public static AsyncEntityProducer create(final String content, final Header... trailers) {
+        return withTrailers(create(content), trailers);
+    }
+
+    public static AsyncEntityProducer create(final byte[] content, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(content, contentType), trailers);
+    }
+
+    public static AsyncEntityProducer create(final File content, final ContentType contentType, final Header... trailers) {
+        return withTrailers(create(content, contentType), trailers);
+    }
+
+    public static AsyncEntityProducer createBinary(
+            final Callback<StreamChannel<ByteBuffer>> callback,
+            final ContentType contentType,
+            final Header... trailers) {
+        return withTrailers(createBinary(callback, contentType), trailers);
+    }
+
+    public static AsyncEntityProducer createText(
+            final Callback<StreamChannel<CharBuffer>> callback,
+            final ContentType contentType,
+            final Header... trailers) {
+        return withTrailers(createText(callback, contentType), trailers);
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncServerAuthFilter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncServerAuthFilter.java
index 1ee3713..b056692 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncServerAuthFilter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractAsyncServerAuthFilter.java
@@ -47,7 +47,7 @@ import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.AsyncFilterChain;
 import org.apache.hc.core5.http.nio.AsyncFilterHandler;
 import org.apache.hc.core5.http.nio.CapacityChannel;
-import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.net.URIAuthority;
 
@@ -110,7 +110,7 @@ public abstract class AbstractAsyncServerAuthFilter<T> implements AsyncFilterHan
      * @return the response content entity.
      */
     protected AsyncEntityProducer generateResponseContent(final HttpResponse unauthorized) {
-        return new BasicAsyncEntityProducer("Unauthorized");
+        return AsyncEntityProducers.create("Unauthorized");
     }
 
     @Override
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 2511d4c..9903af5 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
@@ -30,7 +30,6 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
 
-import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
@@ -43,7 +42,7 @@ import org.apache.hc.core5.http.nio.BasicResponseProducer;
 import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.ResponseChannel;
-import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 
@@ -63,7 +62,7 @@ public final class ImmediateResponseExchangeHandler implements AsyncServerExchan
     }
 
     public ImmediateResponseExchangeHandler(final HttpResponse response, final String message) {
-        this(new BasicResponseProducer(response, new BasicAsyncEntityProducer(message, ContentType.TEXT_PLAIN)));
+        this(new BasicResponseProducer(response, AsyncEntityProducers.create(message)));
     }
 
     public ImmediateResponseExchangeHandler(final int status, final String message) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
index f45fa83..04ba5c3 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
@@ -46,7 +46,7 @@ import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.http.nio.HandlerFactory;
 import org.apache.hc.core5.http.nio.ResponseChannel;
-import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.Args;
 
@@ -147,7 +147,7 @@ public final class TerminalAsyncServerFilter implements AsyncFilterHandler {
             }, context);
             return exchangeHandler;
         }
-        responseTrigger.submitResponse(new BasicHttpResponse(HttpStatus.SC_NOT_FOUND), new BasicAsyncEntityProducer("Not found"));
+        responseTrigger.submitResponse(new BasicHttpResponse(HttpStatus.SC_NOT_FOUND), AsyncEntityProducers.create("Not found"));
         return null;
     }
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpContentProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/io/IOCallback.java
similarity index 80%
rename from httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpContentProducer.java
rename to httpcore5/src/main/java/org/apache/hc/core5/io/IOCallback.java
index 742426b..24fb294 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpContentProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/io/IOCallback.java
@@ -25,20 +25,17 @@
  *
  */
 
-package org.apache.hc.core5.http.io.entity;
+package org.apache.hc.core5.io;
 
 import java.io.IOException;
-import java.io.OutputStream;
 
 /**
- * An abstract entity content producer.
- *<p>Content producers are expected to be able to produce their
- * content multiple times</p>
+ * Abstract I/O callback.
  *
  * @since 5.0
  */
-public interface HttpContentProducer {
+public interface IOCallback<T> {
 
-    void writeTo(OutputStream outStream) throws IOException;
+    void execute(T object) throws IOException;
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/URLEncodedUtils.java b/httpcore5/src/main/java/org/apache/hc/core5/net/URLEncodedUtils.java
index 7cab723..f9c999c 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/URLEncodedUtils.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/URLEncodedUtils.java
@@ -51,11 +51,6 @@ import org.apache.hc.core5.util.Args;
  */
 public class URLEncodedUtils {
 
-    /**
-     * The default HTML form content type.
-     */
-    public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
-
     private static final char QP_SEP_A = '&';
     private static final char QP_SEP_S = ';';
     private static final String NAME_VALUE_SEPARATOR = "=";
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 f8b70ad..6da0fc6 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
@@ -33,7 +33,6 @@ import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpConnection;
@@ -55,7 +54,7 @@ import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 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.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
@@ -123,7 +122,7 @@ public class AsyncFullDuplexClientExample {
 
         final URI requestUri = new URI("http://httpbin.org/post");
         final BasicRequestProducer requestProducer = new BasicRequestProducer(
-                Methods.POST.name(), requestUri, new BasicAsyncEntityProducer("stuff", ContentType.TEXT_PLAIN));
+                Methods.POST.name(), requestUri, AsyncEntityProducers.create("stuff"));
         final BasicResponseConsumer<String> responseConsumer = new BasicResponseConsumer<>(
                 new StringAsyncEntityConsumer());
 
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 1d8055e..828f849 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
@@ -31,7 +31,6 @@ import java.net.InetSocketAddress;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-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;
@@ -51,7 +50,7 @@ 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.BasicAsyncEntityProducer;
+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.protocol.HttpContext;
@@ -124,7 +123,7 @@ public class AsyncServerFilterExample {
                         if (request.getRequestUri().equals("/back-door")) {
                             responseTrigger.submitResponse(
                                     new BasicHttpResponse(HttpStatus.SC_OK),
-                                    new BasicAsyncEntityProducer("Welcome", ContentType.TEXT_PLAIN));
+                                    AsyncEntityProducers.create("Welcome"));
                             return null;
                         }
                         return chain.proceed(request, entityDetails, context, new AsyncFilterChain.ResponseTrigger() {
@@ -171,9 +170,9 @@ public class AsyncServerFilterExample {
                             final ResponseTrigger responseTrigger,
                             final HttpContext context) throws HttpException, IOException {
                         // do something useful
-                        responseTrigger.submitResponse(new BasicResponseProducer(
-                                HttpStatus.SC_OK,
-                                new BasicAsyncEntityProducer("Hello", ContentType.TEXT_PLAIN)), context);
+                        responseTrigger.submitResponse(
+                                new BasicResponseProducer(HttpStatus.SC_OK, AsyncEntityProducers.create("Hello")),
+                                context);
                     }
                 })
                 .create();
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 4b33caf..5430bfc 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
@@ -27,7 +27,8 @@
 
 package org.apache.hc.core5.http.examples;
 
-import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.concurrent.TimeUnit;
 
@@ -44,14 +45,14 @@ import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
 import org.apache.hc.core5.http.impl.bootstrap.RequesterBootstrap;
 import org.apache.hc.core5.http.io.SocketConfig;
-import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
-import org.apache.hc.core5.http.io.entity.InputStreamEntity;
-import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.io.entity.HttpEntities;
 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
+import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.apache.hc.core5.io.IOCallback;
 import org.apache.hc.core5.util.Timeout;
 
 /**
@@ -92,17 +93,26 @@ public class ClassicPostExecutionExample {
         final HttpHost target = new HttpHost("httpbin.org");
 
         final HttpEntity[] requestBodies = {
-                new StringEntity(
+                HttpEntities.create(
                         "This is the first test request",
-                        ContentType.create("text/plain", StandardCharsets.UTF_8)),
-                new ByteArrayEntity(
+                        ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)),
+                HttpEntities.create(
                         "This is the second test request".getBytes(StandardCharsets.UTF_8),
                         ContentType.APPLICATION_OCTET_STREAM),
-                new InputStreamEntity(
-                        new ByteArrayInputStream(
-                                "This is the third test request (will be chunked)"
-                                        .getBytes(StandardCharsets.UTF_8)),
-                        ContentType.APPLICATION_OCTET_STREAM)
+                HttpEntities.create(new IOCallback<OutputStream>() {
+
+                    @Override
+                    public void execute(final OutputStream outStream) throws IOException {
+                        outStream.write(("This is the third test request " +
+                                "(streaming)").getBytes(StandardCharsets.UTF_8));
+                    }
+
+                }, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)),
+                HttpEntities.create(
+                        "This is the fourth test request " +
+                                "(streaming with trailers)",
+                        ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8),
+                        new BasicHeader("trailer1","And goodbye"))
         };
 
         final String requestUri = "/post";
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostWithTrailersExecutionExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostWithTrailersExecutionExample.java
deleted file mode 100644
index 7bb487b..0000000
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostWithTrailersExecutionExample.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.hc.core5.http.examples;
-
-import java.util.concurrent.TimeUnit;
-
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.ContentType;
-import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.Methods;
-import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
-import org.apache.hc.core5.http.impl.bootstrap.RequesterBootstrap;
-import org.apache.hc.core5.http.io.SocketConfig;
-import org.apache.hc.core5.http.io.entity.EntityUtils;
-import org.apache.hc.core5.http.io.entity.HttpEntityWithTrailers;
-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.protocol.HttpCoreContext;
-import org.apache.hc.core5.util.Timeout;
-
-/**
- * Example of POST request with trailers execution using classic I/O.
- */
-public class ClassicPostWithTrailersExecutionExample {
-    public static void main(final String[] args) throws Exception {
-        final HttpRequester httpRequester = RequesterBootstrap.bootstrap()
-                .setSocketConfig(SocketConfig.custom()
-                        .setSoTimeout(5, TimeUnit.SECONDS)
-                        .build())
-                .create();
-
-        final HttpCoreContext coreContext = HttpCoreContext.create();
-        final HttpHost target = new HttpHost("httpbin.org");
-
-        final String requestUri = "/post";
-        final ClassicHttpRequest request = new BasicClassicHttpRequest(Methods.POST, target, requestUri);
-        final HttpEntity requestBody = new HttpEntityWithTrailers(
-                new StringEntity("Chunked message with trailers", ContentType.TEXT_PLAIN),
-                new BasicHeader("t1","Hello world"));
-        request.setEntity(requestBody);
-
-        System.out.println(">> Request URI: " + request.getUri());
-        try (ClassicHttpResponse response = httpRequester.execute(target, request, Timeout.ofSeconds(5), coreContext)) {
-            System.out.println(requestUri + "->" + response.getCode());
-            System.out.println(EntityUtils.toString(response.getEntity()));
-            System.out.println("==============");
-        }
-    }
-
-}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/io/entity/TestEntityUtils.java b/httpcore5/src/test/java/org/apache/hc/core5/http/io/entity/TestEntityUtils.java
index 2fe5cbf..e8a3611 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/io/entity/TestEntityUtils.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/io/entity/TestEntityUtils.java
@@ -230,7 +230,7 @@ public class TestEntityUtils {
         Assert.assertEquals("russian=%D0%92%D1%81%D0%B5%D0%BC_%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82" +
                 "&swiss=Gr%C3%BCezi_z%C3%A4m%C3%A4", s);
         final StringEntity entity = new StringEntity(s,
-                ContentType.create(URLEncodedUtils.CONTENT_TYPE, StandardCharsets.UTF_8));
+                ContentType.APPLICATION_FORM_URLENCODED.withCharset(StandardCharsets.UTF_8));
         final List<NameValuePair> result = EntityUtils.parse(entity);
         Assert.assertEquals(2, result.size());
         assertNameValuePair(result.get(0), "russian", ru_hello);
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestMessageSupport.java b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestMessageSupport.java
index 0df4c32..9909a09 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestMessageSupport.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestMessageSupport.java
@@ -32,10 +32,10 @@ import java.util.LinkedHashSet;
 import java.util.Set;
 
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpMessage;
-import org.apache.hc.core5.http.io.entity.HttpEntityWithTrailers;
-import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.io.entity.HttpEntities;
 import org.apache.hc.core5.util.CharArrayBuffer;
 import org.junit.Assert;
 import org.junit.Test;
@@ -103,8 +103,7 @@ public class TestMessageSupport {
 
     @Test
     public void testAddContentHeaders() throws Exception {
-        final HttpEntityWithTrailers entity = new HttpEntityWithTrailers(
-                new StringEntity("some stuff with trailers", StandardCharsets.US_ASCII),
+        final HttpEntity entity = HttpEntities.create("some stuff with trailers", StandardCharsets.US_ASCII,
                 new BasicHeader("z", "this"), new BasicHeader("b", "that"), new BasicHeader("a", "this and that"));
         final HttpMessage message = new BasicHttpResponse(200);
         MessageSupport.addTrailerHeader(message, entity);
@@ -121,8 +120,7 @@ public class TestMessageSupport {
 
     @Test
     public void testContentHeadersAlreadyPresent() throws Exception {
-        final HttpEntityWithTrailers entity = new HttpEntityWithTrailers(
-                new StringEntity("some stuff with trailers", StandardCharsets.US_ASCII),
+        final HttpEntity entity = HttpEntities.create("some stuff with trailers", StandardCharsets.US_ASCII,
                 new BasicHeader("z", "this"), new BasicHeader("b", "that"), new BasicHeader("a", "this and that"));
         final HttpMessage message = new BasicHttpResponse(200);
         message.addHeader(HttpHeaders.TRAILER, "a, a, a");
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestStandardInterceptors.java b/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestStandardInterceptors.java
index b8bce7b..c4d24d2 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestStandardInterceptors.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestStandardInterceptors.java
@@ -40,7 +40,7 @@ import org.apache.hc.core5.http.Methods;
 import org.apache.hc.core5.http.ProtocolException;
 import org.apache.hc.core5.http.impl.io.EmptyInputStream;
 import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
-import org.apache.hc.core5.http.io.entity.HttpEntityWithTrailers;
+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.BasicClassicHttpResponse;
@@ -299,7 +299,7 @@ public class TestStandardInterceptors {
     public void testRequestContentEntityWithTrailers() throws Exception {
         final HttpContext context = new BasicHttpContext(null);
         final BasicClassicHttpRequest request = new BasicClassicHttpRequest(Methods.POST, "/");
-        request.setEntity(new HttpEntityWithTrailers(new StringEntity("whatever", StandardCharsets.US_ASCII),
+        request.setEntity(HttpEntities.create("whatever", StandardCharsets.US_ASCII,
                 new BasicHeader("h1", "this"), new BasicHeader("h1", "that"), new BasicHeader("h2", "this and that")));
 
         final RequestContent interceptor = new RequestContent();
@@ -888,7 +888,7 @@ public class TestStandardInterceptors {
     public void testResponseContentEntityWithTrailers() throws Exception {
         final HttpContext context = new BasicHttpContext(null);
         final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
-        response.setEntity(new HttpEntityWithTrailers(new StringEntity("whatever", StandardCharsets.US_ASCII),
+        response.setEntity(HttpEntities.create("whatever", StandardCharsets.US_ASCII,
                 new BasicHeader("h1", "this"), new BasicHeader("h1", "that"), new BasicHeader("h2", "this and that")));
 
         final ResponseContent interceptor = new ResponseContent();