From 76d5cdb9e8d3676f0306daac07a3d93e24430a46 Mon Sep 17 00:00:00 2001 From: Aayush Atharva Date: Thu, 5 Nov 2020 20:23:32 +0530 Subject: [PATCH] Add HttpScheme Support in HttpToHttp2ConnectionHandler (#10641) Motivation: We should have a method to add `HttpScheme` if `HttpRequest` does not contain `x-http2-scheme` then we should use add it if `HttpToHttp2ConnectionHandler` is build using specified `HttpScheme`. Modification: Added `HttpScheme` in `HttpToHttp2ConnectionHandlerBuilder`. Result: Automatically add `HttpScheme` if missing in `HttpRequest`. --- .../http2/HttpToHttp2ConnectionHandler.java | 15 +++++++++++ .../HttpToHttp2ConnectionHandlerBuilder.java | 18 +++++++++++-- .../HttpToHttp2ConnectionHandlerTest.java | 25 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) 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 e164f2b7a0..70d02c16c5 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 @@ -23,6 +23,7 @@ import io.netty.handler.codec.http.FullHttpMessage; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMessage; +import io.netty.handler.codec.http.HttpScheme; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http2.Http2CodecUtil.SimpleChannelPromiseAggregator; import io.netty.util.ReferenceCountUtil; @@ -38,6 +39,7 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler { private final boolean validateHeaders; private int currentStreamId; + private HttpScheme httpScheme; protected HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings, boolean validateHeaders) { @@ -48,8 +50,15 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler { protected HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings, boolean validateHeaders, boolean decoupleCloseAndGoAway) { + this(decoder, encoder, initialSettings, validateHeaders, decoupleCloseAndGoAway, null); + } + + protected HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, + Http2Settings initialSettings, boolean validateHeaders, + boolean decoupleCloseAndGoAway, HttpScheme httpScheme) { super(decoder, encoder, initialSettings, decoupleCloseAndGoAway); this.validateHeaders = validateHeaders; + this.httpScheme = httpScheme; } /** @@ -87,6 +96,12 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler { // Provide the user the opportunity to specify the streamId currentStreamId = getStreamId(httpMsg.headers()); + // Add HttpScheme if it's defined in constructor and header does not contain it. + if (httpScheme != null && + !httpMsg.headers().contains(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text())) { + httpMsg.headers().set(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), httpScheme.name()); + } + // Convert and write the headers. Http2Headers http2Headers = HttpConversionUtil.toHttp2Headers(httpMsg, validateHeaders); endStream = msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable(); diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerBuilder.java index f733014a11..52a71d6d42 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerBuilder.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerBuilder.java @@ -16,6 +16,7 @@ package io.netty.handler.codec.http2; +import io.netty.handler.codec.http.HttpScheme; import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector; import io.netty.util.internal.UnstableApi; @@ -26,6 +27,8 @@ import io.netty.util.internal.UnstableApi; public final class HttpToHttp2ConnectionHandlerBuilder extends AbstractHttp2ConnectionHandlerBuilder { + private HttpScheme httpScheme; + @Override public HttpToHttp2ConnectionHandlerBuilder validateHeaders(boolean validateHeaders) { return super.validateHeaders(validateHeaders); @@ -58,7 +61,7 @@ public final class HttpToHttp2ConnectionHandlerBuilder extends @Override public HttpToHttp2ConnectionHandlerBuilder codec(Http2ConnectionDecoder decoder, - Http2ConnectionEncoder encoder) { + Http2ConnectionEncoder encoder) { return super.codec(decoder, encoder); } @@ -90,6 +93,17 @@ public final class HttpToHttp2ConnectionHandlerBuilder extends return super.decoupleCloseAndGoAway(decoupleCloseAndGoAway); } + /** + * Add {@code scheme} in {@link Http2Headers} if not already present. + * + * @param httpScheme {@link HttpScheme} type + * @return {@code this}. + */ + public HttpToHttp2ConnectionHandlerBuilder httpScheme(HttpScheme httpScheme) { + this.httpScheme = httpScheme; + return self(); + } + @Override public HttpToHttp2ConnectionHandler build() { return super.build(); @@ -99,6 +113,6 @@ public final class HttpToHttp2ConnectionHandlerBuilder extends protected HttpToHttp2ConnectionHandler build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings) { return new HttpToHttp2ConnectionHandler(decoder, encoder, initialSettings, isValidateHeaders(), - decoupleCloseAndGoAway()); + decoupleCloseAndGoAway(), httpScheme); } } diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java index 50f7c8015c..9e9527ff22 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java @@ -37,6 +37,7 @@ import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpScheme; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http2.Http2TestUtil.FrameCountDown; import io.netty.util.AsciiString; @@ -147,6 +148,29 @@ public class HttpToHttp2ConnectionHandlerTest { verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise)); } + @Test + public void testHttpScheme() throws Exception { + bootstrapEnv(2, 1, 0); + final FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, + "http://my-user_name@www.example.org:5555/example"); + final HttpHeaders httpHeaders = request.headers(); + httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 5); + httpHeaders.set(HttpHeaderNames.HOST, "my-user_name@www.example.org:5555"); + httpHeaders.add(of("foo"), of("goo")); + httpHeaders.add(of("foo"), of("goo2")); + httpHeaders.add(of("foo2"), of("goo2")); + final Http2Headers http2Headers = + new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/example")) + .authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("http")) + .scheme(new AsciiString("http")) + .add(new AsciiString("foo"), new AsciiString("goo")) + .add(new AsciiString("foo"), new AsciiString("goo2")) + .add(new AsciiString("foo2"), new AsciiString("goo2")); + + ChannelPromise writePromise = newPromise(); + verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise)); + } + @Test public void testMultipleCookieEntriesAreCombined() throws Exception { bootstrapEnv(2, 1, 0); @@ -520,6 +544,7 @@ public class HttpToHttp2ConnectionHandlerTest { p.addLast(new HttpToHttp2ConnectionHandlerBuilder() .server(true) .frameListener(serverFrameCountDown) + .httpScheme(HttpScheme.HTTP) .build()); serverChannelLatch.countDown(); }