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

[1/2] httpcomponents-client git commit: Redesign of SimpleHttpRequest / SimpleHttpResponse APIs

Repository: httpcomponents-client
Updated Branches:
  refs/heads/master 18e56cc6c -> e8972624a


Redesign of SimpleHttpRequest / SimpleHttpResponse APIs


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

Branch: refs/heads/master
Commit: e8972624acf83c1c84ddf34c7058d5dcb8079550
Parents: 5203c66
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Thu Sep 28 15:41:06 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Fri Sep 29 17:02:41 2017 +0200

----------------------------------------------------------------------
 .../client5/http/cache/HttpCacheResponse.java   | 140 +++++++++++++++++
 .../AbstractSimpleServerExchangeHandler.java    |  30 +++-
 .../testing/async/TestAsyncRedirects.java       |  39 +++--
 .../async/TestAsyncStatefulConnManagement.java  |   8 +-
 .../testing/async/TestClientAuthentication.java |  19 ++-
 .../hc/client5/testing/async/TestHttpAsync.java |  12 +-
 .../testing/async/TestHttpAsyncMinimal.java     |   4 +-
 .../examples/AsyncClientConnectionEviction.java |   8 +-
 .../http/examples/AsyncClientCustomSSL.java     |   4 +-
 .../examples/AsyncClientHttp1Pipelining.java    |   4 +-
 .../examples/AsyncClientHttp2Multiplexing.java  |   4 +-
 .../examples/AsyncClientMessageTrailers.java    |   2 +-
 .../client5/http/async/methods/SimpleBody.java  |  99 ++++++++++++
 .../http/async/methods/SimpleHttpRequest.java   | 150 ++++++++++---------
 .../http/async/methods/SimpleHttpResponse.java  |  59 ++++----
 .../async/methods/SimpleRequestProducer.java    |  33 +++-
 .../async/methods/SimpleResponseConsumer.java   |  21 ++-
 .../impl/async/CloseableHttpAsyncClient.java    |   4 +-
 18 files changed, 484 insertions(+), 156 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheResponse.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheResponse.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheResponse.java
new file mode 100644
index 0000000..68a6dba
--- /dev/null
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheResponse.java
@@ -0,0 +1,140 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.cache;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Set;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.util.Args;
+
+public final class HttpCacheResponse implements EntityDetails {
+
+    private final int code;
+    private final String reasonPhrase;
+    private final byte[] body;
+    private final ContentType contentType;
+
+    public static HttpCacheResponse create(
+            final int code,
+            final String reasonPhrase,
+            final byte[] body,
+            final ContentType contentType) {
+        return new HttpCacheResponse(code, reasonPhrase, body, contentType);
+    }
+
+    public static HttpCacheResponse create(
+            final int code,
+            final byte[] body,
+            final ContentType contentType) {
+        return new HttpCacheResponse(code, null, body, contentType);
+    }
+
+    public static HttpCacheResponse create(
+            final int code,
+            final String reasonPhrase) {
+        return new HttpCacheResponse(code, reasonPhrase, null, null);
+    }
+
+    public static HttpCacheResponse create(final int code) {
+        return new HttpCacheResponse(code, null, null, null);
+    }
+
+    public static HttpCacheResponse create(
+            final int code,
+            final String reasonPhrase,
+            final String body,
+            final ContentType contentType) {
+        if (body != null) {
+            final Charset charset = contentType != null ? contentType.getCharset() : null;
+            final byte[] b = body.getBytes(charset != null ? charset : StandardCharsets.US_ASCII);
+            return new HttpCacheResponse(code, reasonPhrase, b, contentType);
+        } else {
+            return create(code, reasonPhrase);
+        }
+    }
+
+    public static HttpCacheResponse create(
+            final int code,
+            final String body,
+            final ContentType contentType) {
+        return create(code, null, body, contentType);
+    }
+
+    private HttpCacheResponse(
+            final int code,
+            final String reasonPhrase,
+            final byte[] body,
+            final ContentType contentType) {
+        this.code = Args.checkRange(code, 200, 599, "HTTP status");
+        this.reasonPhrase = reasonPhrase;
+        this.body = body;
+        this.contentType = contentType;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getReasonPhrase() {
+        return reasonPhrase;
+    }
+
+    public byte[] getBody() {
+        return body;
+    }
+
+    @Override
+    public long getContentLength() {
+        return body != null ? body.length : 0;
+    }
+
+    @Override
+    public String getContentType() {
+        return contentType != null ? contentType.toString() : null;
+    }
+
+    @Override
+    public String getContentEncoding() {
+        return null;
+    }
+
+    @Override
+    public boolean isChunked() {
+        return false;
+    }
+
+    @Override
+    public Set<String> getTrailerNames() {
+        return null;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
index 5200e63..a88b576 100644
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/AbstractSimpleServerExchangeHandler.java
@@ -28,15 +28,18 @@ package org.apache.hc.client5.testing.async;
 
 import java.io.IOException;
 
+import org.apache.hc.client5.http.async.methods.SimpleBody;
 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
 import org.apache.hc.core5.http.nio.BasicResponseProducer;
-import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.support.AbstractAsyncRequesterConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler;
@@ -51,14 +54,18 @@ public abstract class AbstractSimpleServerExchangeHandler extends AbstractServer
     protected final AsyncRequestConsumer<SimpleHttpRequest> supplyConsumer(
             final HttpRequest request,
             final HttpContext context) throws HttpException {
-        return new AbstractAsyncRequesterConsumer<SimpleHttpRequest, String>(new StringAsyncEntityConsumer()) {
+        return new AbstractAsyncRequesterConsumer<SimpleHttpRequest, byte[]>(new BasicAsyncEntityConsumer()) {
 
             @Override
             protected SimpleHttpRequest buildResult(
                     final HttpRequest request,
-                    final String entity,
+                    final byte[] body,
                     final ContentType contentType) {
-                return new SimpleHttpRequest(request, entity, contentType);
+                final SimpleHttpRequest simpleRequest = SimpleHttpRequest.copy(request);
+                if (body != null) {
+                    simpleRequest.setBodyBytes(body, contentType);
+                }
+                return simpleRequest;
             }
 
         };
@@ -70,9 +77,18 @@ public abstract class AbstractSimpleServerExchangeHandler extends AbstractServer
             final AsyncServerRequestHandler.ResponseTrigger responseTrigger,
             final HttpContext context) throws HttpException, IOException {
         final SimpleHttpResponse response = handle(request, HttpCoreContext.adapt(context));
-        responseTrigger.submitResponse(new BasicResponseProducer(
-                response,
-                response.getBody() != null ? new StringAsyncEntityProducer(response.getBody(), response.getContentType()) : null));
+        final SimpleBody body = response.getBody();
+        final AsyncEntityProducer entityProducer;
+        if (body != null) {
+            if (body.isText()) {
+                entityProducer = new StringAsyncEntityProducer(body.getBodyText(), body.getContentType());
+            } else {
+                entityProducer = new BasicAsyncEntityProducer(body.getBodyBytes(), body.getContentType());
+            }
+        } else {
+            entityProducer = null;
+        }
+        responseTrigger.submitResponse(new BasicResponseProducer(response, entityProducer));
 
     }
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
index a110817..cacbef1 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncRedirects.java
@@ -122,9 +122,11 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                     }
                     return response;
                 } else if (path.equals("/newlocation/")) {
-                    return new SimpleHttpResponse(HttpStatus.SC_OK, "Successful redirect", ContentType.TEXT_PLAIN);
+                    final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                    response.setBodyText("Successful redirect", ContentType.TEXT_PLAIN);
+                    return response;
                 } else {
-                    return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND, null, null);
+                    return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND);
                 }
             } catch (final URISyntaxException ex) {
                 throw new ProtocolException(ex.getMessage(), ex);
@@ -154,7 +156,7 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                     response.addHeader(new BasicHeader("Location", "/circular-oldlocation"));
                     return response;
                 } else {
-                    return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND, null, null);
+                    return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND);
                 }
             } catch (final URISyntaxException ex) {
                 throw new ProtocolException(ex.getMessage(), ex);
@@ -176,7 +178,9 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                     response.addHeader(new BasicHeader("Location", "/relativelocation/"));
                     return response;
                 } else if (path.equals("/relativelocation/")) {
-                    return new SimpleHttpResponse(HttpStatus.SC_OK, "Successful redirect", ContentType.TEXT_PLAIN);
+                    final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                    response.setBodyText("Successful redirect", ContentType.TEXT_PLAIN);
+                    return response;
                 } else {
                     return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND);
                 }
@@ -199,7 +203,9 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                     response.addHeader(new BasicHeader("Location", "relativelocation"));
                     return response;
                 } else if (path.equals("/test/relativelocation")) {
-                    return new SimpleHttpResponse(HttpStatus.SC_OK, "Successful redirect", ContentType.TEXT_PLAIN);
+                    final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                    response.setBodyText("Successful redirect", ContentType.TEXT_PLAIN);
+                    return response;
                 } else {
                     return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND);
                 }
@@ -450,9 +456,8 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                 .setMaxRedirects(5).build();
         try {
             final Future<SimpleHttpResponse> future = httpclient.execute(
-                    new SimpleRequestProducer(
-                            SimpleHttpRequest.get(target, "/circular-oldlocation/"), config),
-                    new SimpleResponseConsumer(), null);
+                    SimpleRequestProducer.create(SimpleHttpRequest.get(target, "/circular-oldlocation/"), config),
+                    SimpleResponseConsumer.create(), null);
             future.get();
         } catch (final ExecutionException e) {
             Assert.assertTrue(e.getCause() instanceof RedirectException);
@@ -477,9 +482,8 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                 .build();
         try {
             final Future<SimpleHttpResponse> future = httpclient.execute(
-                    new SimpleRequestProducer(
-                            SimpleHttpRequest.get(target, "/circular-oldlocation/"), config),
-                    new SimpleResponseConsumer(), null);
+                    SimpleRequestProducer.create(SimpleHttpRequest.get(target, "/circular-oldlocation/"), config),
+                    SimpleResponseConsumer.create(), null);
             future.get();
         } catch (final ExecutionException e) {
             Assert.assertTrue(e.getCause() instanceof CircularRedirectException);
@@ -501,8 +505,9 @@ public class TestAsyncRedirects extends IntegrationTestBase {
 
         final HttpClientContext context = HttpClientContext.create();
 
-        final Future<SimpleHttpResponse> future = httpclient.execute(
-                SimpleHttpRequest.post(target, "/oldlocation/", "stuff", ContentType.TEXT_PLAIN), context, null);
+        final SimpleHttpRequest post = SimpleHttpRequest.post(target, "/oldlocation/");
+        post.setBodyText("stuff", ContentType.TEXT_PLAIN);
+        final Future<SimpleHttpResponse> future = httpclient.execute(post, context, null);
         final HttpResponse response = future.get();
         Assert.assertNotNull(response);
 
@@ -585,7 +590,9 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                     response.addHeader(new BasicHeader("Location", url));
                     return response;
                 } else if (path.equals("/relativelocation/")) {
-                    return new SimpleHttpResponse(HttpStatus.SC_OK, "Successful redirect", ContentType.TEXT_PLAIN);
+                    final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                    response.setBodyText("Successful redirect", ContentType.TEXT_PLAIN);
+                    return response;
                 } else {
                     return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND);
                 }
@@ -793,7 +800,9 @@ public class TestAsyncRedirects extends IntegrationTestBase {
                 final URI requestURI = request.getUri();
                 final String path = requestURI.getPath();
                 if (path.equals("/rome")) {
-                    return new SimpleHttpResponse(HttpStatus.SC_OK, "Successful redirect", ContentType.TEXT_PLAIN);
+                    final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                    response.setBodyText("Successful redirect", ContentType.TEXT_PLAIN);
+                    return response;
                 } else {
                     final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
                     response.addHeader(new BasicHeader("Location", "/rome"));

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncStatefulConnManagement.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncStatefulConnManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncStatefulConnManagement.java
index 1918fa5..bbede25 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncStatefulConnManagement.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestAsyncStatefulConnManagement.java
@@ -62,7 +62,9 @@ public class TestAsyncStatefulConnManagement extends IntegrationTestBase {
                     protected SimpleHttpResponse handle(
                             final SimpleHttpRequest request,
                             final HttpCoreContext context) throws HttpException {
-                        return new SimpleHttpResponse(HttpStatus.SC_OK, "Whatever", ContentType.TEXT_PLAIN);
+                        final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                        response.setBodyText("Whatever", ContentType.TEXT_PLAIN);
+                        return response;
                     }
                 };
             }
@@ -185,7 +187,9 @@ public class TestAsyncStatefulConnManagement extends IntegrationTestBase {
                     protected SimpleHttpResponse handle(
                             final SimpleHttpRequest request,
                             final HttpCoreContext context) throws HttpException {
-                        return new SimpleHttpResponse(HttpStatus.SC_OK, "Whatever", ContentType.TEXT_PLAIN);
+                        final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
+                        response.setBodyText("Whatever", ContentType.TEXT_PLAIN);
+                        return response;
                     }
                 };
             }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
index afde7f2..606e66a 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
@@ -234,8 +234,9 @@ public class TestClientAuthentication extends IntegrationTestBase {
         final HttpClientContext context = HttpClientContext.create();
         context.setCredentialsProvider(credsProvider);
 
-        final Future<SimpleHttpResponse> future = httpclient.execute(
-                SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
+        final SimpleHttpRequest put = SimpleHttpRequest.put(target, "/");
+        put.setBodyText("Some important stuff", ContentType.TEXT_PLAIN);
+        final Future<SimpleHttpResponse> future = httpclient.execute(put, context, null);
         final HttpResponse response = future.get();
 
         Assert.assertNotNull(response);
@@ -306,8 +307,9 @@ public class TestClientAuthentication extends IntegrationTestBase {
         context.setCredentialsProvider(credsProvider);
         context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
 
-        final Future<SimpleHttpResponse> future = httpclient.execute(
-                SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
+        final SimpleHttpRequest put = SimpleHttpRequest.put(target, "/");
+        put.setBodyText("Some important stuff", ContentType.TEXT_PLAIN);
+        final Future<SimpleHttpResponse> future = httpclient.execute(put, context, null);
         final HttpResponse response = future.get();
 
         Assert.assertNotNull(response);
@@ -332,8 +334,9 @@ public class TestClientAuthentication extends IntegrationTestBase {
         context.setCredentialsProvider(credsProvider);
         context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
 
-        final Future<SimpleHttpResponse> future = httpclient.execute(
-                SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
+        final SimpleHttpRequest put = SimpleHttpRequest.put(target, "/");
+        put.setBodyText("Some important stuff", ContentType.TEXT_PLAIN);
+        final Future<SimpleHttpResponse> future = httpclient.execute(put, context, null);
         final HttpResponse response = future.get();
 
         Assert.assertNotNull(response);
@@ -547,8 +550,8 @@ public class TestClientAuthentication extends IntegrationTestBase {
             final HttpGet httpget = new HttpGet("/");
             httpget.setConfig(config);
             final Future<SimpleHttpResponse> future = httpclient.execute(
-                    new SimpleRequestProducer(SimpleHttpRequest.get(target, "/"), config),
-                    new SimpleResponseConsumer(),
+                    SimpleRequestProducer.create(SimpleHttpRequest.get(target, "/"), config),
+                    SimpleResponseConsumer.create(),
                     context, null);
             final SimpleHttpResponse response = future.get();
             Assert.assertNotNull(response);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsync.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsync.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsync.java
index a4e4b98..5f32a6f 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsync.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsync.java
@@ -78,7 +78,7 @@ public class TestHttpAsync extends IntegrationTestBase {
             final SimpleHttpResponse response = future.get();
             Assert.assertThat(response, CoreMatchers.notNullValue());
             Assert.assertThat(response.getCode(), CoreMatchers.equalTo(200));
-            final String body = response.getBody();
+            final String body = response.getBodyText();
             Assert.assertThat(body, CoreMatchers.notNullValue());
             Assert.assertThat(body.length(), CoreMatchers.equalTo(2048));
         }
@@ -93,7 +93,7 @@ public class TestHttpAsync extends IntegrationTestBase {
             final SimpleHttpResponse response = future.get();
             Assert.assertThat(response, CoreMatchers.notNullValue());
             Assert.assertThat(response.getCode(), CoreMatchers.equalTo(200));
-            final String body = response.getBody();
+            final String body = response.getBodyText();
             Assert.assertThat(body, CoreMatchers.nullValue());
         }
     }
@@ -108,7 +108,7 @@ public class TestHttpAsync extends IntegrationTestBase {
             final SimpleHttpResponse response = future.get();
             Assert.assertThat(response, CoreMatchers.notNullValue());
             Assert.assertThat(response.getCode(), CoreMatchers.equalTo(200));
-            final String body = response.getBody();
+            final String body = response.getBodyText();
             Assert.assertThat(body, CoreMatchers.notNullValue());
             Assert.assertThat(body.length(), CoreMatchers.equalTo(2048));
         }
@@ -209,7 +209,7 @@ public class TestHttpAsync extends IntegrationTestBase {
         final SimpleHttpResponse response1 = future1.get();
         Assert.assertThat(response1, CoreMatchers.notNullValue());
         Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(200));
-        final String body1 = response1.getBody();
+        final String body1 = response1.getBodyText();
         Assert.assertThat(body1, CoreMatchers.notNullValue());
         Assert.assertThat(body1.length(), CoreMatchers.equalTo(2048));
 
@@ -224,7 +224,7 @@ public class TestHttpAsync extends IntegrationTestBase {
             final SimpleHttpResponse response2 = future2.get();
             Assert.assertThat(response2, CoreMatchers.notNullValue());
             Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(200));
-            final String body2 = response2.getBody();
+            final String body2 = response2.getBodyText();
             Assert.assertThat(body2, CoreMatchers.notNullValue());
             Assert.assertThat(body2.length(), CoreMatchers.equalTo(2048));
         }
@@ -234,7 +234,7 @@ public class TestHttpAsync extends IntegrationTestBase {
         final SimpleHttpResponse response3 = future3.get();
         Assert.assertThat(response3, CoreMatchers.notNullValue());
         Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(200));
-        final String body3 = response3.getBody();
+        final String body3 = response3.getBodyText();
         Assert.assertThat(body3, CoreMatchers.notNullValue());
         Assert.assertThat(body3.length(), CoreMatchers.equalTo(2048));
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
index 97e3acb..b7b1ef5 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimal.java
@@ -189,7 +189,7 @@ public class TestHttpAsyncMinimal {
             final SimpleHttpResponse response = future.get();
             Assert.assertThat(response, CoreMatchers.notNullValue());
             Assert.assertThat(response.getCode(), CoreMatchers.equalTo(200));
-            final String body = response.getBody();
+            final String body = response.getBodyText();
             Assert.assertThat(body, CoreMatchers.notNullValue());
             Assert.assertThat(body.length(), CoreMatchers.equalTo(2048));
         }
@@ -204,7 +204,7 @@ public class TestHttpAsyncMinimal {
             final SimpleHttpResponse response = future.get();
             Assert.assertThat(response, CoreMatchers.notNullValue());
             Assert.assertThat(response.getCode(), CoreMatchers.equalTo(200));
-            final String body = response.getBody();
+            final String body = response.getBodyText();
             Assert.assertThat(body, CoreMatchers.nullValue());
         }
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientConnectionEviction.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientConnectionEviction.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientConnectionEviction.java
index ca7bd01..d9dc724 100644
--- a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientConnectionEviction.java
+++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientConnectionEviction.java
@@ -66,8 +66,8 @@ public class AsyncClientConnectionEviction {
 
         final SimpleHttpRequest request = SimpleHttpRequest.get(target, "/");
         final Future<SimpleHttpResponse> future1 = client.execute(
-                new SimpleRequestProducer(request),
-                new SimpleResponseConsumer(),
+                SimpleRequestProducer.create(request, null),
+                SimpleResponseConsumer.create(),
                 new FutureCallback<SimpleHttpResponse>() {
 
                     @Override
@@ -95,8 +95,8 @@ public class AsyncClientConnectionEviction {
         // Previous connection should get evicted from the pool by now
 
         final Future<SimpleHttpResponse> future2 = client.execute(
-                new SimpleRequestProducer(request),
-                new SimpleResponseConsumer(),
+                SimpleRequestProducer.create(request, null),
+                SimpleResponseConsumer.create(),
                 new FutureCallback<SimpleHttpResponse>() {
 
                     @Override

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
index c166612..4a66ba4 100644
--- a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
+++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientCustomSSL.java
@@ -105,8 +105,8 @@ public class AsyncClientCustomSSL {
 
             final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
             final Future<SimpleHttpResponse> future = client.execute(
-                    new SimpleRequestProducer(request),
-                    new SimpleResponseConsumer(),
+                    SimpleRequestProducer.create(request, null),
+                    SimpleResponseConsumer.create(),
                     clientContext,
                     new FutureCallback<SimpleHttpResponse>() {
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
index efcb975..ccf204f 100644
--- a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
+++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp1Pipelining.java
@@ -69,8 +69,8 @@ public class AsyncClientHttp1Pipelining {
             for (final String requestUri: requestUris) {
                 final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
                 endpoint.execute(
-                        new SimpleRequestProducer(request),
-                        new SimpleResponseConsumer(),
+                        SimpleRequestProducer.create(request, null),
+                        SimpleResponseConsumer.create(),
                         new FutureCallback<SimpleHttpResponse>() {
 
                             @Override

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2Multiplexing.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2Multiplexing.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2Multiplexing.java
index ae0c239..1c1bf96 100644
--- a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2Multiplexing.java
+++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2Multiplexing.java
@@ -70,8 +70,8 @@ public class AsyncClientHttp2Multiplexing {
             for (final String requestUri: requestUris) {
                 final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
                 endpoint.execute(
-                        new SimpleRequestProducer(request),
-                        new SimpleResponseConsumer(),
+                        SimpleRequestProducer.create(request, null),
+                        SimpleResponseConsumer.create(),
                         new FutureCallback<SimpleHttpResponse>() {
 
                             @Override

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientMessageTrailers.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientMessageTrailers.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientMessageTrailers.java
index 0af66f9..7da44f3 100644
--- a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientMessageTrailers.java
+++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientMessageTrailers.java
@@ -93,7 +93,7 @@ public class AsyncClientMessageTrailers {
                 .build();
         final Future<SimpleHttpResponse> future = client.execute(
                 requestProducer,
-                new SimpleResponseConsumer(),
+                SimpleResponseConsumer.create(),
                 new FutureCallback<SimpleHttpResponse>() {
 
                     @Override

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleBody.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleBody.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleBody.java
new file mode 100644
index 0000000..4c2028f
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleBody.java
@@ -0,0 +1,99 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.async.methods;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.util.Args;
+
+public final class SimpleBody {
+
+    private final byte[] bodyAsBytes;
+    private final String bodyAsText;
+    private final ContentType contentType;
+
+    SimpleBody(final byte[] bodyAsBytes, final String bodyAsText, final ContentType contentType) {
+        this.bodyAsBytes = bodyAsBytes;
+        this.bodyAsText = bodyAsText;
+        this.contentType = contentType;
+    }
+
+    static SimpleBody create(final String body, final ContentType contentType) {
+        Args.notNull(body, "Body");
+        if (body.length() > 2048) {
+            return new SimpleBody(null, body, contentType);
+        } else {
+            final Charset charset = (contentType != null ? contentType : ContentType.DEFAULT_TEXT).getCharset();
+            final byte[] bytes = body.getBytes(charset != null ? charset : StandardCharsets.US_ASCII);
+            return new SimpleBody(bytes, null, contentType);
+        }
+    }
+
+    static SimpleBody create(final byte[] body, final ContentType contentType) {
+        Args.notNull(body, "Body");
+        return new SimpleBody(body, null, contentType);
+    }
+
+    public ContentType getContentType() {
+        return contentType;
+    }
+
+    public byte[] getBodyBytes() {
+        if (bodyAsBytes != null) {
+            return bodyAsBytes;
+        } else if (bodyAsText != null) {
+            final Charset charset = (contentType != null ? contentType : ContentType.DEFAULT_TEXT).getCharset();
+            return bodyAsText.getBytes(charset != null ? charset : StandardCharsets.US_ASCII);
+        } else {
+            return null;
+        }
+    }
+
+    public String getBodyText() {
+        if (bodyAsBytes != null) {
+            final Charset charset = (contentType != null ? contentType : ContentType.DEFAULT_TEXT).getCharset();
+            return new String(bodyAsBytes, charset != null ? charset : StandardCharsets.US_ASCII);
+        } else if (bodyAsText != null) {
+            return bodyAsText;
+        } else {
+            return null;
+        }
+    }
+
+    public boolean isText() {
+        return bodyAsText != null;
+    }
+
+    public boolean isBytes() {
+        return bodyAsBytes != null;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java
index c7e497d..69238d9 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java
@@ -28,174 +28,190 @@
 package org.apache.hc.client5.http.async.methods;
 
 import java.net.URI;
+import java.util.Iterator;
 
 import org.apache.hc.client5.http.StandardMethods;
 import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
-import org.apache.hc.core5.http.message.HttpRequestWrapper;
 import org.apache.hc.core5.util.Args;
 
-public final class SimpleHttpRequest extends HttpRequestWrapper {
+public final class SimpleHttpRequest extends BasicHttpRequest {
 
-    private final String body;
-    private final ContentType contentType;
+    private SimpleBody body;
 
     public static SimpleHttpRequest get(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.GET, requestUri, null, null);
+        return new SimpleHttpRequest(StandardMethods.GET, requestUri);
     }
 
     public static SimpleHttpRequest get(final String requestUri) {
-        return new SimpleHttpRequest(StandardMethods.GET, URI.create(requestUri), null, null);
+        return new SimpleHttpRequest(StandardMethods.GET, URI.create(requestUri));
     }
 
     public static SimpleHttpRequest get(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.GET, host, path, null, null);
+        return new SimpleHttpRequest(StandardMethods.GET, host, path);
     }
 
-    public static SimpleHttpRequest head(final URI requestUri) {
+    public static SimpleHttpRequest post(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.HEAD, requestUri, null, null);
+        return new SimpleHttpRequest(StandardMethods.POST, requestUri);
     }
 
-    public static SimpleHttpRequest head(final String requestUri) {
-        return new SimpleHttpRequest(StandardMethods.HEAD, URI.create(requestUri), null, null);
+    public static SimpleHttpRequest post(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.POST, URI.create(requestUri));
     }
 
-    public static SimpleHttpRequest head(final HttpHost host, final String path) {
+    public static SimpleHttpRequest post(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.HEAD, host, path, null, null);
+        return new SimpleHttpRequest(StandardMethods.POST, host, path);
     }
 
-    public static SimpleHttpRequest post(final URI requestUri, final String body, final ContentType contentType) {
+    public static SimpleHttpRequest put(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.POST, requestUri, body, contentType);
+        return new SimpleHttpRequest(StandardMethods.PUT, requestUri);
     }
 
-    public static SimpleHttpRequest post(final String requestUri, final String body, final ContentType contentType) {
-        return new SimpleHttpRequest(StandardMethods.POST, URI.create(requestUri), body, contentType);
+    public static SimpleHttpRequest put(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.PUT, URI.create(requestUri));
     }
 
-    public static SimpleHttpRequest post(final HttpHost host, final String path, final String body, final ContentType contentType) {
+    public static SimpleHttpRequest put(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.POST, host, path, body, contentType);
+        return new SimpleHttpRequest(StandardMethods.PUT, host, path);
     }
 
-    public static SimpleHttpRequest PUT(final URI requestUri, final String body, final ContentType contentType) {
+    public static SimpleHttpRequest head(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.PUT, requestUri, body, contentType);
+        return new SimpleHttpRequest(StandardMethods.HEAD, requestUri);
     }
 
-    public static SimpleHttpRequest put(final String requestUri, final String body, final ContentType contentType) {
-        return new SimpleHttpRequest(StandardMethods.PUT, URI.create(requestUri), body, contentType);
+    public static SimpleHttpRequest head(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.HEAD, URI.create(requestUri));
     }
 
-    public static SimpleHttpRequest put(final HttpHost host, final String path, final String body, final ContentType contentType) {
+    public static SimpleHttpRequest head(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.PUT, host, path, body, contentType);
+        return new SimpleHttpRequest(StandardMethods.HEAD, host, path);
     }
 
     public static SimpleHttpRequest delete(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.DELETE, requestUri, null, null);
+        return new SimpleHttpRequest(StandardMethods.DELETE, requestUri);
     }
 
     public static SimpleHttpRequest delete(final String requestUri) {
-        return new SimpleHttpRequest(StandardMethods.DELETE, URI.create(requestUri), null, null);
+        return new SimpleHttpRequest(StandardMethods.DELETE, URI.create(requestUri));
     }
 
     public static SimpleHttpRequest delete(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.DELETE, host, path, null, null);
+        return new SimpleHttpRequest(StandardMethods.DELETE, host, path);
     }
 
     public static SimpleHttpRequest trace(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.TRACE, requestUri, null, null);
+        return new SimpleHttpRequest(StandardMethods.TRACE, requestUri);
     }
 
     public static SimpleHttpRequest trace(final String requestUri) {
-        return new SimpleHttpRequest(StandardMethods.TRACE, URI.create(requestUri), null, null);
+        return new SimpleHttpRequest(StandardMethods.TRACE, URI.create(requestUri));
     }
 
     public static SimpleHttpRequest trace(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.TRACE, host, path, null, null);
+        return new SimpleHttpRequest(StandardMethods.TRACE, host, path);
     }
 
     public static SimpleHttpRequest options(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.OPTIONS, requestUri, null, null);
+        return new SimpleHttpRequest(StandardMethods.OPTIONS, requestUri);
     }
 
     public static SimpleHttpRequest options(final String requestUri) {
-        return new SimpleHttpRequest(StandardMethods.OPTIONS, URI.create(requestUri), null, null);
+        return new SimpleHttpRequest(StandardMethods.OPTIONS, URI.create(requestUri));
     }
 
     public static SimpleHttpRequest options(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.OPTIONS, host, path, null, null);
+        return new SimpleHttpRequest(StandardMethods.OPTIONS, host, path);
     }
 
-    public static SimpleHttpRequest patch(final URI requestUri, final String body, final ContentType contentType) {
+    public static SimpleHttpRequest patch(final URI requestUri) {
         Args.notNull(requestUri, "Request URI");
-        return new SimpleHttpRequest(StandardMethods.PATCH, requestUri, body, contentType);
+        return new SimpleHttpRequest(StandardMethods.PATCH, requestUri);
     }
 
-    public static SimpleHttpRequest patch(final String requestUri, final String body, final ContentType contentType) {
-        return new SimpleHttpRequest(StandardMethods.PATCH, URI.create(requestUri), body, contentType);
+    public static SimpleHttpRequest patch(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.PATCH, URI.create(requestUri));
     }
 
-    public static SimpleHttpRequest patch(final HttpHost host, final String path, final String body, final ContentType contentType) {
+    public static SimpleHttpRequest patch(final HttpHost host, final String path) {
         Args.notNull(host, "Host");
-        return new SimpleHttpRequest(StandardMethods.PATCH, host, path, body, contentType);
+        return new SimpleHttpRequest(StandardMethods.PATCH, host, path);
     }
 
-    public SimpleHttpRequest(final HttpRequest head, final String body, final ContentType contentType) {
-        super(head);
-        this.body = body;
-        this.contentType = contentType;
+    public static SimpleHttpRequest copy(final HttpRequest original) {
+        Args.notNull(original, "HTTP request");
+        final SimpleHttpRequest copy = new SimpleHttpRequest(original.getMethod(), original.getRequestUri());
+        copy.setVersion(original.getVersion());
+        for (final Iterator<Header> it = original.headerIterator(); it.hasNext(); ) {
+            copy.addHeader(it.next());
+        }
+        copy.setScheme(original.getScheme());
+        copy.setAuthority(original.getAuthority());
+        return copy;
     }
 
-    public SimpleHttpRequest(
-            final String method,
-            final HttpHost host,
-            final String path,
-            final String body,
-            final ContentType contentType) {
-        super(new BasicHttpRequest(method, host, path));
-        this.body = body;
-        this.contentType = contentType;
+    public SimpleHttpRequest(final String method, final String path) {
+        super(method, path);
+    }
+
+    public SimpleHttpRequest(final String method, final HttpHost host, final String path) {
+        super(method, host, path);
     }
 
-    SimpleHttpRequest(
-            final StandardMethods method,
-            final HttpHost host,
-            final String path,
-            final String body,
-            final ContentType contentType) {
-        this(method.name(), host, path, body, contentType);
+    public SimpleHttpRequest(final String method, final URI requestUri) {
+        super(method, requestUri);
     }
 
-    public SimpleHttpRequest(final String method, final URI requestUri, final String body, final ContentType contentType) {
-        super(new BasicHttpRequest(method, requestUri));
+    SimpleHttpRequest(final StandardMethods method, final URI requestUri) {
+        this(method.name(), requestUri);
+    }
+
+    SimpleHttpRequest(final StandardMethods method, final HttpHost host, final String path) {
+        this(method.name(), host, path);
+    }
+
+    public void setBody(final SimpleBody body) {
         this.body = body;
-        this.contentType = contentType;
     }
 
-    SimpleHttpRequest(final StandardMethods method, final URI requestUri, final String body, final ContentType contentType) {
-        this(method.name(), requestUri, body, contentType);
+    public void setBodyBytes(final byte[] bodyBytes, final ContentType contentType) {
+        this.body = SimpleBody.create(bodyBytes, contentType);
+    }
+
+    public void setBodyText(final String bodyText, final ContentType contentType) {
+        this.body = SimpleBody.create(bodyText, contentType);
     }
 
-    public String getBody() {
+    public SimpleBody getBody() {
         return body;
     }
 
     public ContentType getContentType() {
-        return contentType;
+        return body != null ? body.getContentType() : null;
+    }
+
+    public String getBodyText() {
+        return body != null ? body.getBodyText() : null;
+    }
+
+    public byte[] getBodyBytes() {
+        return body != null ? body.getBodyBytes() : null;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java
index 6e51535..7d1686d 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java
@@ -27,51 +27,58 @@
 
 package org.apache.hc.client5.http.async.methods;
 
+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.BasicHttpResponse;
-import org.apache.hc.core5.http.message.HttpResponseWrapper;
+import org.apache.hc.core5.util.Args;
 
-public final class SimpleHttpResponse extends HttpResponseWrapper {
+public final class SimpleHttpResponse extends BasicHttpResponse {
 
-    private final String body;
-    private final ContentType contentType;
+    private SimpleBody body;
 
-    public SimpleHttpResponse(
-            final HttpResponse head,
-            final String body,
-            final ContentType contentType) {
-        super(head);
-        this.body = body;
-        this.contentType = contentType;
+    public SimpleHttpResponse(final int code) {
+        super(code);
     }
 
-    public SimpleHttpResponse(
-            final int code,
-            final String reasonPhrase,
-            final String body,
-            final ContentType contentType) {
-        super(new BasicHttpResponse(code, reasonPhrase));
-        this.body = body;
-        this.contentType = contentType;
+    public static SimpleHttpResponse copy(final HttpResponse original) {
+        Args.notNull(original, "HTTP response");
+        final SimpleHttpResponse copy = new SimpleHttpResponse(original.getCode());
+        copy.setVersion(original.getVersion());
+        for (final Iterator<Header> it = original.headerIterator(); it.hasNext(); ) {
+            copy.addHeader(it.next());
+        }
+        return copy;
     }
 
-    public SimpleHttpResponse(final int code, final String body, final ContentType contentType) {
-        super(new BasicHttpResponse(code));
+    public void setBody(final SimpleBody body) {
         this.body = body;
-        this.contentType = contentType;
     }
 
-    public SimpleHttpResponse(final int code) {
-        this(code, null, null);
+    public void setBodyBytes(final byte[] bodyBytes, final ContentType contentType) {
+        this.body = SimpleBody.create(bodyBytes, contentType);
     }
 
-    public String getBody() {
+    public void setBodyText(final String bodyText, final ContentType contentType) {
+        this.body = SimpleBody.create(bodyText, contentType);
+    }
+
+    public SimpleBody getBody() {
         return body;
     }
 
     public ContentType getContentType() {
-        return contentType;
+        return body != null ? body.getContentType() : null;
+    }
+
+    public String getBodyText() {
+        return body != null ? body.getBodyText() : null;
+    }
+
+    public byte[] getBodyBytes() {
+        return body != null ? body.getBodyBytes() : null;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java
index 943669d..69bb6fa 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java
@@ -27,18 +27,41 @@
 package org.apache.hc.client5.http.async.methods;
 
 import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.util.Args;
 
 public final class SimpleRequestProducer extends DefaultAsyncRequestProducer {
 
-    public SimpleRequestProducer(final SimpleHttpRequest request, final RequestConfig requestConfig) {
-        super(Args.notNull(request, "Request"), request.getBody() != null ?
-                new StringAsyncEntityProducer(request.getBody(), request.getContentType()) : null, requestConfig);
+    SimpleRequestProducer(final HttpRequest request, final AsyncEntityProducer entityProducer, final RequestConfig requestConfig) {
+        super(request, entityProducer, requestConfig);
     }
 
-    public SimpleRequestProducer(final SimpleHttpRequest request) {
-        this(request, null);
+    public static SimpleRequestProducer create(final SimpleHttpRequest request, final RequestConfig requestConfig) {
+        Args.notNull(request, "Request");
+        final SimpleBody body = request.getBody();
+        final AsyncEntityProducer entityProducer;
+        if (body != null) {
+            if (body.isText()) {
+                entityProducer = new StringAsyncEntityProducer(body.getBodyText(), body.getContentType());
+            } else {
+                entityProducer = new BasicAsyncEntityProducer(body.getBodyBytes(), body.getContentType()) {
+
+                    //TODO: return the actual content length once
+                    // the entity producers made repeatable in HttpCore
+                    @Override
+                    public long getContentLength() {
+                        return -1;
+                    }
+
+                };
+            }
+        } else {
+            entityProducer = null;
+        }
+        return new SimpleRequestProducer(request, entityProducer, requestConfig);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java
index e84be5b..395d1db 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java
@@ -28,18 +28,27 @@ package org.apache.hc.client5.http.async.methods;
 
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.support.AbstractAsyncResponseConsumer;
 
-public final class SimpleResponseConsumer extends AbstractAsyncResponseConsumer<SimpleHttpResponse, String> {
+public final class SimpleResponseConsumer extends AbstractAsyncResponseConsumer<SimpleHttpResponse, byte[]> {
 
-    public SimpleResponseConsumer() {
-        super(new StringAsyncEntityConsumer());
+    SimpleResponseConsumer(final AsyncEntityConsumer<byte[]> entityConsumer) {
+        super(entityConsumer);
+    }
+
+    public static SimpleResponseConsumer create() {
+        return new SimpleResponseConsumer(new BasicAsyncEntityConsumer());
     }
 
     @Override
-    protected SimpleHttpResponse buildResult(final HttpResponse response, final String entity, final ContentType contentType) {
-        return new SimpleHttpResponse(response, entity, contentType);
+    protected SimpleHttpResponse buildResult(final HttpResponse response, final byte[] entity, final ContentType contentType) {
+        final SimpleHttpResponse simpleResponse = SimpleHttpResponse.copy(response);
+        if (entity != null) {
+            simpleResponse.setBodyBytes(entity, contentType);
+        }
+        return simpleResponse;
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/e8972624/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient.java
index 5526800..56bcd93 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient.java
@@ -48,6 +48,7 @@ import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.io.ShutdownType;
 import org.apache.hc.core5.reactor.ExceptionEvent;
 import org.apache.hc.core5.reactor.IOReactorStatus;
+import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 
 /**
@@ -85,8 +86,9 @@ public abstract class CloseableHttpAsyncClient implements HttpAsyncClient, Close
             final SimpleHttpRequest request,
             final HttpContext context,
             final FutureCallback<SimpleHttpResponse> callback) {
+        Args.notNull(request, "Request");
         final BasicFuture<SimpleHttpResponse> future = new BasicFuture<>(callback);
-        execute(new SimpleRequestProducer(request), new SimpleResponseConsumer(), context, new FutureCallback<SimpleHttpResponse>() {
+        execute(SimpleRequestProducer.create(request, null), SimpleResponseConsumer.create(), context, new FutureCallback<SimpleHttpResponse>() {
 
             @Override
             public void completed(final SimpleHttpResponse response) {


[2/2] httpcomponents-client git commit: Corrected configuration of the 'expect-continue' handshake in async client authentication tests

Posted by ol...@apache.org.
Corrected configuration of the 'expect-continue' handshake in async
client authentication tests


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

Branch: refs/heads/master
Commit: 5203c669289e15fa8dd6ce2e257e94c36423bd2d
Parents: 18e56cc
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Thu Sep 28 15:39:43 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Fri Sep 29 17:02:41 2017 +0200

----------------------------------------------------------------------
 .../testing/async/TestClientAuthentication.java | 30 ++++++++++++++++++++
 1 file changed, 30 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/5203c669/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
index fa54a35..afde7f2 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestClientAuthentication.java
@@ -218,6 +218,34 @@ public class TestClientAuthentication extends IntegrationTestBase {
     }
 
     @Test
+    public void testBasicAuthenticationWithEntitySuccess() throws Exception {
+        server.register("*", new Supplier<AsyncServerExchangeHandler>() {
+
+            @Override
+            public AsyncServerExchangeHandler get() {
+                return new AsyncEchoHandler();
+            }
+
+        });
+        final HttpHost target = start();
+
+        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
+                new UsernamePasswordCredentials("test", "test".toCharArray()));
+        final HttpClientContext context = HttpClientContext.create();
+        context.setCredentialsProvider(credsProvider);
+
+        final Future<SimpleHttpResponse> future = httpclient.execute(
+                SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
+        final HttpResponse response = future.get();
+
+        Assert.assertNotNull(response);
+        Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
+        final AuthScope authscope = credsProvider.getAuthScope();
+        Assert.assertNotNull(authscope);
+        Assert.assertEquals("test realm", authscope.getRealm());
+    }
+
+    @Test
     public void testBasicAuthenticationSuccessNonPersistentConnection() throws Exception {
         server.register("*", new Supplier<AsyncServerExchangeHandler>() {
 
@@ -276,6 +304,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
                 new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
         final HttpClientContext context = HttpClientContext.create();
         context.setCredentialsProvider(credsProvider);
+        context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
 
         final Future<SimpleHttpResponse> future = httpclient.execute(
                 SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
@@ -301,6 +330,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
                 new UsernamePasswordCredentials("test", "test".toCharArray()));
         final HttpClientContext context = HttpClientContext.create();
         context.setCredentialsProvider(credsProvider);
+        context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
 
         final Future<SimpleHttpResponse> future = httpclient.execute(
                 SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);