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 2016/11/13 14:07:18 UTC

svn commit: r1769497 [2/2] - in /httpcomponents/httpcore/trunk: httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/ httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/ httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ ht...

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -38,13 +38,14 @@ import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.io.entity.ContentType;
 import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.CapacityChannel;
 import org.apache.hc.core5.util.Args;
 
 public abstract class AbstractBinAsyncEntityConsumer<T> implements AsyncEntityConsumer<T> {
 
     protected abstract void dataStart(ContentType contentType, FutureCallback<T> resultCallback) throws HttpException, IOException;
 
-    protected abstract int consumeData(ByteBuffer src) throws IOException;
+    protected abstract void consumeData(ByteBuffer src) throws IOException;
 
     protected abstract void dataEnd() throws IOException;
 
@@ -62,12 +63,18 @@ public abstract class AbstractBinAsyncEn
     }
 
     @Override
+    public final void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
+        capacityChannel.update(Integer.MAX_VALUE);
+    }
+
+    @Override
     public final int consume(final ByteBuffer src) throws IOException {
-        return consumeData(src);
+        consumeData(src);
+        return Integer.MAX_VALUE;
     }
 
     @Override
-    public final void streamEnd(final List<Header> trailers) throws IOException {
+    public final void streamEnd(final List<? extends Header> trailers) throws IOException {
         dataEnd();
     }
 

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -87,7 +87,7 @@ public abstract class AbstractCharAsyncE
         if (chunk > 0) {
             consumeData(charbuf);
         }
-        charbuf.compact();
+        charbuf.clear();
     }
 
     @Override
@@ -107,11 +107,11 @@ public abstract class AbstractCharAsyncE
             checkResult(charsetDecoder.decode(src, charbuf, false));
             doDecode();
         }
-        return charbuf.remaining();
+        return Integer.MAX_VALUE;
     }
 
     @Override
-    public final void streamEnd(final List<Header> trailers) throws IOException {
+    public final void streamEnd(final List<? extends Header> trailers) throws IOException {
         if (charsetDecoder != null) {
             if (charbuf == null) {
                 charbuf = CharBuffer.allocate(512);

Copied: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityConsumer.java (from r1769496, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityConsumer.java?p2=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityConsumer.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java&r1=1769496&r2=1769497&rev=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -28,6 +28,9 @@ package org.apache.hc.core5.http.nio.ent
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
@@ -36,50 +39,77 @@ import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
 import org.apache.hc.core5.http.nio.CapacityChannel;
+import org.apache.hc.core5.util.Args;
 
 /**
  * @since 5.0
  */
-public final class NoopEntityConsumer implements AsyncEntityConsumer<Void> {
+public class DigestingEntityConsumer<T> implements AsyncEntityConsumer<T> {
 
-    private volatile FutureCallback<Void> resultCallback;
+    private final AsyncEntityConsumer<T> wrapped;
+    private final List<Header> trailers;
+    private final MessageDigest digester;
+
+    private volatile byte[] digest;
+
+    public DigestingEntityConsumer(
+            final String algo,
+            final AsyncEntityConsumer<T> wrapped) throws NoSuchAlgorithmException {
+        this.wrapped = Args.notNull(wrapped, "Entity consumer");
+        this.trailers = new ArrayList<>();
+        this.digester = MessageDigest.getInstance(algo);
+    }
 
     @Override
-    public final void streamStart(
+    public void streamStart(
             final EntityDetails entityDetails,
-            final FutureCallback<Void> resultCallback) throws IOException, HttpException {
-        this.resultCallback = resultCallback;
+            final FutureCallback<T> resultCallback) throws IOException, HttpException {
+        wrapped.streamStart(entityDetails, resultCallback);
     }
 
     @Override
     public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
-        capacityChannel.update(Integer.MAX_VALUE);
+        wrapped.updateCapacity(capacityChannel);
     }
 
     @Override
-    public final int consume(final ByteBuffer src) throws IOException {
-        return Integer.MAX_VALUE;
+    public int consume(final ByteBuffer src) throws IOException {
+        src.mark();
+        digester.update(src);
+        src.reset();
+        return wrapped.consume(src);
     }
 
     @Override
-    public final void streamEnd(final List<Header> trailers) throws IOException {
-        if (resultCallback != null) {
-            resultCallback.completed(null);
+    public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
+        if (trailers != null) {
+            this.trailers.addAll(trailers);
         }
+        digest = digester.digest();
+        wrapped.streamEnd(trailers);
     }
 
     @Override
     public void failed(final Exception cause) {
-        releaseResources();
+        wrapped.failed(cause);
     }
 
     @Override
-    public Void getContent() {
-        return null;
+    public T getContent() {
+        return wrapped.getContent();
     }
 
     @Override
     public void releaseResources() {
+        wrapped.releaseResources();
+    }
+
+    public List<Header> getTrailers() {
+        return trailers != null ? new ArrayList<>(trailers) : null;
+    }
+
+    public byte[] getDigest() {
+        return digest;
     }
 
 }

Added: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java?rev=1769497&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java Sun Nov 13 14:07:18 2016
@@ -0,0 +1,157 @@
+/*
+ * ====================================================================
+ * 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.IOException;
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.message.BasicHeader;
+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.TextUtils;
+
+/**
+ * @since 5.0
+ */
+public class DigestingEntityProducer implements AsyncEntityProducer {
+
+    private final AsyncEntityProducer wrapped;
+    private final MessageDigest digester;
+
+    private volatile byte[] digest;
+
+    public DigestingEntityProducer(
+            final String algo,
+            final AsyncEntityProducer wrapped) {
+        this.wrapped = Args.notNull(wrapped, "Entity consumer");
+        try {
+            this.digester = MessageDigest.getInstance(algo);
+        } catch (NoSuchAlgorithmException ex) {
+            throw new IllegalArgumentException("Unsupported digest algorithm: " + algo);
+        }
+    }
+
+    @Override
+    public long getContentLength() {
+        return wrapped.getContentLength();
+    }
+
+    @Override
+    public String getContentType() {
+        return wrapped.getContentType();
+    }
+
+    @Override
+    public String getContentEncoding() {
+        return wrapped.getContentEncoding();
+    }
+
+    @Override
+    public boolean isChunked() {
+        return wrapped.isChunked();
+    }
+
+    @Override
+    public Set<String> getTrailerNames() {
+        final Set<String> allNames = new LinkedHashSet<>();
+        final Set<String> names = wrapped.getTrailerNames();
+        if (names != null) {
+            allNames.addAll(names);
+        }
+        allNames.add("digest-algo");
+        allNames.add("digest");
+        return allNames;
+    }
+
+    @Override
+    public int available() {
+        return wrapped.available();
+    }
+
+    @Override
+    public void produce(final DataStreamChannel channel) throws IOException {
+        wrapped.produce(new DataStreamChannel() {
+
+            @Override
+            public void requestOutput() {
+                channel.requestOutput();
+            }
+
+            @Override
+            public int write(final ByteBuffer src) throws IOException {
+                final ByteBuffer dup = src.duplicate();
+                final int writtenBytes = channel.write(src);
+                if (writtenBytes > 0) {
+                    dup.limit(dup.position() + writtenBytes);
+                    digester.update(dup);
+                }
+                return writtenBytes;
+            }
+
+            @Override
+            public void endStream(final List<? extends Header> trailers) throws IOException {
+                digest = digester.digest();
+                final List<Header> allTrailers = new ArrayList<>();
+                if (trailers != null) {
+                    allTrailers.addAll(trailers);
+                }
+                allTrailers.add(new BasicHeader("digest-algo", digester.getAlgorithm()));
+                allTrailers.add(new BasicHeader("digest", TextUtils.toHexString(digest)));
+                channel.endStream(allTrailers);
+            }
+
+            @Override
+            public void endStream() throws IOException {
+                endStream(null);
+            }
+
+        });
+    }
+
+    @Override
+    public void failed(final Exception cause) {
+        wrapped.failed(cause);
+    }
+
+    @Override
+    public void releaseResources() {
+        wrapped.releaseResources();
+    }
+
+    public byte[] getDigest() {
+        return digest;
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -62,7 +62,7 @@ public final class NoopEntityConsumer im
     }
 
     @Override
-    public final void streamEnd(final List<Header> trailers) throws IOException {
+    public final void streamEnd(final List<? extends Header> trailers) throws IOException {
         if (resultCallback != null) {
             resultCallback.completed(null);
         }

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java Sun Nov 13 14:07:18 2016
@@ -189,7 +189,7 @@ public abstract class AbstractServerExch
     }
 
     @Override
-    public final void streamEnd(final List<Header> trailers) throws HttpException, IOException {
+    public final void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
         if (!expectationFailed) {
             final AsyncRequestConsumer<T> requestConsumer = requestConsumerRef.get();
             Asserts.notNull(requestConsumer, "Data consumer");

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicAsyncPushHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicAsyncPushHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicAsyncPushHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicAsyncPushHandler.java Sun Nov 13 14:07:18 2016
@@ -101,7 +101,7 @@ public class BasicAsyncPushHandler<T> im
     }
 
     @Override
-    public final void streamEnd(final List<Header> trailers) throws HttpException, IOException {
+    public final void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
         responseConsumer.streamEnd(trailers);
     }
 

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java Sun Nov 13 14:07:18 2016
@@ -142,7 +142,7 @@ public class BasicClientExchangeHandler<
     }
 
     @Override
-    public void streamEnd(final List<Header> trailers) throws HttpException, IOException {
+    public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
         responseConsumer.streamEnd(trailers);
     }
 

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java Sun Nov 13 14:07:18 2016
@@ -89,7 +89,7 @@ public final class ImmediateResponseExch
     }
 
     @Override
-    public void streamEnd(final List<Header> trailers) throws HttpException, IOException {
+    public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
     }
 
     @Override

Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/util/TextUtils.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/util/TextUtils.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/util/TextUtils.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/util/TextUtils.java Sun Nov 13 14:07:18 2016
@@ -76,4 +76,19 @@ public final class TextUtils {
         return false;
     }
 
+    public static String toHexString(final byte[] bytes) {
+        if (bytes == null) {
+            return null;
+        }
+        final StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            final byte b = bytes[i];
+            if (b < 16) {
+                buffer.append('0');
+            }
+            buffer.append(Integer.toHexString(b & 0xff));
+        }
+        return buffer.toString();
+    }
+
 }

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestChunkCoding.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestChunkCoding.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestChunkCoding.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestChunkCoding.java Sun Nov 13 14:07:18 2016
@@ -32,18 +32,20 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
 
 import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.MalformedChunkCodingException;
 import org.apache.hc.core5.http.MessageConstraintException;
 import org.apache.hc.core5.http.StreamClosedException;
-import org.apache.hc.core5.http.TrailerSupplier;
 import org.apache.hc.core5.http.TruncatedChunkException;
 import org.apache.hc.core5.http.config.H1Config;
 import org.apache.hc.core5.http.io.SessionInputBuffer;
 import org.apache.hc.core5.http.io.SessionOutputBuffer;
 import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.nio.Supplier;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -373,15 +375,15 @@ public class TestChunkCoding {
     public void testChunkedOutputStreamWithTrailers() throws IOException {
         final SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(16);
         final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        final ChunkedOutputStream out = new ChunkedOutputStream(2, outbuffer, outputStream, new TrailerSupplier() {
+        final ChunkedOutputStream out = new ChunkedOutputStream(2, outbuffer, outputStream, new Supplier<List<? extends Header>>() {
             @Override
-            public Header[] get() {
-                return new Header[] {
+            public List<? extends Header> get() {
+                return Arrays.asList(
                         new BasicHeader("E", ""),
-                        new BasicHeader("Y", "Z")
-                };
+                        new BasicHeader("Y", "Z"));
+                }
             }
-        });
+        );
         out.write('x');
         out.finish();
         out.close();

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/ContentDecoderMock.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/ContentDecoderMock.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/ContentDecoderMock.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/ContentDecoderMock.java Sun Nov 13 14:07:18 2016
@@ -30,7 +30,9 @@ package org.apache.hc.core5.http.impl.ni
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
+import java.util.List;
 
+import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.nio.ContentDecoder;
 
 public class ContentDecoderMock implements ContentDecoder {
@@ -60,4 +62,9 @@ public class ContentDecoderMock implemen
         return this.completed;
     }
 
+    @Override
+    public List<? extends Header> getTrailers() {
+        return null;
+    }
+
 }

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkDecoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkDecoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkDecoder.java Sun Nov 13 14:07:18 2016
@@ -31,6 +31,7 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.charset.StandardCharsets;
+import java.util.List;
 
 import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.Header;
@@ -63,8 +64,8 @@ public class TestChunkDecoder {
         int bytesRead = decoder.read(dst);
         Assert.assertEquals(16, bytesRead);
         Assert.assertEquals("0123456789abcdef", CodecTestUtils.convert(dst));
-        final Header[] footers = decoder.getFooters();
-        Assert.assertEquals(0, footers.length);
+        final List<? extends Header> trailers = decoder.getTrailers();
+        Assert.assertEquals(null, trailers);
 
         dst.clear();
         bytesRead = decoder.read(dst);
@@ -97,12 +98,12 @@ public class TestChunkDecoder {
         Assert.assertEquals(26, bytesRead);
         Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
 
-        final Header[] footers = decoder.getFooters();
-        Assert.assertEquals(2, footers.length);
-        Assert.assertEquals("Footer1", footers[0].getName());
-        Assert.assertEquals("abcde", footers[0].getValue());
-        Assert.assertEquals("Footer2", footers[1].getName());
-        Assert.assertEquals("fghij", footers[1].getValue());
+        final List<? extends Header> trailers = decoder.getTrailers();
+        Assert.assertEquals(2, trailers.size());
+        Assert.assertEquals("Footer1", trailers.get(0).getName());
+        Assert.assertEquals("abcde", trailers.get(0).getValue());
+        Assert.assertEquals("Footer2", trailers.get(1).getName());
+        Assert.assertEquals("fghij", trailers.get(1).getValue());
 
         dst.clear();
         bytesRead = decoder.read(dst);
@@ -201,12 +202,12 @@ public class TestChunkDecoder {
         Assert.assertEquals("123456789012345612345abcdef", CodecTestUtils.convert(dst));
         Assert.assertTrue(decoder.isCompleted());
 
-        final Header[] footers = decoder.getFooters();
-        Assert.assertEquals(2, footers.length);
-        Assert.assertEquals("Footer1", footers[0].getName());
-        Assert.assertEquals("abcde", footers[0].getValue());
-        Assert.assertEquals("Footer2", footers[1].getName());
-        Assert.assertEquals("fghij", footers[1].getValue());
+        final List<? extends Header> trailers = decoder.getTrailers();
+        Assert.assertEquals(2, trailers.size());
+        Assert.assertEquals("Footer1", trailers.get(0).getName());
+        Assert.assertEquals("abcde", trailers.get(0).getValue());
+        Assert.assertEquals("Footer2", trailers.get(1).getName());
+        Assert.assertEquals("fghij", trailers.get(1).getValue());
 
         dst.clear();
         bytesRead = decoder.read(dst);
@@ -274,10 +275,10 @@ public class TestChunkDecoder {
         Assert.assertEquals(26, bytesRead);
         Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
 
-        final Header[] footers = decoder.getFooters();
-        Assert.assertEquals(1, footers.length);
-        Assert.assertEquals("Footer1", footers[0].getName());
-        Assert.assertEquals("abcde  fghij", footers[0].getValue());
+        final List<? extends Header> trailers = decoder.getTrailers();
+        Assert.assertEquals(1, trailers.size());
+        Assert.assertEquals("Footer1", trailers.get(0).getName());
+        Assert.assertEquals("abcde  fghij", trailers.get(0).getValue());
     }
 
     @Test(expected=IOException.class)
@@ -453,9 +454,9 @@ public class TestChunkDecoder {
         final int bytesRead = decoder1.read(dst);
         Assert.assertEquals(16, bytesRead);
         Assert.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
-        final Header[] footers = decoder1.getFooters();
-        Assert.assertNotNull(footers);
-        Assert.assertEquals(1, footers.length);
+        final List<? extends Header> trailers = decoder1.getTrailers();
+        Assert.assertNotNull(trailers);
+        Assert.assertEquals(1, trailers.size());
 
         final ReadableByteChannel channel2 = new ReadableByteChannelMock(
                 new String[] {s}, StandardCharsets.US_ASCII);
@@ -488,9 +489,9 @@ public class TestChunkDecoder {
         final int bytesRead = decoder1.read(dst);
         Assert.assertEquals(16, bytesRead);
         Assert.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
-        final Header[] footers = decoder1.getFooters();
-        Assert.assertNotNull(footers);
-        Assert.assertEquals(1, footers.length);
+        final List<? extends Header> trailers = decoder1.getTrailers();
+        Assert.assertNotNull(trailers);
+        Assert.assertEquals(1, trailers.size());
 
         final H1Config constraints = H1Config.custom()
                 .setMaxLineLength(25)
@@ -526,9 +527,9 @@ public class TestChunkDecoder {
         final int bytesRead = decoder1.read(dst);
         Assert.assertEquals(16, bytesRead);
         Assert.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
-        final Header[] footers = decoder1.getFooters();
-        Assert.assertNotNull(footers);
-        Assert.assertEquals(4, footers.length);
+        final List<? extends Header> trailers = decoder1.getTrailers();
+        Assert.assertNotNull(trailers);
+        Assert.assertEquals(4, trailers.size());
 
         final H1Config constraints = H1Config.custom()
                 .setMaxHeaderCount(3).build();

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkEncoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkEncoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkEncoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkEncoder.java Sun Nov 13 14:07:18 2016
@@ -30,9 +30,8 @@ package org.apache.hc.core5.http.impl.ni
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.TrailerSupplier;
 import org.apache.hc.core5.http.WritableByteChannelMock;
 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
 import org.apache.hc.core5.http.message.BasicHeader;
@@ -123,7 +122,7 @@ public class TestChunkEncoder {
         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(1024));
         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 1024);
         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
-        final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics, 1024, null);
+        final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics, 1024);
 
         Assert.assertEquals(16, encoder.write(CodecTestUtils.wrap("0123456789ABCDEF")));
         Assert.assertEquals(16, encoder.write(CodecTestUtils.wrap("0123456789ABCDEF")));
@@ -237,18 +236,10 @@ public class TestChunkEncoder {
         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
-        final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics, 0,
-                new TrailerSupplier() {
-                    @Override
-                    public Header[] get() {
-                        return new Header[] {
-                                new BasicHeader("E", ""),
-                                new BasicHeader("Y", "Z")};
-                    }
-                });
+        final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics, 0);
         encoder.write(CodecTestUtils.wrap("1"));
         encoder.write(CodecTestUtils.wrap("23"));
-        encoder.complete();
+        encoder.complete(Arrays.asList(new BasicHeader("E", ""), new BasicHeader("Y", "Z")));
 
         outbuf.flush(channel);
 

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/BasicDataStreamChannel.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/BasicDataStreamChannel.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/BasicDataStreamChannel.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/BasicDataStreamChannel.java Sun Nov 13 14:07:18 2016
@@ -30,6 +30,7 @@ package org.apache.hc.core5.http.nio;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.hc.core5.http.Header;
@@ -37,6 +38,7 @@ import org.apache.hc.core5.http.Header;
 public class BasicDataStreamChannel implements DataStreamChannel {
 
     private final WritableByteChannel byteChannel;
+    private List<Header> trailers;
 
     public BasicDataStreamChannel(final WritableByteChannel byteChannel) {
         this.byteChannel = byteChannel;
@@ -59,8 +61,16 @@ public class BasicDataStreamChannel impl
     }
 
     @Override
-    public void endStream(final List<Header> trailers) throws IOException {
+    public void endStream(final List<? extends Header> trailers) throws IOException {
         endStream();
+        if (trailers != null) {
+            this.trailers = new ArrayList<>();
+            this.trailers.addAll(trailers);
+        }
+    }
+
+    public List<Header> getTrailers() {
+        return trailers;
     }
 
 }

Added: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java?rev=1769497&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -0,0 +1,149 @@
+/*
+ * ====================================================================
+ * 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.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.impl.BasicEntityDetails;
+import org.apache.hc.core5.http.impl.nio.ExpandableBuffer;
+import org.apache.hc.core5.http.io.entity.ContentType;
+import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestAbstractBinAsyncEntityConsumer {
+
+    private static class InternalBuffer extends ExpandableBuffer {
+
+        InternalBuffer(final int bufferSize) {
+            super(bufferSize);
+        }
+
+        void write(final ByteBuffer src) {
+            setInputMode();
+            final int requiredCapacity = buffer().position() + src.remaining();
+            ensureCapacity(requiredCapacity);
+            buffer().put(src);
+        }
+
+        byte[] toByteArray() {
+            setOutputMode();
+            final byte[] bytes = new byte[buffer().remaining()];
+            buffer().get(bytes);
+            return bytes;
+        }
+
+    }
+
+    static private class ByteArrayAsyncEntityConsumer extends AbstractBinAsyncEntityConsumer<byte[]> {
+
+        private final InternalBuffer buffer;
+        private volatile FutureCallback<byte[]> resultCallback;
+        private byte[] content;
+
+        public ByteArrayAsyncEntityConsumer() {
+            super();
+            this.buffer = new InternalBuffer(1024);
+        }
+
+        @Override
+        protected void dataStart(
+                final ContentType contentType,
+                final FutureCallback<byte[]> resultCallback) throws HttpException, IOException {
+            this.resultCallback = resultCallback;
+        }
+
+        @Override
+        protected void consumeData(final ByteBuffer src) throws IOException {
+            buffer.write(src);
+        }
+
+        @Override
+        protected void dataEnd() throws IOException {
+            content = buffer.toByteArray();
+            if (resultCallback != null) {
+                resultCallback.completed(content);
+            }
+        }
+
+        @Override
+        public void failed(final Exception cause) {
+        }
+
+        @Override
+        public byte[] getContent() {
+            return content;
+        }
+
+        @Override
+        public void releaseResources() {
+        }
+
+    };
+
+    @Test
+    public void testConsumeData() throws Exception {
+
+        final AsyncEntityConsumer<byte[]> consumer = new ByteArrayAsyncEntityConsumer();
+
+        final AtomicLong count = new AtomicLong(0);
+        consumer.streamStart(new BasicEntityDetails(-1, ContentType.APPLICATION_OCTET_STREAM), new FutureCallback<byte[]>() {
+
+            @Override
+            public void completed(final byte[] result) {
+                count.incrementAndGet();
+            }
+
+            @Override
+            public void failed(final Exception ex) {
+                count.incrementAndGet();
+            }
+
+            @Override
+            public void cancelled() {
+                count.incrementAndGet();
+            }
+
+        });
+
+        consumer.consume(ByteBuffer.wrap(new byte[]{'1', '2', '3'}));
+        consumer.consume(ByteBuffer.wrap(new byte[]{'4', '5'}));
+        consumer.consume(ByteBuffer.wrap(new byte[]{}));
+
+        Assert.assertEquals(null, consumer.getContent());
+        consumer.streamEnd(null);
+
+        Assert.assertArrayEquals(new byte[] {'1', '2', '3', '4', '5'}, consumer.getContent());
+        Assert.assertEquals(1L, count.longValue());
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java Sun Nov 13 14:07:18 2016
@@ -42,12 +42,12 @@ import org.junit.Test;
 
 public class TestAbstractBinAsyncEntityProducer {
 
-    static private class ChunkCharAsyncEntityProducer extends AbstractBinAsyncEntityProducer {
+    static private class ChunkByteAsyncEntityProducer extends AbstractBinAsyncEntityProducer {
 
         private final byte[][] content;
         private int count = 0;
 
-        public ChunkCharAsyncEntityProducer(
+        public ChunkByteAsyncEntityProducer(
                 final int bufferSize,
                 final int fragmentSizeHint,
                 final ContentType contentType,
@@ -90,7 +90,7 @@ public class TestAbstractBinAsyncEntityP
     @Test
     public void testProduceDataNoBuffering() throws Exception {
 
-        final AsyncEntityProducer producer = new ChunkCharAsyncEntityProducer(
+        final AsyncEntityProducer producer = new ChunkByteAsyncEntityProducer(
                 256, 0, ContentType.TEXT_PLAIN,
                 new byte[] { '1', '2', '3' }, new byte[] { '4', '5', '6' });
 
@@ -115,7 +115,7 @@ public class TestAbstractBinAsyncEntityP
     @Test
     public void testProduceDataWithBuffering() throws Exception {
 
-        final AsyncEntityProducer producer = new ChunkCharAsyncEntityProducer(
+        final AsyncEntityProducer producer = new ChunkByteAsyncEntityProducer(
                 256, 5, ContentType.TEXT_PLAIN,
                 new byte[] { '1', '2', '3' },
                 new byte[] { '4', '5', '6' },

Added: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java?rev=1769497&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -0,0 +1,133 @@
+/*
+ * ====================================================================
+ * 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.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.impl.BasicEntityDetails;
+import org.apache.hc.core5.http.io.entity.ContentType;
+import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.CapacityChannel;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestAbstractCharAsyncEntityConsumer {
+
+    static private class StringBuilderAsyncEntityConsumer extends AbstractCharAsyncEntityConsumer<String> {
+
+        private final StringBuilder buffer;
+        private volatile FutureCallback<String> resultCallback;
+        private String content;
+
+        public StringBuilderAsyncEntityConsumer() {
+            super();
+            this.buffer = new StringBuilder(1024);
+        }
+
+        @Override
+        protected void dataStart(
+                final ContentType contentType,
+                final FutureCallback<String> resultCallback) throws HttpException, IOException {
+            this.resultCallback = resultCallback;
+        }
+
+        @Override
+        public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
+            capacityChannel.update(Integer.MAX_VALUE);
+        }
+
+        @Override
+        protected void consumeData(final CharBuffer src) throws IOException {
+            buffer.append(src);
+        }
+
+        @Override
+        protected void dataEnd() throws IOException {
+            content = buffer.toString();
+            if (resultCallback != null) {
+                resultCallback.completed(content);
+            }
+        }
+
+        @Override
+        public void failed(final Exception cause) {
+        }
+
+        @Override
+        public String getContent() {
+            return content;
+        }
+
+        @Override
+        public void releaseResources() {
+        }
+
+    };
+
+    @Test
+    public void testConsumeData() throws Exception {
+
+        final AsyncEntityConsumer<String> consumer = new StringBuilderAsyncEntityConsumer();
+
+        final AtomicLong count = new AtomicLong(0);
+        consumer.streamStart(new BasicEntityDetails(-1, ContentType.TEXT_PLAIN), new FutureCallback<String>() {
+
+            @Override
+            public void completed(final String result) {
+                count.incrementAndGet();
+            }
+
+            @Override
+            public void failed(final Exception ex) {
+                count.incrementAndGet();
+            }
+
+            @Override
+            public void cancelled() {
+                count.incrementAndGet();
+            }
+
+        });
+
+        consumer.consume(ByteBuffer.wrap(new byte[]{'1', '2', '3'}));
+        consumer.consume(ByteBuffer.wrap(new byte[]{'4', '5'}));
+        consumer.consume(ByteBuffer.wrap(new byte[]{}));
+
+        Assert.assertEquals(null, consumer.getContent());
+        consumer.streamEnd(null);
+
+        Assert.assertEquals("12345", consumer.getContent());
+        Assert.assertEquals(1L, count.longValue());
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityConsumer.java (from r1769496, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityConsumer.java?p2=httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityConsumer.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java&r1=1769496&r2=1769497&rev=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityConsumer.java Sun Nov 13 14:07:18 2016
@@ -24,26 +24,30 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http.nio;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.List;
-
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpException;
+package org.apache.hc.core5.http.nio.entity;
 
-/**
- * Abstract asynchronous data consumer.
- *
- * @since 5.0
- */
-public interface AsyncDataConsumer extends ResourceHolder {
-
-    void updateCapacity(CapacityChannel capacityChannel) throws IOException;
-
-    int consume(ByteBuffer src) throws IOException;
+import java.nio.ByteBuffer;
 
-    void streamEnd(List<Header> trailers) throws HttpException, IOException;
+import org.apache.hc.core5.util.TextUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestDigestingEntityConsumer {
+
+    @Test
+    public void testConsumeData() throws Exception {
+
+        final DigestingEntityConsumer<String> consumer = new DigestingEntityConsumer<>("MD5",
+                new StringAsyncEntityConsumer());
+
+        consumer.consume(ByteBuffer.wrap(new byte[]{'1', '2', '3'}));
+        consumer.consume(ByteBuffer.wrap(new byte[]{'4', '5'}));
+        consumer.consume(ByteBuffer.wrap(new byte[]{}));
+        consumer.streamEnd(null);
+
+        Assert.assertEquals("12345", consumer.getContent());
+        Assert.assertEquals("0827c0cb0e0ea08a706c4c340a1680910f84e7b", TextUtils.toHexString(consumer.getDigest()));
+    }
 
 }

Added: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java?rev=1769497&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java Sun Nov 13 14:07:18 2016
@@ -0,0 +1,65 @@
+/*
+ * ====================================================================
+ * 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 java.util.List;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.WritableByteChannelMock;
+import org.apache.hc.core5.http.io.entity.ContentType;
+import org.apache.hc.core5.http.nio.BasicDataStreamChannel;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestDigestingEntityProducer {
+
+    @Test
+    public void testProduceData() throws Exception {
+
+        final DigestingEntityProducer producer = new DigestingEntityProducer("MD5",
+                new StringAsyncEntityProducer("12345", ContentType.TEXT_PLAIN));
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final BasicDataStreamChannel dataStreamChannel = new BasicDataStreamChannel(byteChannel);
+        while (byteChannel.isOpen()) {
+            producer.produce(dataStreamChannel);
+        }
+
+        Assert.assertEquals("12345", byteChannel.dump(StandardCharsets.US_ASCII));
+        final List<Header> trailers = dataStreamChannel.getTrailers();
+        Assert.assertNotNull(trailers);
+        Assert.assertEquals(2, trailers.size());
+
+        Assert.assertEquals("digest-algo", trailers.get(0).getName());
+        Assert.assertEquals("MD5", trailers.get(0).getValue());
+        Assert.assertEquals("digest", trailers.get(1).getName());
+        Assert.assertEquals("0827c0cb0e0ea08a706c4c340a1680910f84e7b", trailers.get(1).getValue());
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/util/TestTextUtils.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/util/TestTextUtils.java?rev=1769497&r1=1769496&r2=1769497&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/util/TestTextUtils.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/util/TestTextUtils.java Sun Nov 13 14:07:18 2016
@@ -61,4 +61,10 @@ public class TestTextUtils {
         Assert.assertFalse(TextUtils.containsBlanks("a"));
     }
 
+    @Test
+    public void testToHexString() {
+        Assert.assertEquals("000c2001", TextUtils.toHexString(new byte[] { 0, 12, 32, 1 }));
+        Assert.assertEquals(null, TextUtils.toHexString(null));
+    }
+
 }