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/10/16 14:09:12 UTC

[1/2] httpcomponents-core git commit: Fixed handling of relative request paths in BasicHttpRequest

Repository: httpcomponents-core
Updated Branches:
  refs/heads/master 48f8bb20a -> f9d8ead68


Fixed handling of relative request paths in BasicHttpRequest


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

Branch: refs/heads/master
Commit: f9d8ead68bcb4c095d7550d846c71a171cd37abf
Parents: f1f936e
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Mon Oct 16 16:06:13 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Mon Oct 16 16:07:00 2017 +0200

----------------------------------------------------------------------
 .../hc/core5/http/message/BasicHttpRequest.java  |  9 ++++++++-
 .../hc/core5/http/message/TestBasicMessages.java | 19 +++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f9d8ead6/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
index c32f8fa..495b237 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
@@ -187,7 +187,14 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
                     buf.append(":").append(this.authority.getPort());
                 }
             }
-            buf.append(this.path != null ? this.path : "/");
+            if (this.path == null) {
+                buf.append("/");
+            } else {
+                if (buf.length() > 0 && !this.path.startsWith("/")) {
+                    buf.append("/");
+                }
+                buf.append(this.path);
+            }
             this.requestUri = new URI(buf.toString());
         }
         return this.requestUri;

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f9d8ead6/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
index 7fadd36..5e1baab 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
@@ -29,6 +29,7 @@ package org.apache.hc.core5.http.message;
 
 import java.net.URI;
 
+import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
@@ -175,5 +176,23 @@ public class TestBasicMessages {
         Assert.assertEquals(new URI("https://host:9443/stuff?param=value"), request.getUri());
     }
 
+    @Test
+    public void testRequestWithAuthority() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("somehost", -1, "http"), "/stuff");
+        Assert.assertEquals("GET", request.getMethod());
+        Assert.assertEquals("/stuff", request.getPath());
+        Assert.assertEquals(new URIAuthority("somehost"), request.getAuthority());
+        Assert.assertEquals(new URI("http://somehost/stuff"), request.getUri());
+    }
+
+    @Test
+    public void testRequestWithAuthorityRelativePath() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("somehost", -1, "http"), "stuff");
+        Assert.assertEquals("GET", request.getMethod());
+        Assert.assertEquals("stuff", request.getPath());
+        Assert.assertEquals(new URIAuthority("somehost"), request.getAuthority());
+        Assert.assertEquals(new URI("http://somehost/stuff"), request.getUri());
+    }
+
 }
 


[2/2] httpcomponents-core git commit: Make basic string, byte array and file entity producers repeatable

Posted by ol...@apache.org.
Make basic string, byte array and file entity producers repeatable


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

Branch: refs/heads/master
Commit: f1f936e040cd1f42492215507f796ebef3ba9c09
Parents: 48f8bb2
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Fri Sep 29 16:42:34 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Mon Oct 16 16:07:00 2017 +0200

----------------------------------------------------------------------
 .../testing/nio/MultiLineEntityProducer.java    |   9 +-
 .../hc/core5/http/nio/AsyncEntityProducer.java  |   6 ++
 .../entity/AbstractCharAsyncEntityProducer.java |  10 ++
 .../entity/AbstractClassicEntityProducer.java   |   5 +
 .../nio/entity/BasicAsyncEntityProducer.java    |   6 ++
 .../nio/entity/DigestingEntityProducer.java     |   5 +
 .../http/nio/entity/FileEntityProducer.java     |  26 +++--
 .../nio/entity/StringAsyncEntityProducer.java   |   8 +-
 .../nio/support/TerminalAsyncServerFilter.java  |   5 +
 .../TestAbstractBinAsyncEntityProducer.java     |   5 +
 .../TestAbstractCharAsyncEntityProducer.java    |  11 +-
 .../entity/TestBasicAsyncEntityProducer.java    |  24 ++++-
 .../nio/entity/TestFileAsyncEntityProducer.java | 107 +++++++++++++++++++
 .../entity/TestStringAsyncEntityProducer.java   |  83 ++++++++++++++
 14 files changed, 294 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineEntityProducer.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineEntityProducer.java
index 731fb55..85589e8 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineEntityProducer.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/MultiLineEntityProducer.java
@@ -50,6 +50,11 @@ public class MultiLineEntityProducer extends AbstractCharAsyncEntityProducer {
     }
 
     @Override
+    public boolean isRepeatable() {
+        return true;
+    }
+
+    @Override
     public long getContentLength() {
         return -1;
     }
@@ -80,7 +85,9 @@ public class MultiLineEntityProducer extends AbstractCharAsyncEntityProducer {
     }
 
     @Override
-    public void releaseResources() {
+    public void releaseResourcesInternal() {
+        count = 0;
+        charbuf.clear();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncEntityProducer.java
index bd61caf..0814760 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncEntityProducer.java
@@ -35,6 +35,12 @@ import org.apache.hc.core5.http.EntityDetails;
  */
 public interface AsyncEntityProducer extends AsyncDataProducer, EntityDetails {
 
+    /**
+     * Determines whether the producer can consistently produce the same content
+     * after invocation of {@link ResourceHolder#releaseResources()}.
+     */
+    boolean isRepeatable();
+
     void failed(Exception cause);
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java
index 8a727cd..2c434f9 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java
@@ -143,4 +143,14 @@ public abstract class AbstractCharAsyncEntityProducer implements AsyncEntityProd
         }
     }
 
+    protected void releaseResourcesInternal() {
+    }
+
+    @Override
+    public final void releaseResources() {
+        charsetEncoder.reset();
+        state = State.ACTIVE;
+        releaseResourcesInternal();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractClassicEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractClassicEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractClassicEntityProducer.java
index 5a4b19a..b582987 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractClassicEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractClassicEntityProducer.java
@@ -58,6 +58,11 @@ public abstract class AbstractClassicEntityProducer implements AsyncEntityProduc
         this.exception = new AtomicReference<>(null);
     }
 
+    @Override
+    public final boolean isRepeatable() {
+        return false;
+    }
+
     protected abstract void produceData(ContentType contentType, OutputStream outputStream) throws IOException;
 
     @Override

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
index 0fcc97c..d87e079 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
@@ -78,6 +78,11 @@ public class BasicAsyncEntityProducer implements AsyncEntityProducer {
     }
 
     @Override
+    public boolean isRepeatable() {
+        return true;
+    }
+
+    @Override
     public final String getContentType() {
         return contentType != null ? contentType.toString() : null;
     }
@@ -128,6 +133,7 @@ public class BasicAsyncEntityProducer implements AsyncEntityProducer {
 
     @Override
     public void releaseResources() {
+        bytebuf.clear();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
index a6896f0..ce55e82 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
@@ -64,6 +64,11 @@ public class DigestingEntityProducer implements AsyncEntityProducer {
     }
 
     @Override
+    public boolean isRepeatable() {
+        return wrapped.isRepeatable();
+    }
+
+    @Override
     public long getContentLength() {
         return wrapped.getContentLength();
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java
index d95608f..8497aaf 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java
@@ -37,11 +37,12 @@ import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
 import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.Asserts;
 
 /**
  * @since 5.0
  */
-public class FileEntityProducer implements AsyncEntityProducer {
+public final class FileEntityProducer implements AsyncEntityProducer {
 
     private final File file;
     private final ByteBuffer bytebuf;
@@ -49,15 +50,16 @@ public class FileEntityProducer implements AsyncEntityProducer {
     private final ContentType contentType;
     private final AtomicReference<Exception> exception;
 
-    private RandomAccessFile accessFile;
+    private AtomicReference<RandomAccessFile> accessFileRef;
     private boolean eof;
 
     public FileEntityProducer(final File file, final int bufferSize, final ContentType contentType) {
         this.file = Args.notNull(file, "File");
         this.length = file.length();
+        this.bytebuf = ByteBuffer.allocate((int)(bufferSize > this.length ? bufferSize : this.length));
         this.contentType = contentType;
+        this.accessFileRef = new AtomicReference<>(null);
         this.exception = new AtomicReference<>(null);
-        this.bytebuf = ByteBuffer.allocate((int)(bufferSize > this.length ? bufferSize : this.length));
     }
 
     public FileEntityProducer(final File file, final ContentType contentType) {
@@ -69,7 +71,12 @@ public class FileEntityProducer implements AsyncEntityProducer {
     }
 
     @Override
-    public final String getContentType() {
+    public boolean isRepeatable() {
+        return true;
+    }
+
+    @Override
+    public String getContentType() {
         return contentType != null ? contentType.toString() : null;
     }
 
@@ -99,9 +106,11 @@ public class FileEntityProducer implements AsyncEntityProducer {
     }
 
     @Override
-    public final void produce(final DataStreamChannel channel) throws IOException {
+    public void produce(final DataStreamChannel channel) throws IOException {
+        RandomAccessFile accessFile = accessFileRef.get();
         if (accessFile == null) {
             accessFile = new RandomAccessFile(file, "r");
+            Asserts.check(accessFileRef.getAndSet(accessFile) == null, "Illegal producer state");
         }
         if (!eof) {
             final int bytesRead = accessFile.getChannel().read(bytebuf);
@@ -121,24 +130,25 @@ public class FileEntityProducer implements AsyncEntityProducer {
     }
 
     @Override
-    public final void failed(final Exception cause) {
+    public void failed(final Exception cause) {
         if (exception.compareAndSet(null, cause)) {
             releaseResources();
         }
     }
 
-    public final Exception getException() {
+    public Exception getException() {
         return exception.get();
     }
 
     @Override
     public void releaseResources() {
+        eof = false;
+        final RandomAccessFile accessFile = accessFileRef.getAndSet(null);
         if (accessFile != null) {
             try {
                 accessFile.close();
             } catch (final IOException ignore) {
             }
-            accessFile = null;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/StringAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/StringAsyncEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/StringAsyncEntityProducer.java
index 130ad54..b89269d 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/StringAsyncEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/StringAsyncEntityProducer.java
@@ -64,6 +64,11 @@ public class StringAsyncEntityProducer extends AbstractCharAsyncEntityProducer {
     }
 
     @Override
+    public boolean isRepeatable() {
+        return true;
+    }
+
+    @Override
     public long getContentLength() {
         return -1;
     }
@@ -94,7 +99,8 @@ public class StringAsyncEntityProducer extends AbstractCharAsyncEntityProducer {
     }
 
     @Override
-    public void releaseResources() {
+    public void releaseResourcesInternal() {
+        this.content.clear();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/TerminalAsyncServerFilter.java
----------------------------------------------------------------------
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 50762c0..341531e 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
@@ -88,6 +88,11 @@ public final class TerminalAsyncServerFilter implements AsyncFilterHandler {
                         }
 
                         @Override
+                        public boolean isRepeatable() {
+                            return false;
+                        }
+
+                        @Override
                         public long getContentLength() {
                             return entityDetails.getContentLength();
                         }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
index 020daf1..a38b968 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
@@ -57,6 +57,11 @@ public class TestAbstractBinAsyncEntityProducer {
         }
 
         @Override
+        public boolean isRepeatable() {
+            return false;
+        }
+
+        @Override
         protected void produceData(final StreamChannel<ByteBuffer> channel) throws IOException {
             if (count < content.length) {
                 channel.write(ByteBuffer.wrap(content[count]));

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityProducer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityProducer.java
index ab2357f..221ea42 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityProducer.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityProducer.java
@@ -31,8 +31,8 @@ import java.io.IOException;
 import java.nio.CharBuffer;
 import java.nio.charset.StandardCharsets;
 
-import org.apache.hc.core5.http.WritableByteChannelMock;
 import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.WritableByteChannelMock;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.BasicDataStreamChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
@@ -57,6 +57,11 @@ public class TestAbstractCharAsyncEntityProducer {
         }
 
         @Override
+        public boolean isRepeatable() {
+            return false;
+        }
+
+        @Override
         protected void produceData(final StreamChannel<CharBuffer> channel) throws IOException {
             if (count < content.length) {
                 channel.write(CharBuffer.wrap(content[count]));
@@ -81,10 +86,6 @@ public class TestAbstractCharAsyncEntityProducer {
         public void failed(final Exception cause) {
         }
 
-        @Override
-        public void releaseResources() {
-        }
-
     };
 
     @Test

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
index 611382f..2a1d2f8 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
@@ -29,8 +29,8 @@ package org.apache.hc.core5.http.nio.entity;
 
 import java.nio.charset.StandardCharsets;
 
-import org.apache.hc.core5.http.WritableByteChannelMock;
 import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.WritableByteChannelMock;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.BasicDataStreamChannel;
 import org.apache.hc.core5.http.nio.DataStreamChannel;
@@ -77,4 +77,26 @@ public class TestBasicAsyncEntityProducer {
         Assert.assertEquals("abc", byteChannel.dump(StandardCharsets.US_ASCII));
     }
 
+    @Test
+    public void testTextContentRepeatable() throws Exception {
+        final AsyncEntityProducer producer = new BasicAsyncEntityProducer(
+                "abc", ContentType.TEXT_PLAIN);
+
+        Assert.assertEquals(3, producer.getContentLength());
+        Assert.assertEquals(ContentType.TEXT_PLAIN.toString(), producer.getContentType());
+        Assert.assertEquals(null, producer.getContentEncoding());
+
+        for (int i = 0; i < 3; i++) {
+            final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+            final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+
+            producer.produce(streamChannel);
+
+            Assert.assertFalse(byteChannel.isOpen());
+            Assert.assertEquals("abc", byteChannel.dump(StandardCharsets.US_ASCII));
+
+            producer.releaseResources();
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestFileAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestFileAsyncEntityProducer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestFileAsyncEntityProducer.java
new file mode 100644
index 0000000..25fbe8b
--- /dev/null
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestFileAsyncEntityProducer.java
@@ -0,0 +1,107 @@
+/*
+ * ====================================================================
+ * 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.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.WritableByteChannelMock;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.BasicDataStreamChannel;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestFileAsyncEntityProducer {
+
+    private File tempFile;
+
+    @Before
+    public void setup() throws Exception {
+        tempFile = File.createTempFile("testing", ".txt");
+        try (final Writer writer = new OutputStreamWriter(new FileOutputStream(tempFile), StandardCharsets.US_ASCII)) {
+            writer.append("abcdef");
+            writer.flush();
+        }
+    }
+
+    @After
+    public void cleanup() {
+        if (tempFile != null) {
+            tempFile.delete();
+            tempFile = null;
+        }
+    }
+    @Test
+    public void testTextContent() throws Exception {
+
+        final AsyncEntityProducer producer = new FileEntityProducer(tempFile, ContentType.TEXT_PLAIN);
+
+        Assert.assertEquals(6, producer.getContentLength());
+        Assert.assertEquals(ContentType.TEXT_PLAIN.toString(), producer.getContentType());
+        Assert.assertEquals(null, producer.getContentEncoding());
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+
+        producer.produce(streamChannel);
+        producer.produce(streamChannel);
+
+        Assert.assertFalse(byteChannel.isOpen());
+        Assert.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+    }
+
+    @Test
+    public void testTextContentRepeatable() throws Exception {
+        final AsyncEntityProducer producer = new FileEntityProducer(tempFile, ContentType.TEXT_PLAIN);
+
+        Assert.assertEquals(6, producer.getContentLength());
+        Assert.assertEquals(ContentType.TEXT_PLAIN.toString(), producer.getContentType());
+        Assert.assertEquals(null, producer.getContentEncoding());
+
+        for (int i = 0; i < 3; i++) {
+            final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+            final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+
+            producer.produce(streamChannel);
+            producer.produce(streamChannel);
+
+            Assert.assertFalse(byteChannel.isOpen());
+            Assert.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+
+            producer.releaseResources();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/f1f936e0/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestStringAsyncEntityProducer.java
----------------------------------------------------------------------
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestStringAsyncEntityProducer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestStringAsyncEntityProducer.java
new file mode 100644
index 0000000..615dce9
--- /dev/null
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestStringAsyncEntityProducer.java
@@ -0,0 +1,83 @@
+/*
+ * ====================================================================
+ * 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.nio.charset.StandardCharsets;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.WritableByteChannelMock;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.BasicDataStreamChannel;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestStringAsyncEntityProducer {
+
+    @Test
+    public void testTextContent() throws Exception {
+
+        final AsyncEntityProducer producer = new StringAsyncEntityProducer(
+                "abc", ContentType.TEXT_PLAIN);
+
+        Assert.assertEquals(-1, producer.getContentLength());
+        Assert.assertEquals(ContentType.TEXT_PLAIN.toString(), producer.getContentType());
+        Assert.assertEquals(null, producer.getContentEncoding());
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+
+        producer.produce(streamChannel);
+
+        Assert.assertFalse(byteChannel.isOpen());
+        Assert.assertEquals("abc", byteChannel.dump(StandardCharsets.US_ASCII));
+    }
+
+    @Test
+    public void testTextContentRepeatable() throws Exception {
+        final AsyncEntityProducer producer = new StringAsyncEntityProducer(
+                "abc", ContentType.TEXT_PLAIN);
+
+        Assert.assertEquals(-1, producer.getContentLength());
+        Assert.assertEquals(ContentType.TEXT_PLAIN.toString(), producer.getContentType());
+        Assert.assertEquals(null, producer.getContentEncoding());
+
+        for (int i = 0; i < 3; i++) {
+            final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+            final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+
+            producer.produce(streamChannel);
+
+            Assert.assertFalse(byteChannel.isOpen());
+            Assert.assertEquals("abc", byteChannel.dump(StandardCharsets.US_ASCII));
+
+            producer.releaseResources();
+        }
+    }
+
+}