Author: markt Date: Wed Oct 19 13:31:26 2016 New Revision: 1765589 URL: http://svn.apache.org/viewvc?rev=1765589&view=rev Log: Add initial support for trailer headers
Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java tomcat/trunk/java/org/apache/coyote/http2/Stream.java tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1765589&r1=1765588&r2=1765589&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Wed Oct 19 13:31:26 2016 @@ -1247,8 +1247,9 @@ class Http2UpgradeHandler extends Abstra setMaxProcessedStream(streamId); Stream stream = getStream(streamId, connectionState.get().isNewStreamAllowed()); if (stream != null && stream.isActive()) { - stream.receivedEndOfHeaders(); - processStreamOnContainerThread(stream); + if (stream.receivedEndOfHeaders()) { + processStreamOnContainerThread(stream); + } } } Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1765589&r1=1765588&r2=1765589&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Wed Oct 19 13:31:26 2016 @@ -293,13 +293,14 @@ class Stream extends AbstractStream impl } - final void receivedEndOfHeaders() { + final boolean receivedEndOfHeaders() { // Cookie headers need to be concatenated into a single header // See RFC 7540 8.1.2.5 // Can only do this once the headers are fully received if (cookieHeader != null) { coyoteRequest.getMimeHeaders().addValue("cookie").setString(cookieHeader.toString()); } + return headerState == HEADER_STATE_REGULAR || headerState == HEADER_STATE_PSEUDO; } @@ -362,6 +363,9 @@ class Stream extends AbstractStream impl final void receivedEndOfStream() { + synchronized (inputBuffer) { + inputBuffer.notifyAll(); + } state.recievedEndOfStream(); } Modified: tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java?rev=1765589&r1=1765588&r2=1765589&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java (original) +++ tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java Wed Oct 19 13:31:26 2016 @@ -69,6 +69,8 @@ public abstract class Http2TestBase exte EMPTY_HTTP2_SETTINGS_HEADER = "HTTP2-Settings: " + Base64.encodeBase64String(empty) + "\r\n"; } + private static final String TRAILER_HEADER_NAME = "X-TrailerTest"; + private Socket s; protected HpackEncoder hpackEncoder; protected Input input; @@ -294,6 +296,13 @@ public abstract class Http2TestBase exte protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, int streamId) { + buildPostRequest(headersFrameHeader, headersPayload, useExpectation, dataFrameHeader, + dataPayload, padding, null, null, streamId); + } + + protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, + boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, + byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { MimeHeaders headers = new MimeHeaders(); headers.addValue(":method").setString("POST"); headers.addValue(":path").setString("/simple"); @@ -332,12 +341,31 @@ public abstract class Http2TestBase exte ByteUtil.setThreeBytes(dataFrameHeader, 0, dataPayload.limit()); // Data is type 0 // Flags: End of stream 1, Padding 8 - if (padding == null) { + if (trailersPayload == null) { dataFrameHeader[4] = 0x01; } else { - dataFrameHeader[4] = 0x09; + dataFrameHeader[4] = 0x00; + } + if (padding != null) { + dataFrameHeader[4] += 0x08; } ByteUtil.set31Bits(dataFrameHeader, 5, streamId); + + // Trailers + if (trailersPayload != null) { + MimeHeaders trailerHeaders = new MimeHeaders(); + trailerHeaders.addValue(TRAILER_HEADER_NAME).setString("xxxx"); + hpackEncoder.encode(trailerHeaders, trailersPayload); + + trailersPayload.flip(); + + ByteUtil.setThreeBytes(trailersFrameHeader, 0, trailersPayload.limit()); + trailersFrameHeader[3] = FrameType.HEADERS.getIdByte(); + // Flags. end of headers (0x04) and end of stream (0x01) + trailersFrameHeader[4] = 0x05; + // Stream id + ByteUtil.set31Bits(trailersFrameHeader, 5, streamId); + } } @@ -1049,6 +1077,12 @@ public abstract class Http2TestBase exte ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); IOTools.flow(bais, resp.getOutputStream()); + + // Check for trailer headers + String trailerValue = req.getHeader(TRAILER_HEADER_NAME); + if (trailerValue != null) { + resp.getOutputStream().write(trailerValue.getBytes(StandardCharsets.UTF_8)); + } } } Modified: tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java?rev=1765589&r1=1765588&r2=1765589&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java (original) +++ tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java Wed Oct 19 13:31:26 2016 @@ -33,6 +33,44 @@ import org.junit.Test; public class TestHttp2Section_8_1 extends Http2TestBase { @Test + public void testPostWithTrailerHeaders() throws Exception { + http2Connect(); + + byte[] headersFrameHeader = new byte[9]; + ByteBuffer headersPayload = ByteBuffer.allocate(128); + byte[] dataFrameHeader = new byte[9]; + ByteBuffer dataPayload = ByteBuffer.allocate(256); + byte[] trailerFrameHeader = new byte[9]; + ByteBuffer trailerPayload = ByteBuffer.allocate(256); + + buildPostRequest(headersFrameHeader, headersPayload, false, dataFrameHeader, dataPayload, + null, trailerFrameHeader, trailerPayload, 3); + + // Write the headers + writeFrame(headersFrameHeader, headersPayload); + // Body + writeFrame(dataFrameHeader, dataPayload); + // Trailers + writeFrame(trailerFrameHeader, trailerPayload); + + parser.readFrame(true); + parser.readFrame(true); + parser.readFrame(true); + parser.readFrame(true); + + Assert.assertEquals("0-WindowSize-[256]\n" + + "3-WindowSize-[256]\n" + + "3-HeadersStart\n" + + "3-Header-[:status]-[200]\n" + + "3-Header-[date]-["+ DEFAULT_DATE + "]\n" + + "3-HeadersEnd\n" + + "3-Body-260\n" + + "3-EndOfStream\n", + output.getTrace()); + } + + + @Test public void testSendAck() throws Exception { http2Connect(); --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org