Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id F2CBB200BBC for ; Sun, 13 Nov 2016 15:07:33 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id F1517160B12; Sun, 13 Nov 2016 14:07:33 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id A6CC3160AF2 for ; Sun, 13 Nov 2016 15:07:31 +0100 (CET) Received: (qmail 41586 invoked by uid 500); 13 Nov 2016 14:07:30 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 41577 invoked by uid 99); 13 Nov 2016 14:07:30 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 13 Nov 2016 14:07:30 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id 4E826C0595 for ; Sun, 13 Nov 2016 14:07:30 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -1.199 X-Spam-Level: X-Spam-Status: No, score=-1.199 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RP_MATCHES_RCVD=-2.999] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id vglYa9aVewsf for ; Sun, 13 Nov 2016 14:07:21 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with ESMTP id D0BAA5F249 for ; Sun, 13 Nov 2016 14:07:20 +0000 (UTC) Received: from svn01-us-west.apache.org (svn.apache.org [10.41.0.6]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 5E626E0CBE for ; Sun, 13 Nov 2016 14:07:19 +0000 (UTC) Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 5AD003A18EE for ; Sun, 13 Nov 2016 14:07:19 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1769497 [1/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... Date: Sun, 13 Nov 2016 14:07:18 -0000 To: commits@hc.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20161113140719.5AD003A18EE@svn01-us-west.apache.org> archived-at: Sun, 13 Nov 2016 14:07:34 -0000 Author: olegk Date: Sun Nov 13 14:07:18 2016 New Revision: 1769497 URL: http://svn.apache.org/viewvc?rev=1769497&view=rev Log: RFC 7230, RFC 7540: full support for message trailers Added: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityConsumer.java - copied, changed from r1769496, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java (with props) httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityConsumer.java (with props) httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractCharAsyncEntityConsumer.java (with props) httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityConsumer.java - copied, changed from r1769496, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java (with props) Removed: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/TrailerSupplier.java Modified: httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkConnection.java httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/entity/TestSharedOutputBuffer.java httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/HttpEntity.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/IncomingHttpEntity.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/BHttpConnectionBase.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/ChunkedOutputStream.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentDecoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentEncoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkDecoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkEncoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/LengthDelimitedEncoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/entity/AbstractClassicEntityConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentDecoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentEncoder.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/DataStreamChannel.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/NoopEntityConsumer.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicAsyncPushHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/util/TextUtils.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestChunkCoding.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/ContentDecoderMock.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkDecoder.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestChunkEncoder.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/BasicDataStreamChannel.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/util/TestTextUtils.java Modified: httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkConnection.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkConnection.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkConnection.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkConnection.java Sun Nov 13 14:07:18 2016 @@ -28,11 +28,13 @@ package org.apache.hc.core5.http.benchma import java.io.InputStream; import java.io.OutputStream; +import java.util.List; -import org.apache.hc.core5.http.TrailerSupplier; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection; import org.apache.hc.core5.http.io.SessionInputBuffer; import org.apache.hc.core5.http.io.SessionOutputBuffer; +import org.apache.hc.core5.http.nio.Supplier; class BenchmarkConnection extends DefaultBHttpClientConnection { @@ -47,7 +49,7 @@ class BenchmarkConnection extends Defaul protected OutputStream createContentOutputStream(final long len, final SessionOutputBuffer outbuffer, final OutputStream outputStream, - final TrailerSupplier trailers) { + final Supplier> trailers) { return new CountingOutputStream( super.createContentOutputStream(len, outbuffer, outputStream, trailers), this.stats); Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java Sun Nov 13 14:07:18 2016 @@ -295,7 +295,7 @@ public final class HPackEncoder { } void encodeHeaders( - final ByteArrayBuffer dst, final List
headers, + final ByteArrayBuffer dst, final List headers, final boolean noIndexing, final boolean useHuffman) throws CharacterCodingException { for (int i = 0; i < headers.size(); i++) { encodeHeader(dst, headers.get(i), noIndexing, useHuffman); @@ -317,7 +317,7 @@ public final class HPackEncoder { } public void encodeHeaders( - final ByteArrayBuffer dst, final List
headers) throws CharacterCodingException { + final ByteArrayBuffer dst, final List headers) throws CharacterCodingException { Args.notNull(dst, "ByteArrayBuffer"); Args.notEmpty(headers, "Header list"); encodeHeaders(dst, headers, false, true); Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java Sun Nov 13 14:07:18 2016 @@ -215,10 +215,7 @@ abstract class AbstractHttp2StreamMultip } private void commitHeaders( - final int streamId, final List
headers, final boolean endStream) throws IOException { - if (headers == null || headers.isEmpty()) { - throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Message headers are missing"); - } + final int streamId, final List headers, final boolean endStream) throws IOException { if (streamListener != null) { streamListener.onHeaderOutput(headers); } @@ -1178,6 +1175,9 @@ abstract class AbstractHttp2StreamMultip public void submit(final List
headers, final boolean endStream) throws IOException { outputLock.lock(); try { + if (headers == null || headers.isEmpty()) { + throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Message headers are missing"); + } if (localEndStream) { return; } @@ -1193,7 +1193,7 @@ abstract class AbstractHttp2StreamMultip @Override public void push(final List
headers, final AsyncPushProducer pushProducer) throws HttpException, IOException { if (mode == Mode.CLIENT) { - throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Illegal attempt to pushPromise a response"); + throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Illegal attempt to push a response"); } final int promisedStreamId = generateStreamId(); final Http2StreamChannelImpl channel = new Http2StreamChannelImpl( @@ -1239,15 +1239,19 @@ abstract class AbstractHttp2StreamMultip } @Override - public void endStream(final List
trailers) throws IOException { + public void endStream(final List trailers) throws IOException { outputLock.lock(); try { if (localEndStream) { return; } localEndStream = true; - final RawFrame frame = frameFactory.createData(id, null, true); - commitFrameInternal(frame); + if (trailers != null && !trailers.isEmpty()) { + commitHeaders(id, trailers, true); + } else { + final RawFrame frame = frameFactory.createData(id, null, true); + commitFrameInternal(frame); + } } finally { outputLock.unlock(); } Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java Sun Nov 13 14:07:18 2016 @@ -92,7 +92,7 @@ class ClientHttp2StreamHandler implement } @Override - public void endStream(final List
trailers) throws IOException { + public void endStream(final List trailers) throws IOException { outputChannel.endStream(trailers); requestState = MessageState.COMPLETE; } @@ -181,34 +181,44 @@ class ClientHttp2StreamHandler implement @Override public void consumeHeader(final List
headers, final boolean endStream) throws HttpException, IOException { - if (done.get() || responseState != MessageState.HEADERS) { + if (done.get()) { throw new ProtocolException("Unexpected message headers"); } - final HttpResponse response = DefaultH2ResponseConverter.INSTANCE.convert(headers); - final int status = response.getCode(); - if (status < HttpStatus.SC_INFORMATIONAL) { - throw new ProtocolException("Invalid response: " + status); - } - if (status < HttpStatus.SC_SUCCESS) { - exchangeHandler.consumeInformation(response); - } - if (requestState == MessageState.ACK) { - if (status == HttpStatus.SC_CONTINUE || status >= HttpStatus.SC_SUCCESS) { - requestState = MessageState.BODY; - exchangeHandler.produce(dataChannel); - } - } - if (status < HttpStatus.SC_SUCCESS) { - return; - } + switch (responseState) { + case HEADERS: + final HttpResponse response = DefaultH2ResponseConverter.INSTANCE.convert(headers); + final int status = response.getCode(); + if (status < HttpStatus.SC_INFORMATIONAL) { + throw new ProtocolException("Invalid response: " + status); + } + if (status < HttpStatus.SC_SUCCESS) { + exchangeHandler.consumeInformation(response); + } + if (requestState == MessageState.ACK) { + if (status == HttpStatus.SC_CONTINUE || status >= HttpStatus.SC_SUCCESS) { + requestState = MessageState.BODY; + exchangeHandler.produce(dataChannel); + } + } + if (status < HttpStatus.SC_SUCCESS) { + return; + } - final EntityDetails entityDetails = endStream ? null : new LazyEntityDetails(response); - context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response); - httpProcessor.process(response, entityDetails, context); - connMetrics.incrementResponseCount(); + final EntityDetails entityDetails = endStream ? null : new LazyEntityDetails(response); + context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response); + httpProcessor.process(response, entityDetails, context); + connMetrics.incrementResponseCount(); - exchangeHandler.consumeResponse(response, entityDetails); - responseState = endStream ? MessageState.COMPLETE : MessageState.BODY; + exchangeHandler.consumeResponse(response, entityDetails); + responseState = endStream ? MessageState.COMPLETE : MessageState.BODY; + break; + case BODY: + responseState = MessageState.COMPLETE; + exchangeHandler.streamEnd(headers); + break; + default: + throw new ProtocolException("Unexpected message headers"); + } } @Override Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java Sun Nov 13 14:07:18 2016 @@ -38,9 +38,9 @@ import org.apache.hc.core5.http2.frame.R */ public interface Http2StreamListener { - void onHeaderInput(List
headers); + void onHeaderInput(List headers); - void onHeaderOutput(List
headers); + void onHeaderOutput(List headers); void onFrameInput(RawFrame frame); Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java Sun Nov 13 14:07:18 2016 @@ -94,7 +94,7 @@ public class ServerHttp2StreamHandler im } @Override - public void endStream(final List
trailers) throws IOException { + public void endStream(final List trailers) throws IOException { outputChannel.endStream(trailers); responseState = MessageState.COMPLETE; } @@ -172,54 +172,64 @@ public class ServerHttp2StreamHandler im } @Override - public void consumeHeader(final List
requestHeaders, final boolean requestEndStream) throws HttpException, IOException { - if (done.get() || requestState != MessageState.HEADERS) { + public void consumeHeader(final List
headers, final boolean endStream) throws HttpException, IOException { + if (done.get()) { throw new ProtocolException("Unexpected message headers"); } - requestState = requestEndStream ? MessageState.COMPLETE : MessageState.BODY; - - final HttpRequest request = DefaultH2RequestConverter.INSTANCE.convert(requestHeaders); - final EntityDetails requestEntityDetails = requestEndStream ? null : new LazyEntityDetails(request); - - final AsyncServerExchangeHandler handler; - try { - handler = exchangeHandlerFactory != null ? exchangeHandlerFactory.create(request) : null; - } catch (ProtocolException ex) { - throw new H2StreamResetException(H2Error.PROTOCOL_ERROR, ex.getMessage()); - } - if (handler == null) { - throw new H2StreamResetException(H2Error.REFUSED_STREAM, "Stream refused"); + switch (requestState) { + case HEADERS: + requestState = endStream ? MessageState.COMPLETE : MessageState.BODY; + + final HttpRequest request = DefaultH2RequestConverter.INSTANCE.convert(headers); + final EntityDetails requestEntityDetails = endStream ? null : new LazyEntityDetails(request); + + final AsyncServerExchangeHandler handler; + try { + handler = exchangeHandlerFactory != null ? exchangeHandlerFactory.create(request) : null; + } catch (ProtocolException ex) { + throw new H2StreamResetException(H2Error.PROTOCOL_ERROR, ex.getMessage()); + } + if (handler == null) { + throw new H2StreamResetException(H2Error.REFUSED_STREAM, "Stream refused"); + } + exchangeHandler = handler; + + context.setProtocolVersion(HttpVersion.HTTP_2); + context.setAttribute(HttpCoreContext.HTTP_REQUEST, request); + context.setAttribute(HttpCoreContext.HTTP_CONNECTION, connection); + exchangeHandler.setContext(context); + + httpProcessor.process(request, requestEntityDetails, context); + connMetrics.incrementRequestCount(); + + exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() { + + @Override + public void sendInformation(final HttpResponse response) throws HttpException, IOException { + commitInformation(response); + } + + @Override + public void sendResponse( + final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException { + commitResponse(response, responseEntityDetails); + } + + @Override + public void pushPromise( + final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException { + commitPromise(promise, pushProducer); + } + + }); + break; + case BODY: + responseState = MessageState.COMPLETE; + exchangeHandler.streamEnd(headers); + break; + default: + throw new ProtocolException("Unexpected message headers"); } - exchangeHandler = handler; - - context.setProtocolVersion(HttpVersion.HTTP_2); - context.setAttribute(HttpCoreContext.HTTP_REQUEST, request); - context.setAttribute(HttpCoreContext.HTTP_CONNECTION, connection); - exchangeHandler.setContext(context); - - httpProcessor.process(request, requestEntityDetails, context); - connMetrics.incrementRequestCount(); - - exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() { - - @Override - public void sendInformation(final HttpResponse response) throws HttpException, IOException { - commitInformation(response); - } - - @Override - public void sendResponse( - final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException { - commitResponse(response, responseEntityDetails); - } - - @Override - public void pushPromise( - final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException { - commitPromise(promise, pushProducer); - } - - }); } @Override Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java Sun Nov 13 14:07:18 2016 @@ -88,7 +88,7 @@ class ServerPushHttp2StreamHandler imple } @Override - public void endStream(final List
trailers) throws IOException { + public void endStream(final List trailers) throws IOException { outputChannel.endStream(trailers); responseState = MessageState.COMPLETE; } Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/entity/TestSharedOutputBuffer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/entity/TestSharedOutputBuffer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/entity/TestSharedOutputBuffer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/entity/TestSharedOutputBuffer.java Sun Nov 13 14:07:18 2016 @@ -69,7 +69,7 @@ public class TestSharedOutputBuffer { } @Override - public synchronized void endStream(final List
trailers) throws IOException { + public synchronized void endStream(final List trailers) throws IOException { channel.close(); notifyAll(); } Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java Sun Nov 13 14:07:18 2016 @@ -82,7 +82,7 @@ class InternalHttp2StreamListener implem } @Override - public void onHeaderInput(final List
headers) { + public void onHeaderInput(final List headers) { if (headerLog.isDebugEnabled()) { for (int i = 0; i < headers.size(); i++) { headerLog.debug(id + " << " + headers.get(i)); @@ -91,7 +91,7 @@ class InternalHttp2StreamListener implem } @Override - public void onHeaderOutput(final List
headers) { + public void onHeaderOutput(final List headers) { if (headerLog.isDebugEnabled()) { for (int i = 0; i < headers.size(); i++) { headerLog.debug(id + " >> " + headers.get(i)); Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java Sun Nov 13 14:07:18 2016 @@ -111,7 +111,7 @@ public class EchoHandler implements Asyn } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { endStream = true; if (buffer.position() == 0) { if (outputDataChannel != null) { Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java Sun Nov 13 14:07:18 2016 @@ -44,8 +44,11 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Queue; import java.util.Random; import java.util.StringTokenizer; @@ -87,9 +90,11 @@ import org.apache.hc.core5.http.io.entit import org.apache.hc.core5.http.message.BasicHttpRequest; import org.apache.hc.core5.http.message.BasicHttpResponse; import org.apache.hc.core5.http.nio.AsyncEntityProducer; +import org.apache.hc.core5.http.nio.AsyncRequestConsumer; import org.apache.hc.core5.http.nio.AsyncRequestProducer; import org.apache.hc.core5.http.nio.AsyncResponseProducer; import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; +import org.apache.hc.core5.http.nio.BasicRequestConsumer; import org.apache.hc.core5.http.nio.BasicRequestProducer; import org.apache.hc.core5.http.nio.BasicResponseConsumer; import org.apache.hc.core5.http.nio.BasicResponseProducer; @@ -103,8 +108,11 @@ import org.apache.hc.core5.http.nio.Resp import org.apache.hc.core5.http.nio.SessionOutputBuffer; import org.apache.hc.core5.http.nio.Supplier; import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer; +import org.apache.hc.core5.http.nio.entity.DigestingEntityConsumer; +import org.apache.hc.core5.http.nio.entity.DigestingEntityProducer; import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer; import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer; +import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler; import org.apache.hc.core5.http.nio.support.ResponseTrigger; import org.apache.hc.core5.http.protocol.DefaultHttpProcessor; import org.apache.hc.core5.http.protocol.HttpContext; @@ -118,6 +126,7 @@ import org.apache.hc.core5.reactor.IOSes import org.apache.hc.core5.reactor.SessionRequest; import org.apache.hc.core5.testing.ProtocolScheme; import org.apache.hc.core5.util.CharArrayBuffer; +import org.apache.hc.core5.util.TextUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -819,7 +828,7 @@ public class Http1IntegrationTest extend } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { } @Override @@ -914,7 +923,7 @@ public class Http1IntegrationTest extend } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { } @Override @@ -1296,8 +1305,8 @@ public class Http1IntegrationTest extend } @Override - public void complete() throws IOException { - super.complete(); + public void complete(final List trailers) throws IOException { + super.complete(trailers); } @Override @@ -1551,4 +1560,64 @@ public class Http1IntegrationTest extend Assert.assertEquals("Host header is absent", result2.getBody()); } + @Test + public void testMessageWithTrailers() throws Exception { + server.register("/hello", new Supplier() { + + @Override + public AsyncServerExchangeHandler get() { + return new AbstractServerExchangeHandler>() { + + @Override + protected AsyncRequestConsumer> supplyConsumer( + final HttpRequest request, final HttpContext context) throws HttpException { + return new BasicRequestConsumer<>(new StringAsyncEntityConsumer()); + } + + @Override + protected void handle( + final Message requestMessage, + final ResponseTrigger responseTrigger, + final HttpContext context) throws HttpException, IOException { + responseTrigger.submitResponse(new BasicResponseProducer( + HttpStatus.SC_OK, + new DigestingEntityProducer("MD5", + new StringAsyncEntityProducer("Hello back with some trailers")))); + } + }; + } + + }); + final InetSocketAddress serverEndpoint = server.start(); + + client.start(); + + final Future connectFuture = client.connect( + "localhost", serverEndpoint.getPort(), TIMEOUT, TimeUnit.SECONDS); + final ClientEndpoint streamEndpoint = connectFuture.get(); + + final HttpRequest request1 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/hello")); + final DigestingEntityConsumer entityConsumer = new DigestingEntityConsumer<>("MD5", new StringAsyncEntityConsumer()); + final Future> future1 = streamEndpoint.execute( + new BasicRequestProducer(request1, null), + new BasicResponseConsumer<>(entityConsumer), null); + final Message result1 = future1.get(TIMEOUT, TimeUnit.SECONDS); + Assert.assertNotNull(result1); + final HttpResponse response1 = result1.getHead(); + Assert.assertNotNull(response1); + Assert.assertEquals(200, response1.getCode()); + Assert.assertEquals("Hello back with some trailers", result1.getBody()); + + final List
trailers = entityConsumer.getTrailers(); + Assert.assertNotNull(trailers); + Assert.assertEquals(2, trailers.size()); + final Map map = new HashMap<>(); + for (Header header: trailers) { + map.put(header.getName().toLowerCase(Locale.ROOT), header.getValue()); + } + final String digest = TextUtils.toHexString(entityConsumer.getDigest()); + Assert.assertEquals("MD5", map.get("digest-algo")); + Assert.assertEquals(digest, map.get("digest")); + } + } Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java (original) +++ httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java Sun Nov 13 14:07:18 2016 @@ -43,8 +43,11 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Queue; import java.util.StringTokenizer; import java.util.concurrent.BlockingQueue; @@ -69,9 +72,11 @@ import org.apache.hc.core5.http.impl.nio import org.apache.hc.core5.http.io.entity.ContentType; import org.apache.hc.core5.http.message.BasicHttpRequest; import org.apache.hc.core5.http.nio.AsyncPushConsumer; +import org.apache.hc.core5.http.nio.AsyncRequestConsumer; import org.apache.hc.core5.http.nio.AsyncResponseProducer; import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; import org.apache.hc.core5.http.nio.BasicPushProducer; +import org.apache.hc.core5.http.nio.BasicRequestConsumer; import org.apache.hc.core5.http.nio.BasicRequestProducer; import org.apache.hc.core5.http.nio.BasicResponseConsumer; import org.apache.hc.core5.http.nio.BasicResponseProducer; @@ -80,8 +85,12 @@ import org.apache.hc.core5.http.nio.Data import org.apache.hc.core5.http.nio.ResponseChannel; import org.apache.hc.core5.http.nio.Supplier; import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer; +import org.apache.hc.core5.http.nio.entity.DigestingEntityConsumer; +import org.apache.hc.core5.http.nio.entity.DigestingEntityProducer; import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer; import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer; +import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer; +import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler; import org.apache.hc.core5.http.nio.support.BasicAsyncPushHandler; import org.apache.hc.core5.http.nio.support.ResponseTrigger; import org.apache.hc.core5.http.protocol.HttpContext; @@ -95,6 +104,7 @@ import org.apache.hc.core5.testing.nio.h import org.apache.hc.core5.testing.nio.http.MultiLineEntityProducer; import org.apache.hc.core5.testing.nio.http.MultiLineResponseHandler; import org.apache.hc.core5.testing.nio.http.SingleLineResponseHandler; +import org.apache.hc.core5.util.TextUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -765,7 +775,7 @@ public class Http2IntegrationTest extend } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { } @Override @@ -826,4 +836,64 @@ public class Http2IntegrationTest extend Assert.assertNotNull("You shall not pass", result1.getBody()); } + @Test + public void testMessageWithTrailers() throws Exception { + server.register("/hello", new Supplier() { + + @Override + public AsyncServerExchangeHandler get() { + return new AbstractServerExchangeHandler>() { + + @Override + protected AsyncRequestConsumer> supplyConsumer( + final HttpRequest request, final HttpContext context) throws HttpException { + return new BasicRequestConsumer<>(new StringAsyncEntityConsumer()); + } + + @Override + protected void handle( + final Message requestMessage, + final ResponseTrigger responseTrigger, + final HttpContext context) throws HttpException, IOException { + responseTrigger.submitResponse(new BasicResponseProducer( + HttpStatus.SC_OK, + new DigestingEntityProducer("MD5", + new StringAsyncEntityProducer("Hello back with some trailers")))); + } + }; + } + + }); + final InetSocketAddress serverEndpoint = server.start(); + + client.start(); + + final Future connectFuture = client.connect( + "localhost", serverEndpoint.getPort(), TIMEOUT, TimeUnit.SECONDS); + final ClientEndpoint streamEndpoint = connectFuture.get(); + + final HttpRequest request1 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/hello")); + final DigestingEntityConsumer entityConsumer = new DigestingEntityConsumer<>("MD5", new StringAsyncEntityConsumer()); + final Future> future1 = streamEndpoint.execute( + new BasicRequestProducer(request1, null), + new BasicResponseConsumer<>(entityConsumer), null); + final Message result1 = future1.get(TIMEOUT, TimeUnit.SECONDS); + Assert.assertNotNull(result1); + final HttpResponse response1 = result1.getHead(); + Assert.assertNotNull(response1); + Assert.assertEquals(200, response1.getCode()); + Assert.assertEquals("Hello back with some trailers", result1.getBody()); + + final List
trailers = entityConsumer.getTrailers(); + Assert.assertNotNull(trailers); + Assert.assertEquals(2, trailers.size()); + final Map map = new HashMap<>(); + for (Header header: trailers) { + map.put(header.getName().toLowerCase(Locale.ROOT), header.getValue()); + } + final String digest = TextUtils.toHexString(entityConsumer.getDigest()); + Assert.assertEquals("MD5", map.get("digest-algo")); + Assert.assertEquals(digest, map.get("digest")); + } + } Modified: httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java Sun Nov 13 14:07:18 2016 @@ -390,7 +390,7 @@ public class AsyncReverseProxyExample { } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { synchronized (exchangeState) { System.out.println("[client->proxy] " + exchangeState.id + " end of input"); exchangeState.inputEnd = true; @@ -615,7 +615,7 @@ public class AsyncReverseProxyExample { } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { synchronized (exchangeState) { System.out.println("[proxy<-origin] " + exchangeState.id + " end of input"); exchangeState.outputEnd = true; Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/HttpEntity.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/HttpEntity.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/HttpEntity.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/HttpEntity.java Sun Nov 13 14:07:18 2016 @@ -31,6 +31,9 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.List; + +import org.apache.hc.core5.http.nio.Supplier; /** * An entity that can be sent or received with an HTTP message. @@ -124,6 +127,6 @@ public interface HttpEntity extends Enti * * @since 5.0 */ - TrailerSupplier getTrailers(); + Supplier> getTrailers(); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/IncomingHttpEntity.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/IncomingHttpEntity.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/IncomingHttpEntity.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/IncomingHttpEntity.java Sun Nov 13 14:07:18 2016 @@ -30,12 +30,13 @@ package org.apache.hc.core5.http.impl; import java.io.IOException; import java.io.InputStream; import java.util.Collections; +import java.util.List; import java.util.Set; import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.TrailerSupplier; import org.apache.hc.core5.http.impl.io.EmptyInputStream; import org.apache.hc.core5.http.io.entity.AbstractImmutableHttpEntity; +import org.apache.hc.core5.http.nio.Supplier; /** * Represents entity received from an open connection. @@ -94,7 +95,7 @@ public class IncomingHttpEntity extends } @Override - public TrailerSupplier getTrailers() { + public Supplier> getTrailers() { return null; } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/BHttpConnectionBase.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/BHttpConnectionBase.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/BHttpConnectionBase.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/BHttpConnectionBase.java Sun Nov 13 14:07:18 2016 @@ -36,16 +36,17 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; import org.apache.hc.core5.http.ConnectionClosedException; import org.apache.hc.core5.http.ContentLengthStrategy; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpConnectionMetrics; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpMessage; import org.apache.hc.core5.http.ProtocolVersion; -import org.apache.hc.core5.http.TrailerSupplier; import org.apache.hc.core5.http.config.H1Config; import org.apache.hc.core5.http.impl.BasicHttpConnectionMetrics; import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics; @@ -53,6 +54,7 @@ import org.apache.hc.core5.http.impl.Inc import org.apache.hc.core5.http.io.BHttpConnection; import org.apache.hc.core5.http.io.SessionInputBuffer; import org.apache.hc.core5.http.io.SessionOutputBuffer; +import org.apache.hc.core5.http.nio.Supplier; import org.apache.hc.core5.net.InetAddressUtils; import org.apache.hc.core5.util.Args; @@ -134,7 +136,7 @@ class BHttpConnectionBase implements BHt final long len, final SessionOutputBuffer buffer, final OutputStream outputStream, - final TrailerSupplier trailers) { + final Supplier> trailers) { if (len >= 0) { return new ContentLengthOutputStream(buffer, outputStream, len); } else if (len == ContentLengthStrategy.CHUNKED) { Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/ChunkedOutputStream.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/ChunkedOutputStream.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/ChunkedOutputStream.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/ChunkedOutputStream.java Sun Nov 13 14:07:18 2016 @@ -29,13 +29,14 @@ package org.apache.hc.core5.http.impl.io import java.io.IOException; import java.io.OutputStream; +import java.util.List; import org.apache.hc.core5.http.FormattedHeader; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.StreamClosedException; -import org.apache.hc.core5.http.TrailerSupplier; import org.apache.hc.core5.http.io.SessionOutputBuffer; import org.apache.hc.core5.http.message.BasicLineFormatter; +import org.apache.hc.core5.http.nio.Supplier; import org.apache.hc.core5.util.Args; import org.apache.hc.core5.util.CharArrayBuffer; @@ -61,7 +62,7 @@ public class ChunkedOutputStream extends private boolean wroteLastChunk = false; private boolean closed = false; private final CharArrayBuffer lineBuffer; - private final TrailerSupplier trailers; + private final Supplier> trailerSupplier; /** * Default constructor. @@ -69,17 +70,18 @@ public class ChunkedOutputStream extends * @param minChunkSize The minimum chunk size (excluding last chunk) * @param buffer Session output buffer * @param outputStream Output stream - * @param trailers Trailer supplier. May be {@code null} + * @param trailerSupplier Trailer supplier. May be {@code null} * * @since 5.0 */ - public ChunkedOutputStream(final int minChunkSize, final SessionOutputBuffer buffer, final OutputStream outputStream, final TrailerSupplier trailers) { + public ChunkedOutputStream(final int minChunkSize, final SessionOutputBuffer buffer, final OutputStream outputStream, + final Supplier> trailerSupplier) { super(); this.buffer = Args.notNull(buffer, "Session output buffer"); this.outputStream = Args.notNull(outputStream, "Output stream"); this.cache = new byte[minChunkSize]; this.lineBuffer = new CharArrayBuffer(32); - this.trailers = trailers; + this.trailerSupplier = trailerSupplier; } /** @@ -134,9 +136,10 @@ public class ChunkedOutputStream extends } private void writeTrailers() throws IOException { - final Header[] headers = this.trailers != null ? this.trailers.get() : null; - if (headers != null) { - for (final Header header: headers) { + final List trailers = this.trailerSupplier != null ? this.trailerSupplier.get() : null; + if (trailers != null) { + for (int i = 0; i < trailers.size(); i++) { + final Header header = trailers.get(i); if (header instanceof FormattedHeader) { final CharArrayBuffer chbuffer = ((FormattedHeader) header).getBuffer(); this.buffer.writeLine(chbuffer, this.outputStream); Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java Sun Nov 13 14:07:18 2016 @@ -271,7 +271,7 @@ public abstract class AbstractClassicSer } @Override - public final void streamEnd(final List
trailers) throws HttpException, IOException { + public final void streamEnd(final List trailers) throws HttpException, IOException { Asserts.notNull(inputBuffer, "Input buffer"); inputBuffer.markEndStream(); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentDecoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentDecoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentDecoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentDecoder.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.impl.BasicHttpTransportMetrics; import org.apache.hc.core5.http.nio.ContentDecoder; import org.apache.hc.core5.http.nio.SessionInputBuffer; @@ -144,4 +146,9 @@ public abstract class AbstractContentDec return bytesRead; } + @Override + public List getTrailers() { + return null; + } + } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentEncoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentEncoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentEncoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractContentEncoder.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.WritableByteChannel; +import java.util.List; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics; import org.apache.hc.core5.http.nio.ContentEncoder; import org.apache.hc.core5.http.nio.SessionOutputBuffer; @@ -90,10 +92,14 @@ public abstract class AbstractContentEnc } @Override - public void complete() throws IOException { + public void complete(final List trailers) throws IOException { this.completed = true; } + public final void complete() throws IOException { + complete(null); + } + protected void assertNotCompleted() { Asserts.check(!this.completed, "Encoding process already completed"); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java Sun Nov 13 14:07:18 2016 @@ -35,6 +35,7 @@ import java.nio.channels.ClosedChannelEx import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.WritableByteChannel; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -42,6 +43,7 @@ import java.util.concurrent.locks.Reentr import javax.net.ssl.SSLContext; import org.apache.hc.core5.http.ConnectionClosedException; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpConnection; import org.apache.hc.core5.http.HttpConnectionMetrics; import org.apache.hc.core5.http.HttpException; @@ -411,14 +413,14 @@ abstract class AbstractHttp1StreamDuplex enum MessageDelineation { NONE, CHUNK_CODED, MESSAGE_HEAD} - MessageDelineation endOutputStream() throws IOException { + MessageDelineation endOutputStream(final List trailers) throws IOException { outputLock.lock(); try { if (outgoingMessage == null) { return MessageDelineation.NONE; } final ContentEncoder contentEncoder = outgoingMessage.getBody(); - contentEncoder.complete(); + contentEncoder.complete(trailers); ioSession.setEvent(SelectionKey.OP_WRITE); outgoingMessage = null; if (contentEncoder instanceof ChunkEncoder) { Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkDecoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkDecoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkDecoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkDecoder.java Sun Nov 13 14:07:18 2016 @@ -68,8 +68,7 @@ public class ChunkDecoder extends Abstra private final H1Config constraints; private final List trailerBufs; - - private Header[] footers; + private final List
trailers; /** * @since 4.4 @@ -87,6 +86,7 @@ public class ChunkDecoder extends Abstra this.endOfStream = false; this.constraints = constraints != null ? constraints : H1Config.DEFAULT; this.trailerBufs = new ArrayList<>(); + this.trailers = new ArrayList<>(); } public ChunkDecoder( @@ -169,10 +169,10 @@ public class ChunkDecoder extends Abstra private void processFooters() throws IOException { final int count = this.trailerBufs.size(); if (count > 0) { - this.footers = new Header[this.trailerBufs.size()]; + this.trailers.clear(); for (int i = 0; i < this.trailerBufs.size(); i++) { try { - this.footers[i] = new BufferedHeader(this.trailerBufs.get(i)); + this.trailers.add(new BufferedHeader(this.trailerBufs.get(i))); } catch (final ParseException ex) { throw new IOException(ex.getMessage()); } @@ -269,11 +269,9 @@ public class ChunkDecoder extends Abstra return totalRead; } - public Header[] getFooters() { - if (this.footers != null) { - return this.footers.clone(); - } - return new Header[] {}; + @Override + public List getTrailers() { + return this.trailers.isEmpty() ? null : new ArrayList<>(this.trailers); } @Override Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkEncoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkEncoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkEncoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ChunkEncoder.java Sun Nov 13 14:07:18 2016 @@ -30,10 +30,10 @@ package org.apache.hc.core5.http.impl.ni import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; +import java.util.List; import org.apache.hc.core5.http.FormattedHeader; import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.TrailerSupplier; import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics; import org.apache.hc.core5.http.message.BasicLineFormatter; import org.apache.hc.core5.http.nio.SessionOutputBuffer; @@ -46,9 +46,9 @@ import org.apache.hc.core5.util.CharArra * @since 4.0 */ public class ChunkEncoder extends AbstractContentEncoder { + private final int fragHint; private final CharArrayBuffer lineBuffer; - private final TrailerSupplier trailers; /** * @param channel underlying channel. @@ -64,19 +64,17 @@ public class ChunkEncoder extends Abstra final WritableByteChannel channel, final SessionOutputBuffer buffer, final BasicHttpTransportMetrics metrics, - final int fragementSizeHint, - final TrailerSupplier trailers) { + final int fragementSizeHint) { super(channel, buffer, metrics); this.fragHint = fragementSizeHint > 0 ? fragementSizeHint : 0; this.lineBuffer = new CharArrayBuffer(16); - this.trailers = trailers; } public ChunkEncoder( final WritableByteChannel channel, final SessionOutputBuffer buffer, final BasicHttpTransportMetrics metrics) { - this(channel, buffer, metrics, 0, null); + this(channel, buffer, metrics, 0); } @Override @@ -129,21 +127,21 @@ public class ChunkEncoder extends Abstra } @Override - public void complete() throws IOException { + public void complete(final List trailers) throws IOException { assertNotCompleted(); this.lineBuffer.clear(); this.lineBuffer.append("0"); this.buffer.writeLine(this.lineBuffer); - writeTrailers(); + writeTrailers(trailers); this.lineBuffer.clear(); this.buffer.writeLine(this.lineBuffer); - super.complete(); + super.complete(trailers); } - private void writeTrailers() throws IOException { - final Header[] headers = this.trailers != null ? this.trailers.get() : null; - if (headers != null) { - for (final Header header: headers) { + private void writeTrailers(final List trailers) throws IOException { + if (trailers != null) { + for (int i = 0; i < trailers.size(); i++) { + final Header header = trailers.get(i); if (header instanceof FormattedHeader) { final CharArrayBuffer chbuffer = ((FormattedHeader) header).getBuffer(); buffer.writeLine(chbuffer); Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java Sun Nov 13 14:07:18 2016 @@ -31,12 +31,14 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.hc.core5.http.ConnectionClosedException; import org.apache.hc.core5.http.ConnectionReuseStrategy; import org.apache.hc.core5.http.ContentLengthStrategy; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; @@ -148,8 +150,8 @@ public class ClientHttp1StreamDuplexer e } @Override - public void complete() throws IOException { - endOutputStream(); + public void complete(final List trailers) throws IOException { + endOutputStream(trailers); } @Override @@ -159,7 +161,7 @@ public class ClientHttp1StreamDuplexer e @Override public void abortOutput() throws IOException { - final MessageDelineation messageDelineation = endOutputStream(); + final MessageDelineation messageDelineation = endOutputStream(null); if (messageDelineation == MessageDelineation.MESSAGE_HEAD) { inconsistent = true; requestShutdown(ShutdownType.GRACEFUL); @@ -266,7 +268,7 @@ public class ClientHttp1StreamDuplexer e if (len >= 0) { return new LengthDelimitedEncoder(channel, buffer, metrics, len, fragmentSizeHint); } else if (len == ContentLengthStrategy.CHUNKED) { - return new ChunkEncoder(channel, buffer, metrics, fragmentSizeHint, null); + return new ChunkEncoder(channel, buffer, metrics, fragmentSizeHint); } else { throw new LengthRequiredException("Length required"); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java Sun Nov 13 14:07:18 2016 @@ -93,8 +93,8 @@ class ClientHttp1StreamHandler implement } @Override - public void endStream(final List
trailers) throws IOException { - outputChannel.complete(); + public void endStream(final List trailers) throws IOException { + outputChannel.complete(trailers); requestState = MessageState.COMPLETE; } @@ -273,7 +273,7 @@ class ClientHttp1StreamHandler implement } if (contentDecoder.isCompleted()) { responseState = MessageState.COMPLETE; - exchangeHandler.streamEnd(null); + exchangeHandler.streamEnd(contentDecoder.getTrailers()); return total > 0 ? total : -1; } else { return total; Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/LengthDelimitedEncoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/LengthDelimitedEncoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/LengthDelimitedEncoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/LengthDelimitedEncoder.java Sun Nov 13 14:07:18 2016 @@ -136,7 +136,7 @@ public class LengthDelimitedEncoder exte } } if (this.remaining <= 0) { - super.complete(); + super.complete(null); } return total; } @@ -164,7 +164,7 @@ public class LengthDelimitedEncoder exte } this.remaining -= bytesWritten; if (this.remaining <= 0) { - super.complete(); + super.complete(null); } return bytesWritten; } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java Sun Nov 13 14:07:18 2016 @@ -31,12 +31,14 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.hc.core5.http.ConnectionClosedException; import org.apache.hc.core5.http.ConnectionReuseStrategy; import org.apache.hc.core5.http.ContentLengthStrategy; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; @@ -151,8 +153,8 @@ public class ServerHttp1StreamDuplexer e } @Override - public void complete() throws IOException { - endOutputStream(); + public void complete(final List trailers) throws IOException { + endOutputStream(trailers); } @Override @@ -162,7 +164,7 @@ public class ServerHttp1StreamDuplexer e @Override public void abortOutput() throws IOException { - final MessageDelineation messageDelineation = endOutputStream(); + final MessageDelineation messageDelineation = endOutputStream(null); if (messageDelineation == MessageDelineation.MESSAGE_HEAD) { inconsistent = true; } @@ -253,7 +255,7 @@ public class ServerHttp1StreamDuplexer e if (len >= 0) { return new LengthDelimitedEncoder(channel, buffer, metrics, len, fragmentSizeHint); } else if (len == ContentLengthStrategy.CHUNKED) { - return new ChunkEncoder(channel, buffer, metrics, fragmentSizeHint, null); + return new ChunkEncoder(channel, buffer, metrics, fragmentSizeHint); } else { return new IdentityEncoder(channel, buffer, metrics, fragmentSizeHint); } @@ -427,10 +429,10 @@ public class ServerHttp1StreamDuplexer e } @Override - public void complete() throws IOException { + public void complete(final List trailers) throws IOException { synchronized (this) { if (direct) { - channel.complete(); + channel.complete(trailers); } else { completed = true; } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java Sun Nov 13 14:07:18 2016 @@ -96,8 +96,8 @@ class ServerHttp1StreamHandler implement } @Override - public void endStream(final List
trailers) throws IOException { - outputChannel.complete(); + public void endStream(final List trailers) throws IOException { + outputChannel.complete(trailers); responseState = MessageState.COMPLETE; } @@ -320,7 +320,7 @@ class ServerHttp1StreamHandler implement } if (contentDecoder.isCompleted()) { requestState = MessageState.COMPLETE; - exchangeHandler.streamEnd(null); + exchangeHandler.streamEnd(contentDecoder.getTrailers()); return total > 0 ? total : -1; } else { return total; Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/entity/AbstractClassicEntityConsumer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/entity/AbstractClassicEntityConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/entity/AbstractClassicEntityConsumer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/entity/AbstractClassicEntityConsumer.java Sun Nov 13 14:07:18 2016 @@ -108,7 +108,7 @@ public abstract class AbstractClassicEnt } @Override - public final void streamEnd(final List
trailers) throws HttpException, IOException { + public final void streamEnd(final List trailers) throws HttpException, IOException { buffer.markEndStream(); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java Sun Nov 13 14:07:18 2016 @@ -28,9 +28,11 @@ package org.apache.hc.core5.http.io.entity; import java.util.Collections; +import java.util.List; import java.util.Set; -import org.apache.hc.core5.http.TrailerSupplier; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.nio.Supplier; /** * Abstract base class for mutable entities. Provides the commonly used attributes for streamed and @@ -79,7 +81,7 @@ public abstract class AbstractHttpEntity } @Override - public TrailerSupplier getTrailers() { + public Supplier> getTrailers() { return null; } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWithTrailers.java Sun Nov 13 14:07:18 2016 @@ -30,12 +30,14 @@ package org.apache.hc.core5.http.io.enti import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Arrays; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.TrailerSupplier; +import org.apache.hc.core5.http.nio.Supplier; import org.apache.hc.core5.util.Args; /** @@ -46,7 +48,7 @@ import org.apache.hc.core5.util.Args; public class HttpEntityWithTrailers implements HttpEntity { private final HttpEntity wrappedEntity; - private final Header[] trailers; + private final List
trailers; /** * Creates a new entity wrapper. @@ -54,7 +56,7 @@ public class HttpEntityWithTrailers impl public HttpEntityWithTrailers(final HttpEntity wrappedEntity, final Header... trailers) { super(); this.wrappedEntity = Args.notNull(wrappedEntity, "Wrapped entity"); - this.trailers = trailers; + this.trailers = Arrays.asList(trailers); } @Override @@ -100,10 +102,10 @@ public class HttpEntityWithTrailers impl } @Override - public TrailerSupplier getTrailers() { - return new TrailerSupplier() { + public Supplier> getTrailers() { + return new Supplier>() { @Override - public Header[] get() { + public List get() { return trailers; } }; Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/entity/HttpEntityWrapper.java Sun Nov 13 14:07:18 2016 @@ -30,10 +30,12 @@ package org.apache.hc.core5.http.io.enti import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.List; import java.util.Set; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.TrailerSupplier; +import org.apache.hc.core5.http.nio.Supplier; import org.apache.hc.core5.util.Args; /** @@ -101,7 +103,7 @@ public class HttpEntityWrapper implement } @Override - public TrailerSupplier getTrailers() { + public Supplier> getTrailers() { return wrappedEntity.getTrailers(); } Modified: 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/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncDataConsumer.java Sun Nov 13 14:07:18 2016 @@ -44,6 +44,6 @@ public interface AsyncDataConsumer exten int consume(ByteBuffer src) throws IOException; - void streamEnd(List
trailers) throws HttpException, IOException; + void streamEnd(List trailers) throws HttpException, IOException; } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestConsumer.java Sun Nov 13 14:07:18 2016 @@ -91,7 +91,7 @@ public class BasicRequestConsumer imp } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { dataConsumer.streamEnd(trailers); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicResponseConsumer.java Sun Nov 13 14:07:18 2016 @@ -97,7 +97,7 @@ public class BasicResponseConsumer im } @Override - public void streamEnd(final List
trailers) throws HttpException, IOException { + public void streamEnd(final List trailers) throws HttpException, IOException { dataConsumer.streamEnd(trailers); } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentDecoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentDecoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentDecoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentDecoder.java Sun Nov 13 14:07:18 2016 @@ -29,6 +29,9 @@ 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; /** * Abstract HTTP content decoder. HTTP content decoders can be used @@ -58,4 +61,13 @@ public interface ContentDecoder { */ boolean isCompleted(); + /** + * Returns content trailers if available + * + * @return list of trailers + * + * @since 5.0 + */ + List getTrailers(); + } Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentEncoder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentEncoder.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentEncoder.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ContentEncoder.java Sun Nov 13 14:07:18 2016 @@ -29,6 +29,9 @@ 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; /** * Abstract HTTP content encoder. HTTP content encoders can be used @@ -53,7 +56,7 @@ public interface ContentEncoder { * * @throws IOException if I/O error occurs while writing content */ - void complete() throws IOException; + void complete(List trailers) throws IOException; /** * Returns {@code true} if the entity has been transferred in its Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/DataStreamChannel.java URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/DataStreamChannel.java?rev=1769497&r1=1769496&r2=1769497&view=diff ============================================================================== --- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/DataStreamChannel.java (original) +++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/DataStreamChannel.java Sun Nov 13 14:07:18 2016 @@ -47,6 +47,6 @@ public interface DataStreamChannel exten void requestOutput(); - void endStream(List
trailers) throws IOException; + void endStream(List trailers) throws IOException; }