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

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

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();