diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandler.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandler.java index 3a8afaec48..710612d535 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandler.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandler.java @@ -18,6 +18,7 @@ package io.netty.handler.codec.http2; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.handler.codec.http.EmptyHttpHeaders; import io.netty.handler.codec.http.FullHttpMessage; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; @@ -82,18 +83,21 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler { // Convert and write the headers. Http2Headers http2Headers = HttpConversionUtil.toHttp2Headers(httpMsg, validateHeaders); endStream = msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable(); - encoder.writeHeaders(ctx, currentStreamId, http2Headers, 0, endStream, promiseAggregator.newPromise()); + writeHeaders(ctx, encoder, currentStreamId, httpMsg.headers(), http2Headers, + endStream, promiseAggregator); } if (!endStream && msg instanceof HttpContent) { boolean isLastContent = false; - Http2Headers trailers = EmptyHttp2Headers.INSTANCE; + HttpHeaders trailers = EmptyHttpHeaders.INSTANCE; + Http2Headers http2Trailers = EmptyHttp2Headers.INSTANCE; if (msg instanceof LastHttpContent) { isLastContent = true; // Convert any trailing headers. final LastHttpContent lastContent = (LastHttpContent) msg; - trailers = HttpConversionUtil.toHttp2Headers(lastContent.trailingHeaders(), validateHeaders); + trailers = lastContent.trailingHeaders(); + http2Trailers = HttpConversionUtil.toHttp2Headers(trailers, validateHeaders); } // Write the data @@ -104,7 +108,7 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler { if (!trailers.isEmpty()) { // Write trailing headers. - encoder.writeHeaders(ctx, currentStreamId, trailers, 0, true, promiseAggregator.newPromise()); + writeHeaders(ctx, encoder, currentStreamId, trailers, http2Trailers, true, promiseAggregator); } } } catch (Throwable t) { @@ -116,4 +120,15 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler { promiseAggregator.doneAllocatingPromises(); } } + + private static void writeHeaders(ChannelHandlerContext ctx, Http2ConnectionEncoder encoder, int streamId, + HttpHeaders headers, Http2Headers http2Headers, boolean endStream, + SimpleChannelPromiseAggregator promiseAggregator) { + int dependencyId = headers.getInt( + HttpConversionUtil.ExtensionHeaderNames.STREAM_DEPENDENCY_ID.text(), 0); + short weight = headers.getShort( + HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT); + encoder.writeHeaders(ctx, streamId, http2Headers, dependencyId, weight, false, + 0, endStream, promiseAggregator.newPromise()); + } } diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapter.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapter.java index a71bd7a080..4e2d6f5a27 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapter.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapter.java @@ -268,6 +268,14 @@ public class InboundHttp2ToHttpAdapter extends Http2EventAdapter { Http2Stream stream = connection.stream(streamId); FullHttpMessage msg = processHeadersBegin(ctx, stream, headers, endOfStream, true, true); if (msg != null) { + // Add headers for dependency and weight. + // See https://github.com/netty/netty/issues/5866 + if (streamDependency != Http2CodecUtil.CONNECTION_STREAM_ID) { + msg.headers().setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_DEPENDENCY_ID.text(), + streamDependency); + } + msg.headers().setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), weight); + processHeadersEnd(ctx, stream, msg, endOfStream); } } diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java index 30c5284381..009b67be42 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java @@ -140,6 +140,7 @@ public class InboundHttp2ToHttpAdapterTest { httpHeaders.set(HttpHeaderNames.HOST, "example.org"); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")). scheme(new AsciiString("https")).authority(new AsciiString("example.org")) .path(new AsciiString("/some/path/resource2")); @@ -172,6 +173,7 @@ public class InboundHttp2ToHttpAdapterTest { httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); httpHeaders.set(HttpHeaderNames.COOKIE, "a=b; c=d; e=f"); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")). scheme(new AsciiString("https")).authority(new AsciiString("example.org")) .path(new AsciiString("/some/path/resource2")) @@ -207,6 +209,7 @@ public class InboundHttp2ToHttpAdapterTest { httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); httpHeaders.set(HttpHeaderNames.COOKIE, "a=b; c=d; e=f"); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")). scheme(new AsciiString("https")).authority(new AsciiString("example.org")) .path(new AsciiString("/some/path/resource2")) @@ -261,6 +264,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path( new AsciiString("/some/path/resource2")); runInChannel(clientChannel, new Http2Runnable() { @@ -293,6 +297,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path( new AsciiString("/some/path/resource2")); final int midPoint = text.length() / 2; @@ -329,6 +334,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path( new AsciiString("/some/path/resource2")); runInChannel(clientChannel, new Http2Runnable() { @@ -364,6 +370,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); HttpHeaders trailingHeaders = request.trailingHeaders(); trailingHeaders.set(of("FoO"), of("goo")); trailingHeaders.set(of("foO2"), of("goo2")); @@ -404,6 +411,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); HttpHeaders trailingHeaders = request.trailingHeaders(); trailingHeaders.set(of("Foo"), of("goo")); trailingHeaders.set(of("fOo2"), of("goo2")); @@ -449,10 +457,11 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); HttpHeaders httpHeaders2 = request2.headers(); httpHeaders2.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 5); httpHeaders2.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_DEPENDENCY_ID.text(), 3); - httpHeaders2.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), 123); + httpHeaders2.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 123); httpHeaders2.setInt(HttpHeaderNames.CONTENT_LENGTH, text2.length()); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("PUT")).path( new AsciiString("/some/path/resource")); @@ -502,9 +511,11 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); HttpHeaders httpHeaders2 = request2.headers(); httpHeaders2.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 5); httpHeaders2.setInt(HttpHeaderNames.CONTENT_LENGTH, text2.length()); + httpHeaders2.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("PUT")).path( new AsciiString("/some/path/resource")); final Http2Headers http2Headers2 = new DefaultHttp2Headers().method(new AsciiString("PUT")).path( @@ -512,7 +523,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders3 = request3.headers(); httpHeaders3.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 5); httpHeaders3.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_DEPENDENCY_ID.text(), 3); - httpHeaders3.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), 222); + httpHeaders3.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 222); httpHeaders3.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); runInChannel(clientChannel, new Http2Runnable() { @Override @@ -559,6 +570,7 @@ public class InboundHttp2ToHttpAdapterTest { HttpHeaders httpHeaders = response.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length()); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); HttpHeaders httpHeaders2 = response2.headers(); httpHeaders2.set(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), "https"); httpHeaders2.set(HttpHeaderNames.HOST, "example.org"); @@ -569,6 +581,7 @@ public class InboundHttp2ToHttpAdapterTest { httpHeaders = request.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); final Http2Headers http2Headers3 = new DefaultHttp2Headers().method(new AsciiString("GET")) .path(new AsciiString("/push/test")); runInChannel(clientChannel, new Http2Runnable() { @@ -621,6 +634,8 @@ public class InboundHttp2ToHttpAdapterTest { httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.set(HttpHeaderNames.EXPECT, HttpHeaderValues.CONTINUE); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); + final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("PUT")) .path(new AsciiString("/info/test")) .set(new AsciiString(HttpHeaderNames.EXPECT.toString()), @@ -671,6 +686,8 @@ public class InboundHttp2ToHttpAdapterTest { httpHeaders = response2.headers(); httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0); + httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16); + final Http2Headers http2HeadersResponse2 = new DefaultHttp2Headers().status(new AsciiString("200")); runInChannel(serverConnectedChannel, new Http2Runnable() { @Override