Supply a builder for Http2Codec
Motivation: DefaultHttp2FrameWriter has constructors that it would be a hassle to expose as configuration parameters on Http2Codec. We should instead make a builder for Http2Codec. Modifications: Get rid of the public constructors on Http2Codec and instead make sure you can always use the builder where you would have used the constructor before. Result: Http2Codec can be configured more flexibly, and the SensitivityDetector can be configured.
This commit is contained in:
parent
963cd22a05
commit
cf26227c6c
@ -19,7 +19,6 @@ package io.netty.handler.codec.http2;
|
|||||||
import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
|
import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
|
||||||
import io.netty.util.internal.UnstableApi;
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
|
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_RESERVED_STREAMS;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_RESERVED_STREAMS;
|
||||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
|
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
|
||||||
@ -79,7 +78,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
|
|||||||
private static final SensitivityDetector DEFAULT_HEADER_SENSITIVITY_DETECTOR = Http2HeadersEncoder.NEVER_SENSITIVE;
|
private static final SensitivityDetector DEFAULT_HEADER_SENSITIVITY_DETECTOR = Http2HeadersEncoder.NEVER_SENSITIVE;
|
||||||
|
|
||||||
// The properties that can always be set.
|
// The properties that can always be set.
|
||||||
private Http2Settings initialSettings = new Http2Settings().maxHeaderListSize(DEFAULT_HEADER_LIST_SIZE);
|
private Http2Settings initialSettings = Http2Settings.defaultSettings();
|
||||||
private Http2FrameListener frameListener;
|
private Http2FrameListener frameListener;
|
||||||
private long gracefulShutdownTimeoutMillis = DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
|
private long gracefulShutdownTimeoutMillis = DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
|
||||||
|
|
||||||
|
@ -16,70 +16,18 @@
|
|||||||
package io.netty.handler.codec.http2;
|
package io.netty.handler.codec.http2;
|
||||||
|
|
||||||
import io.netty.channel.ChannelDuplexHandler;
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
import io.netty.channel.ChannelHandler;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.util.internal.UnstableApi;
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
import static io.netty.handler.logging.LogLevel.INFO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An HTTP/2 channel handler that adds a {@link Http2FrameCodec} and {@link Http2MultiplexCodec} to the pipeline before
|
* An HTTP/2 channel handler that adds a {@link Http2FrameCodec} and {@link Http2MultiplexCodec} to the pipeline before
|
||||||
* removing itself.
|
* removing itself.
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public final class Http2Codec extends ChannelDuplexHandler {
|
public final class Http2Codec extends ChannelDuplexHandler {
|
||||||
private static final Http2FrameLogger HTTP2_FRAME_LOGGER = new Http2FrameLogger(INFO, Http2Codec.class);
|
|
||||||
|
|
||||||
private final Http2FrameCodec frameCodec;
|
private final Http2FrameCodec frameCodec;
|
||||||
private final Http2MultiplexCodec multiplexCodec;
|
private final Http2MultiplexCodec multiplexCodec;
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new handler whose child channels run in the same event loop as this handler.
|
|
||||||
*
|
|
||||||
* @param server {@code true} this is a server
|
|
||||||
* @param streamHandler the handler added to channels for remotely-created streams. It must be
|
|
||||||
* {@link ChannelHandler.Sharable}. {@code null} if the event loop from the parent channel should be used.
|
|
||||||
*/
|
|
||||||
public Http2Codec(boolean server, ChannelHandler streamHandler) {
|
|
||||||
this(server, new Http2StreamChannelBootstrap().handler(streamHandler), HTTP2_FRAME_LOGGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new handler whose child channels run in the same event loop as this handler.
|
|
||||||
*
|
|
||||||
* @param server {@code true} this is a server
|
|
||||||
* @param streamHandler the handler added to channels for remotely-created streams. It must be
|
|
||||||
* {@link ChannelHandler.Sharable}. {@code null} if the event loop from the parent channel should be used.
|
|
||||||
* @param initialSettings non default initial settings to send to peer
|
|
||||||
*/
|
|
||||||
public Http2Codec(boolean server, ChannelHandler streamHandler, Http2Settings initialSettings) {
|
|
||||||
this(server, new Http2StreamChannelBootstrap().handler(streamHandler), HTTP2_FRAME_LOGGER,
|
|
||||||
initialSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new handler whose child channels run in a different event loop.
|
|
||||||
*
|
|
||||||
* @param server {@code true} this is a server
|
|
||||||
* @param bootstrap bootstrap used to instantiate child channels for remotely-created streams.
|
|
||||||
*/
|
|
||||||
public Http2Codec(boolean server, Http2StreamChannelBootstrap bootstrap, Http2FrameLogger frameLogger) {
|
|
||||||
this(server, bootstrap, new DefaultHttp2FrameWriter(), frameLogger, new Http2Settings());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new handler whose child channels run in a different event loop.
|
|
||||||
*
|
|
||||||
* @param server {@code true} this is a server
|
|
||||||
* @param bootstrap bootstrap used to instantiate child channels for remotely-created streams.
|
|
||||||
* @param initialSettings non default initial settings to send to peer
|
|
||||||
*/
|
|
||||||
public Http2Codec(boolean server, Http2StreamChannelBootstrap bootstrap, Http2FrameLogger frameLogger,
|
|
||||||
Http2Settings initialSettings) {
|
|
||||||
this(server, bootstrap, new DefaultHttp2FrameWriter(), frameLogger, initialSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visible for testing
|
|
||||||
Http2Codec(boolean server, Http2StreamChannelBootstrap bootstrap, Http2FrameWriter frameWriter,
|
Http2Codec(boolean server, Http2StreamChannelBootstrap bootstrap, Http2FrameWriter frameWriter,
|
||||||
Http2FrameLogger frameLogger, Http2Settings initialSettings) {
|
Http2FrameLogger frameLogger, Http2Settings initialSettings) {
|
||||||
frameCodec = new Http2FrameCodec(server, frameWriter, frameLogger, initialSettings);
|
frameCodec = new Http2FrameCodec(server, frameWriter, frameLogger, initialSettings);
|
||||||
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http2;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
|
||||||
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
import static io.netty.handler.logging.LogLevel.INFO;
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder for {@link Http2Codec}.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
public final class Http2CodecBuilder {
|
||||||
|
private static final Http2FrameLogger HTTP2_FRAME_LOGGER = new Http2FrameLogger(INFO, Http2Codec.class);
|
||||||
|
|
||||||
|
private final Http2StreamChannelBootstrap bootstrap;
|
||||||
|
private final boolean server;
|
||||||
|
private Http2Settings initialSettings;
|
||||||
|
private Http2FrameLogger frameLogger;
|
||||||
|
private SensitivityDetector headersSensitivityDetector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Http2Codec} builder.
|
||||||
|
*
|
||||||
|
* @param server {@code true} this is a server
|
||||||
|
* @param streamHandler the handler added to channels for remotely-created streams. It must be
|
||||||
|
* {@link ChannelHandler.Sharable}. {@code null} if the event loop from the parent channel should be used.
|
||||||
|
*/
|
||||||
|
public Http2CodecBuilder(boolean server, ChannelHandler streamHandler) {
|
||||||
|
this(server, new Http2StreamChannelBootstrap().handler(streamHandler));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Http2Codec} builder.
|
||||||
|
*
|
||||||
|
* @param server {@code true} this is a server
|
||||||
|
* @param bootstrap bootstrap used to instantiate child channels for remotely-created streams.
|
||||||
|
*/
|
||||||
|
public Http2CodecBuilder(boolean server, Http2StreamChannelBootstrap bootstrap) {
|
||||||
|
this.bootstrap = checkNotNull(bootstrap, "bootstrap");
|
||||||
|
this.server = server;
|
||||||
|
this.initialSettings = Http2Settings.defaultSettings();
|
||||||
|
this.frameLogger = HTTP2_FRAME_LOGGER;
|
||||||
|
this.headersSensitivityDetector = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the initial settings to send to peer.
|
||||||
|
*
|
||||||
|
* @param initialSettings non default initial settings to send to peer
|
||||||
|
* @return {@link Http2CodecBuilder} the builder for the {@link Http2Codec}
|
||||||
|
*/
|
||||||
|
public Http2CodecBuilder initialSettings(Http2Settings initialSettings) {
|
||||||
|
this.initialSettings = initialSettings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the initial settings to send to peer.
|
||||||
|
*/
|
||||||
|
public Http2Settings initialSettings() {
|
||||||
|
return initialSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the frame logger to log messages with.
|
||||||
|
*
|
||||||
|
* @param frameLogger handler used to log all frames
|
||||||
|
* @return {@link Http2CodecBuilder} the builder for the {@link Http2Codec}
|
||||||
|
*/
|
||||||
|
public Http2CodecBuilder frameLogger(Http2FrameLogger frameLogger) {
|
||||||
|
this.frameLogger = frameLogger;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the frame logger to log messages with.
|
||||||
|
*/
|
||||||
|
public Http2FrameLogger frameLogger() {
|
||||||
|
return frameLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the headers sensitivity detector.
|
||||||
|
*
|
||||||
|
* @param headersSensitivityDetector decides whether headers should be considered sensitive or not
|
||||||
|
* @return {@link Http2CodecBuilder} the builder for the {@link Http2Codec}
|
||||||
|
*/
|
||||||
|
public Http2CodecBuilder headersSensitivityDetector(SensitivityDetector headersSensitivityDetector) {
|
||||||
|
this.headersSensitivityDetector = headersSensitivityDetector;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the headers sensitivity detector.
|
||||||
|
*/
|
||||||
|
public SensitivityDetector headersSensitivityDetector() {
|
||||||
|
return headersSensitivityDetector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Http2FrameWriter frameWriter() {
|
||||||
|
return headersSensitivityDetector() == null ?
|
||||||
|
new DefaultHttp2FrameWriter() :
|
||||||
|
new DefaultHttp2FrameWriter(headersSensitivityDetector());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds/creates a new {@link Http2Codec} instance using this builder's current settings.
|
||||||
|
*/
|
||||||
|
public Http2Codec build() {
|
||||||
|
return new Http2Codec(server, bootstrap,
|
||||||
|
frameWriter(), frameLogger(), initialSettings());
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ package io.netty.handler.codec.http2;
|
|||||||
import io.netty.util.collection.CharObjectHashMap;
|
import io.netty.util.collection.CharObjectHashMap;
|
||||||
import io.netty.util.internal.UnstableApi;
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_CONCURRENT_STREAMS;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_CONCURRENT_STREAMS;
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_LIST_SIZE;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_LIST_SIZE;
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_TABLE_SIZE;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_TABLE_SIZE;
|
||||||
@ -262,4 +263,8 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
|||||||
return super.keyToString(key);
|
return super.keyToString(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Http2Settings defaultSettings() {
|
||||||
|
return new Http2Settings().maxHeaderListSize(DEFAULT_HEADER_LIST_SIZE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class Http2CodecTest {
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
serverConnectedChannel = ch;
|
serverConnectedChannel = ch;
|
||||||
ch.pipeline().addLast(new Http2Codec(true, serverLastInboundHandler));
|
ch.pipeline().addLast(new Http2CodecBuilder(true, serverLastInboundHandler).build());
|
||||||
serverChannelLatch.countDown();
|
serverChannelLatch.countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -81,7 +81,7 @@ public class Http2CodecTest {
|
|||||||
Bootstrap cb = new Bootstrap()
|
Bootstrap cb = new Bootstrap()
|
||||||
.channel(LocalChannel.class)
|
.channel(LocalChannel.class)
|
||||||
.group(group)
|
.group(group)
|
||||||
.handler(new Http2Codec(false, new TestChannelInitializer()));
|
.handler(new Http2CodecBuilder(false, new TestChannelInitializer()).build());
|
||||||
clientChannel = cb.connect(serverAddress).sync().channel();
|
clientChannel = cb.connect(serverAddress).sync().channel();
|
||||||
assertTrue(serverChannelLatch.await(5, SECONDS));
|
assertTrue(serverChannelLatch.await(5, SECONDS));
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import io.netty.example.http2.helloworld.server.HelloWorldHttp1Handler;
|
import io.netty.example.http2.helloworld.server.HelloWorldHttp1Handler;
|
||||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
import io.netty.handler.codec.http2.Http2Codec;
|
import io.netty.handler.codec.http2.Http2CodecBuilder;
|
||||||
import io.netty.handler.ssl.ApplicationProtocolNames;
|
import io.netty.handler.ssl.ApplicationProtocolNames;
|
||||||
import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
|
import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ public class Http2OrHttpHandler extends ApplicationProtocolNegotiationHandler {
|
|||||||
@Override
|
@Override
|
||||||
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
|
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
|
||||||
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
|
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
|
||||||
ctx.pipeline().addLast(new Http2Codec(true, new HelloWorldHttp2Handler()));
|
ctx.pipeline().addLast(new Http2CodecBuilder(true, new HelloWorldHttp2Handler()).build());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ import io.netty.handler.codec.http.HttpServerCodec;
|
|||||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodec;
|
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodec;
|
||||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodecFactory;
|
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodecFactory;
|
||||||
import io.netty.handler.codec.http2.Http2Codec;
|
import io.netty.handler.codec.http2.Http2CodecBuilder;
|
||||||
import io.netty.handler.codec.http2.Http2CodecUtil;
|
import io.netty.handler.codec.http2.Http2CodecUtil;
|
||||||
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
|
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
@ -46,7 +46,7 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
|||||||
@Override
|
@Override
|
||||||
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
|
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
|
||||||
if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {
|
if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {
|
||||||
return new Http2ServerUpgradeCodec(new Http2Codec(true, new HelloWorldHttp2Handler()));
|
return new Http2ServerUpgradeCodec(new Http2CodecBuilder(true, new HelloWorldHttp2Handler()).build());
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user