Http2ConnectionHandler Builder instead of constructors
Motivation: Using the builder pattern for Http2ConnectionHandler (and subclasses) would be advantageous for the following reasons: 1. Provides the consistent construction afforded by the builder pattern for 'optional' arguments. Users can specify these options 1 time in the builder and then re-use the builder after this. 2. Enforces that the Http2ConnectionHandler's internals (decoder Http2FrameListener) are initialized after construction. Modifications: - Add an extensible builder which can be used to build Http2ConnectionHandler objects - Update classes which inherit from Http2ConnectionHandler Result: It is easier to specify options and construct Http2ConnectionHandler objects.
This commit is contained in:
parent
179cd9a4a1
commit
284e3702d8
@ -51,6 +51,11 @@ public class DecoratingHttp2ConnectionDecoder implements Http2ConnectionDecoder
|
|||||||
delegate.frameListener(listener);
|
delegate.frameListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Http2FrameListener frameListener() {
|
||||||
|
return delegate.frameListener();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception {
|
public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception {
|
||||||
delegate.decodeFrame(ctx, in, out);
|
delegate.decodeFrame(ctx, in, out);
|
||||||
|
@ -87,6 +87,11 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
|
|||||||
this.listener = checkNotNull(listener, "listener");
|
this.listener = checkNotNull(listener, "listener");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Http2FrameListener frameListener() {
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean prefaceReceived() {
|
public boolean prefaceReceived() {
|
||||||
return FrameReadListener.class == internalFrameListener.getClass();
|
return FrameReadListener.class == internalFrameListener.getClass();
|
||||||
|
@ -50,6 +50,11 @@ public interface Http2ConnectionDecoder extends Closeable {
|
|||||||
*/
|
*/
|
||||||
void frameListener(Http2FrameListener listener);
|
void frameListener(Http2FrameListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link Http2FrameListener} which will be notified when frames are decoded.
|
||||||
|
*/
|
||||||
|
Http2FrameListener frameListener();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the {@link Http2ConnectionHandler} to decode the next frame from the input buffer.
|
* Called by the {@link Http2ConnectionHandler} to decode the next frame from the input buffer.
|
||||||
*/
|
*/
|
||||||
|
@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import static io.netty.buffer.ByteBufUtil.hexDump;
|
import static io.netty.buffer.ByteBufUtil.hexDump;
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.HTTP_UPGRADE_STREAM_ID;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.HTTP_UPGRADE_STREAM_ID;
|
||||||
|
import static io.netty.handler.codec.http2.Http2CodecUtil.SMALLEST_MAX_CONCURRENT_STREAMS;
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf;
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception;
|
||||||
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
|
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
|
||||||
@ -69,61 +70,191 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
|||||||
private final Http2Settings initialSettings;
|
private final Http2Settings initialSettings;
|
||||||
private ChannelFutureListener closeListener;
|
private ChannelFutureListener closeListener;
|
||||||
private BaseDecoder byteDecoder;
|
private BaseDecoder byteDecoder;
|
||||||
private long gracefulShutdownTimeoutMillis = DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
|
private long gracefulShutdownTimeoutMillis;
|
||||||
|
|
||||||
public Http2ConnectionHandler(boolean server) {
|
/**
|
||||||
this(server, true);
|
* Builder which builds {@link Http2ConnectionHandler} objects.
|
||||||
|
*/
|
||||||
|
public static final class Builder extends BuilderBase<Http2ConnectionHandler, Builder> {
|
||||||
|
@Override
|
||||||
|
public Http2ConnectionHandler build0(Http2ConnectionDecoder decoder,
|
||||||
|
Http2ConnectionEncoder encoder) {
|
||||||
|
return new Http2ConnectionHandler(decoder, encoder, initialSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Http2ConnectionHandler(boolean server, boolean validateHeaders) {
|
|
||||||
this(new DefaultHttp2Connection(server), validateHeaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection) {
|
|
||||||
this(connection, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection, boolean validateHeaders) {
|
|
||||||
this(connection, new DefaultHttp2FrameReader(validateHeaders), new DefaultHttp2FrameWriter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
|
||||||
Http2FrameWriter frameWriter) {
|
|
||||||
initialSettings = null;
|
|
||||||
encoder = new DefaultHttp2ConnectionEncoder(connection, frameWriter);
|
|
||||||
decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, frameReader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for pre-configured encoder and decoder. Just sets the {@code this} as the
|
* Base class for a {@code builder} of any subclass of {@link Http2ConnectionHandler}.
|
||||||
* {@link Http2LifecycleManager} and builds them.
|
* @param <T> The type of handler created by this builder.
|
||||||
|
* @param <B> The concrete type for this builder.
|
||||||
*/
|
*/
|
||||||
public Http2ConnectionHandler(Http2ConnectionDecoder decoder,
|
public abstract static class BuilderBase<T extends Http2ConnectionHandler, B extends BuilderBase<T, B>> {
|
||||||
Http2ConnectionEncoder encoder) {
|
private Http2Settings initialSettings = new Http2Settings();
|
||||||
this.initialSettings = null;
|
private Http2FrameListener frameListener;
|
||||||
this.decoder = checkNotNull(decoder, "decoder");
|
private Http2FrameLogger frameLogger;
|
||||||
this.encoder = checkNotNull(encoder, "encoder");
|
private boolean validateHeaders = true;
|
||||||
if (encoder.connection() != decoder.connection()) {
|
private boolean server = true;
|
||||||
throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object");
|
private int encoderMaxConcurrentStreams = SMALLEST_MAX_CONCURRENT_STREAMS;
|
||||||
|
private long gracefulShutdownTimeoutMillis = DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the listener for inbound frames.
|
||||||
|
* This listener will only be set if the decoder's listener is {@code null}.
|
||||||
|
*/
|
||||||
|
public B frameListener(Http2FrameListener listener) {
|
||||||
|
frameListener = listener;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if HTTP headers should be validated according to
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
|
||||||
|
*/
|
||||||
|
public B validateHeaders(boolean validate) {
|
||||||
|
validateHeaders = validate;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if HTTP headers should be validated according to
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
|
||||||
|
*/
|
||||||
|
public final boolean isValidateHeaders() {
|
||||||
|
return validateHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings to use for the initial connection settings exchange.
|
||||||
|
*/
|
||||||
|
public B initialSettings(Http2Settings settings) {
|
||||||
|
initialSettings = settings;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the settings to use for the initial connection settings exchange.
|
||||||
|
*/
|
||||||
|
public final Http2Settings initialSettings() {
|
||||||
|
return initialSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
|
||||||
|
* or client mode ({@code false}).
|
||||||
|
*/
|
||||||
|
public B server(boolean isServer) {
|
||||||
|
server = isServer;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the logger that is used for the encoder and decoder.
|
||||||
|
*/
|
||||||
|
public B frameLogger(Http2FrameLogger logger) {
|
||||||
|
frameLogger = logger;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis) {
|
||||||
|
this.gracefulShutdownTimeoutMillis = gracefulShutdownTimeoutMillis;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the encoder should queue frames to honor the value set by
|
||||||
|
* {@link #encoderMaxConcurrentStreams(int)}.
|
||||||
|
*/
|
||||||
|
public B encoderEnforceMaxConcurrentStreams(boolean encoderEnforceMaxConcurrentStreams) {
|
||||||
|
encoderMaxConcurrentStreams = -1;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean encoderEnforceMaxConcurrentStreams() {
|
||||||
|
return encoderMaxConcurrentStreams >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many initial streams are allowed to exists concurrently. Frames will be queued if they would result in
|
||||||
|
* creating a stream which would cause the number of existing streams to exceed this number.
|
||||||
|
* @see #encoderEnforceMaxConcurrentStreams(boolean)
|
||||||
|
*/
|
||||||
|
public B encoderMaxConcurrentStreams(int encoderMaxConcurrentStreams) {
|
||||||
|
// This bounds are enforced here because the builder makes assumptions about its valid range to determine
|
||||||
|
// if it should be used.
|
||||||
|
if (encoderMaxConcurrentStreams < 0) {
|
||||||
|
throw new IllegalArgumentException("encoderMaxConcurrentStreams: " + encoderMaxConcurrentStreams +
|
||||||
|
" (expected >= 0)");
|
||||||
|
}
|
||||||
|
this.encoderMaxConcurrentStreams = encoderMaxConcurrentStreams;
|
||||||
|
return thisB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link Http2Connection} and build a new instance.
|
||||||
|
*/
|
||||||
|
public final T build() {
|
||||||
|
return build(new DefaultHttp2Connection(server));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a new instance with an existing {@link Http2Connection}.
|
||||||
|
* <p>
|
||||||
|
* Methods that will be ignored due to objects already being created:
|
||||||
|
* <ul><li>{@link #server(boolean)}</li></ul>
|
||||||
|
*/
|
||||||
|
public final T build(Http2Connection connection) {
|
||||||
|
Http2FrameReader reader = new DefaultHttp2FrameReader(validateHeaders);
|
||||||
|
Http2FrameWriter writer = new DefaultHttp2FrameWriter();
|
||||||
|
if (frameLogger != null) {
|
||||||
|
reader = new Http2InboundFrameLogger(reader, frameLogger);
|
||||||
|
writer = new Http2OutboundFrameLogger(writer, frameLogger);
|
||||||
|
}
|
||||||
|
Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, writer);
|
||||||
|
if (encoderEnforceMaxConcurrentStreams()) {
|
||||||
|
encoder = new StreamBufferingEncoder(encoder, encoderMaxConcurrentStreams);
|
||||||
|
}
|
||||||
|
Http2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, reader);
|
||||||
|
return build(decoder, encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a new instance with an existing {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder}.
|
||||||
|
* <p>
|
||||||
|
* Methods that will be ignored due to objects already being created:
|
||||||
|
* <ul><li>{@link #server(boolean)}</li><li>{@link #validateHttp2Headers(boolean)}</li><li>
|
||||||
|
* {@link #frameLogger(Http2FrameLogger)}</li><li>{@link #encoderEnforceMaxConcurrentStreams(boolean)}</li><li>
|
||||||
|
* {@link #encoderMaxConcurrentStreams(int)}</li></ul>
|
||||||
|
*/
|
||||||
|
public final T build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
|
||||||
|
// Call the abstract build method
|
||||||
|
T handler = build0(decoder, encoder);
|
||||||
|
|
||||||
|
// Setup post build options
|
||||||
|
handler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis);
|
||||||
|
if (handler.decoder().frameListener() == null) {
|
||||||
|
handler.decoder().frameListener(frameListener);
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sub classes should override this to instantiate the concrete type.
|
||||||
|
* <p>
|
||||||
|
* The return of this method will be subject to the following:
|
||||||
|
* <ul><li>{@link #frameListener(Http2FrameListener)} will be set if not already set in the decoder</li><li>
|
||||||
|
* {@link #gracefulShutdownTimeoutMillis(long)} will be set</li></ul>
|
||||||
|
*/
|
||||||
|
protected abstract T build0(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected B thisB() {
|
||||||
|
return (B) this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection, Http2Settings initialSettings) {
|
protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
|
||||||
this(connection, new DefaultHttp2FrameReader(), new DefaultHttp2FrameWriter(),
|
|
||||||
initialSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
|
||||||
Http2FrameWriter frameWriter, Http2Settings initialSettings) {
|
|
||||||
this.initialSettings = initialSettings;
|
|
||||||
encoder = new DefaultHttp2ConnectionEncoder(connection, frameWriter);
|
|
||||||
decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, frameReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Http2ConnectionHandler(Http2ConnectionDecoder decoder,
|
|
||||||
Http2ConnectionEncoder encoder,
|
|
||||||
Http2Settings initialSettings) {
|
Http2Settings initialSettings) {
|
||||||
this.initialSettings = initialSettings;
|
this.initialSettings = checkNotNull(initialSettings, "initialSettings");
|
||||||
this.decoder = checkNotNull(decoder, "decoder");
|
this.decoder = checkNotNull(decoder, "decoder");
|
||||||
this.encoder = checkNotNull(encoder, "encoder");
|
this.encoder = checkNotNull(encoder, "encoder");
|
||||||
if (encoder.connection() != decoder.connection()) {
|
if (encoder.connection() != decoder.connection()) {
|
||||||
@ -378,7 +509,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Both client and server must send their initial settings.
|
// Both client and server must send their initial settings.
|
||||||
encoder.writeSettings(ctx, initialSettings(), ctx.newPromise()).addListener(
|
encoder.writeSettings(ctx, initialSettings, ctx.newPromise()).addListener(
|
||||||
ChannelFutureListener.CLOSE_ON_FAILURE);
|
ChannelFutureListener.CLOSE_ON_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -741,13 +872,6 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the initial settings to be sent to the remote endpoint.
|
|
||||||
*/
|
|
||||||
private Http2Settings initialSettings() {
|
|
||||||
return initialSettings != null ? initialSettings : decoder.localSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the remote endpoint with with a {@code GO_AWAY} frame. Does <strong>not</strong> flush
|
* Close the remote endpoint with with a {@code GO_AWAY} frame. Does <strong>not</strong> flush
|
||||||
* immediately, this is the responsibility of the caller.
|
* immediately, this is the responsibility of the caller.
|
||||||
|
@ -36,43 +36,20 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
|
|||||||
private final boolean validateHeaders;
|
private final boolean validateHeaders;
|
||||||
private int currentStreamId;
|
private int currentStreamId;
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(boolean server) {
|
/**
|
||||||
this(server, true);
|
* Builder which builds {@link HttpToHttp2ConnectionHandler} objects.
|
||||||
}
|
*/
|
||||||
|
public static final class Builder extends BuilderBase<HttpToHttp2ConnectionHandler, Builder> {
|
||||||
public HttpToHttp2ConnectionHandler(boolean server, boolean validateHeaders) {
|
@Override
|
||||||
super(server);
|
public HttpToHttp2ConnectionHandler build0(Http2ConnectionDecoder decoder,
|
||||||
this.validateHeaders = validateHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2Connection connection) {
|
|
||||||
this(connection, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2Connection connection, boolean validateHeaders) {
|
|
||||||
super(connection);
|
|
||||||
this.validateHeaders = validateHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
|
||||||
Http2FrameWriter frameWriter) {
|
|
||||||
this(connection, frameReader, frameWriter, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
|
|
||||||
Http2FrameWriter frameWriter, boolean validateHeaders) {
|
|
||||||
super(connection, frameReader, frameWriter);
|
|
||||||
this.validateHeaders = validateHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder,
|
|
||||||
Http2ConnectionEncoder encoder) {
|
Http2ConnectionEncoder encoder) {
|
||||||
this(decoder, encoder, true);
|
return new HttpToHttp2ConnectionHandler(decoder, encoder, initialSettings(), isValidateHeaders());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder,
|
protected HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
|
||||||
Http2ConnectionEncoder encoder, boolean validateHeaders) {
|
Http2Settings initialSettings, boolean validateHeaders) {
|
||||||
super(decoder, encoder);
|
super(decoder, encoder, initialSettings);
|
||||||
this.validateHeaders = validateHeaders;
|
this.validateHeaders = validateHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,8 +300,9 @@ public class DataCompressionHttp2Test {
|
|||||||
new DefaultHttp2ConnectionEncoder(serverConnection, new DefaultHttp2FrameWriter()));
|
new DefaultHttp2ConnectionEncoder(serverConnection, new DefaultHttp2FrameWriter()));
|
||||||
Http2ConnectionDecoder decoder =
|
Http2ConnectionDecoder decoder =
|
||||||
new DefaultHttp2ConnectionDecoder(serverConnection, encoder, new DefaultHttp2FrameReader());
|
new DefaultHttp2ConnectionDecoder(serverConnection, encoder, new DefaultHttp2FrameReader());
|
||||||
decoder.frameListener(new DelegatingDecompressorFrameListener(serverConnection, serverListener));
|
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler.Builder()
|
||||||
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, encoder);
|
.frameListener(new DelegatingDecompressorFrameListener(serverConnection, serverListener))
|
||||||
|
.build(decoder, encoder);
|
||||||
p.addLast(connectionHandler);
|
p.addLast(connectionHandler);
|
||||||
serverChannelLatch.countDown();
|
serverChannelLatch.countDown();
|
||||||
}
|
}
|
||||||
@ -318,11 +319,11 @@ public class DataCompressionHttp2Test {
|
|||||||
Http2ConnectionDecoder decoder =
|
Http2ConnectionDecoder decoder =
|
||||||
new DefaultHttp2ConnectionDecoder(clientConnection, clientEncoder,
|
new DefaultHttp2ConnectionDecoder(clientConnection, clientEncoder,
|
||||||
new DefaultHttp2FrameReader());
|
new DefaultHttp2FrameReader());
|
||||||
decoder.frameListener(new DelegatingDecompressorFrameListener(clientConnection, clientListener));
|
clientHandler = new Http2ConnectionHandler.Builder()
|
||||||
clientHandler = new Http2ConnectionHandler(decoder, clientEncoder);
|
.frameListener(new DelegatingDecompressorFrameListener(clientConnection, clientListener))
|
||||||
|
|
||||||
// By default tests don't wait for server to gracefully shutdown streams
|
// By default tests don't wait for server to gracefully shutdown streams
|
||||||
clientHandler.gracefulShutdownTimeoutMillis(0);
|
.gracefulShutdownTimeoutMillis(0)
|
||||||
|
.build(decoder, clientEncoder);
|
||||||
p.addLast(clientHandler);
|
p.addLast(clientHandler);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -180,7 +180,7 @@ public class Http2ConnectionHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Http2ConnectionHandler newHandler() throws Exception {
|
private Http2ConnectionHandler newHandler() throws Exception {
|
||||||
Http2ConnectionHandler handler = new Http2ConnectionHandler(decoder, encoder);
|
Http2ConnectionHandler handler = new Http2ConnectionHandler.Builder().build(decoder, encoder);
|
||||||
handler.handlerAdded(ctx);
|
handler.handlerAdded(ctx);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
@ -482,9 +482,11 @@ public class Http2ConnectionRoundtripTest {
|
|||||||
serverFrameCountDown =
|
serverFrameCountDown =
|
||||||
new FrameCountDown(serverListener, serverSettingsAckLatch,
|
new FrameCountDown(serverListener, serverSettingsAckLatch,
|
||||||
requestLatch, dataLatch, trailersLatch, goAwayLatch);
|
requestLatch, dataLatch, trailersLatch, goAwayLatch);
|
||||||
Http2ConnectionHandler handler = new Http2ConnectionHandler(true, false);
|
p.addLast(new Http2ConnectionHandler.Builder()
|
||||||
handler.decoder().frameListener(serverFrameCountDown);
|
.server(true)
|
||||||
p.addLast(handler);
|
.frameListener(serverFrameCountDown)
|
||||||
|
.validateHeaders(false)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -494,9 +496,11 @@ public class Http2ConnectionRoundtripTest {
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
Http2ConnectionHandler handler = new Http2ConnectionHandler(false, false);
|
p.addLast(new Http2ConnectionHandler.Builder()
|
||||||
handler.decoder().frameListener(clientListener);
|
.server(false)
|
||||||
p.addLast(handler);
|
.frameListener(clientListener)
|
||||||
|
.validateHeaders(false)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -487,9 +487,10 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
serverFrameCountDown =
|
serverFrameCountDown =
|
||||||
new FrameCountDown(serverListener, serverSettingsAckLatch, requestLatch, null, trailersLatch);
|
new FrameCountDown(serverListener, serverSettingsAckLatch, requestLatch, null, trailersLatch);
|
||||||
HttpToHttp2ConnectionHandler handler = new HttpToHttp2ConnectionHandler(true);
|
p.addLast(new HttpToHttp2ConnectionHandler.Builder()
|
||||||
handler.decoder().frameListener(serverFrameCountDown);
|
.server(true)
|
||||||
p.addLast(handler);
|
.frameListener(serverFrameCountDown)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -499,9 +500,11 @@ public class HttpToHttp2ConnectionHandlerTest {
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
HttpToHttp2ConnectionHandler handler = new HttpToHttp2ConnectionHandler(false);
|
HttpToHttp2ConnectionHandler handler = new HttpToHttp2ConnectionHandler.Builder()
|
||||||
handler.decoder().frameListener(clientListener);
|
.server(false)
|
||||||
handler.gracefulShutdownTimeoutMillis(0);
|
.frameListener(clientListener)
|
||||||
|
.gracefulShutdownTimeoutMillis(0)
|
||||||
|
.build();
|
||||||
p.addLast(handler);
|
p.addLast(handler);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -111,9 +111,9 @@ public class StreamBufferingEncoderTest {
|
|||||||
encoder = new StreamBufferingEncoder(defaultEncoder);
|
encoder = new StreamBufferingEncoder(defaultEncoder);
|
||||||
DefaultHttp2ConnectionDecoder decoder =
|
DefaultHttp2ConnectionDecoder decoder =
|
||||||
new DefaultHttp2ConnectionDecoder(connection, encoder, mock(Http2FrameReader.class));
|
new DefaultHttp2ConnectionDecoder(connection, encoder, mock(Http2FrameReader.class));
|
||||||
decoder.frameListener(mock(Http2FrameListener.class));
|
Http2ConnectionHandler handler = new Http2ConnectionHandler.Builder()
|
||||||
|
.frameListener(mock(Http2FrameListener.class)).build(decoder, encoder);
|
||||||
|
|
||||||
Http2ConnectionHandler handler = new Http2ConnectionHandler(decoder, encoder);
|
|
||||||
// Set LifeCycleManager on encoder and decoder
|
// Set LifeCycleManager on encoder and decoder
|
||||||
when(ctx.channel()).thenReturn(channel);
|
when(ctx.channel()).thenReturn(channel);
|
||||||
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
||||||
|
@ -25,16 +25,10 @@ import io.netty.handler.codec.http.HttpClientUpgradeHandler;
|
|||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
import io.netty.handler.codec.http.HttpVersion;
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
|
||||||
import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
|
import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
|
||||||
import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
|
import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
|
||||||
import io.netty.handler.codec.http2.Http2Connection;
|
import io.netty.handler.codec.http2.Http2Connection;
|
||||||
import io.netty.handler.codec.http2.Http2FrameLogger;
|
import io.netty.handler.codec.http2.Http2FrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2FrameReader;
|
|
||||||
import io.netty.handler.codec.http2.Http2FrameWriter;
|
|
||||||
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
|
||||||
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
|
||||||
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandler;
|
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandler;
|
||||||
import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapter;
|
import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapter;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
@ -61,13 +55,14 @@ public class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
|
|||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel ch) throws Exception {
|
public void initChannel(SocketChannel ch) throws Exception {
|
||||||
final Http2Connection connection = new DefaultHttp2Connection(false);
|
final Http2Connection connection = new DefaultHttp2Connection(false);
|
||||||
final Http2FrameWriter frameWriter = frameWriter();
|
connectionHandler = new HttpToHttp2ConnectionHandler.Builder()
|
||||||
connectionHandler = new HttpToHttp2ConnectionHandler(connection, frameReader(), frameWriter);
|
.frameListener(new DelegatingDecompressorFrameListener(connection,
|
||||||
connectionHandler.decoder().frameListener(new DelegatingDecompressorFrameListener(connection,
|
|
||||||
new InboundHttp2ToHttpAdapter.Builder(connection)
|
new InboundHttp2ToHttpAdapter.Builder(connection)
|
||||||
.maxContentLength(maxContentLength)
|
.maxContentLength(maxContentLength)
|
||||||
.propagateSettings(true)
|
.propagateSettings(true)
|
||||||
.build()));
|
.build()))
|
||||||
|
.frameLogger(logger)
|
||||||
|
.build(connection);
|
||||||
responseHandler = new HttpResponseHandler();
|
responseHandler = new HttpResponseHandler();
|
||||||
settingsHandler = new Http2SettingsHandler(ch.newPromise());
|
settingsHandler = new Http2SettingsHandler(ch.newPromise());
|
||||||
if (sslCtx != null) {
|
if (sslCtx != null) {
|
||||||
@ -142,12 +137,4 @@ public class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
|
|||||||
ctx.fireUserEventTriggered(evt);
|
ctx.fireUserEventTriggered(evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Http2FrameReader frameReader() {
|
|
||||||
return new Http2InboundFrameLogger(new DefaultHttp2FrameReader(), logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Http2FrameWriter frameWriter() {
|
|
||||||
return new Http2OutboundFrameLogger(new DefaultHttp2FrameWriter(), logger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,21 +19,15 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2Connection;
|
import io.netty.handler.codec.http2.Http2ConnectionDecoder;
|
||||||
|
import io.netty.handler.codec.http2.Http2ConnectionEncoder;
|
||||||
import io.netty.handler.codec.http2.Http2ConnectionHandler;
|
import io.netty.handler.codec.http2.Http2ConnectionHandler;
|
||||||
import io.netty.handler.codec.http2.Http2Exception;
|
import io.netty.handler.codec.http2.Http2Exception;
|
||||||
import io.netty.handler.codec.http2.Http2Flags;
|
import io.netty.handler.codec.http2.Http2Flags;
|
||||||
import io.netty.handler.codec.http2.Http2FrameListener;
|
import io.netty.handler.codec.http2.Http2FrameListener;
|
||||||
import io.netty.handler.codec.http2.Http2FrameLogger;
|
import io.netty.handler.codec.http2.Http2FrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2FrameReader;
|
|
||||||
import io.netty.handler.codec.http2.Http2FrameWriter;
|
|
||||||
import io.netty.handler.codec.http2.Http2Headers;
|
import io.netty.handler.codec.http2.Http2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
|
||||||
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
|
||||||
import io.netty.handler.codec.http2.Http2Settings;
|
import io.netty.handler.codec.http2.Http2Settings;
|
||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
@ -47,21 +41,27 @@ import static io.netty.handler.logging.LogLevel.INFO;
|
|||||||
/**
|
/**
|
||||||
* A simple handler that responds with the message "Hello World!".
|
* A simple handler that responds with the message "Hello World!".
|
||||||
*/
|
*/
|
||||||
public class HelloWorldHttp2Handler extends Http2ConnectionHandler implements Http2FrameListener {
|
public final class HelloWorldHttp2Handler extends Http2ConnectionHandler implements Http2FrameListener {
|
||||||
|
|
||||||
private static final Http2FrameLogger logger = new Http2FrameLogger(INFO, HelloWorldHttp2Handler.class);
|
private static final Http2FrameLogger logger = new Http2FrameLogger(INFO, HelloWorldHttp2Handler.class);
|
||||||
static final ByteBuf RESPONSE_BYTES = unreleasableBuffer(copiedBuffer("Hello World", CharsetUtil.UTF_8));
|
static final ByteBuf RESPONSE_BYTES = unreleasableBuffer(copiedBuffer("Hello World", CharsetUtil.UTF_8));
|
||||||
|
|
||||||
public HelloWorldHttp2Handler() {
|
public static final class Builder extends BuilderBase<HelloWorldHttp2Handler, Builder> {
|
||||||
this(new DefaultHttp2Connection(true), new Http2InboundFrameLogger(
|
public Builder() {
|
||||||
new DefaultHttp2FrameReader(), logger), new Http2OutboundFrameLogger(
|
frameLogger(logger);
|
||||||
new DefaultHttp2FrameWriter(), logger));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HelloWorldHttp2Handler(Http2Connection connection, Http2FrameReader frameReader,
|
@Override
|
||||||
Http2FrameWriter frameWriter) {
|
public HelloWorldHttp2Handler build0(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
|
||||||
super(connection, frameReader, frameWriter);
|
HelloWorldHttp2Handler handler = new HelloWorldHttp2Handler(decoder, encoder, initialSettings());
|
||||||
decoder().frameListener(this);
|
frameListener(handler);
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HelloWorldHttp2Handler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
|
||||||
|
Http2Settings initialSettings) {
|
||||||
|
super(decoder, encoder, initialSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,7 +35,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 HelloWorldHttp2Handler());
|
ctx.pipeline().addLast(new HelloWorldHttp2Handler.Builder().build());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,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 HelloWorldHttp2Handler());
|
return new Http2ServerUpgradeCodec(new HelloWorldHttp2Handler.Builder().build());
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -56,19 +56,13 @@ public class Http2OrHttpHandler extends ApplicationProtocolNegotiationHandler {
|
|||||||
|
|
||||||
private static void configureHttp2(ChannelHandlerContext ctx) {
|
private static void configureHttp2(ChannelHandlerContext ctx) {
|
||||||
DefaultHttp2Connection connection = new DefaultHttp2Connection(true);
|
DefaultHttp2Connection connection = new DefaultHttp2Connection(true);
|
||||||
DefaultHttp2FrameWriter writer = new DefaultHttp2FrameWriter();
|
|
||||||
DefaultHttp2FrameReader reader = new DefaultHttp2FrameReader();
|
|
||||||
InboundHttp2ToHttpAdapter listener = new InboundHttp2ToHttpAdapter.Builder(connection)
|
InboundHttp2ToHttpAdapter listener = new InboundHttp2ToHttpAdapter.Builder(connection)
|
||||||
.propagateSettings(true).validateHttpHeaders(false).maxContentLength(MAX_CONTENT_LENGTH).build();
|
.propagateSettings(true).validateHttpHeaders(false).maxContentLength(MAX_CONTENT_LENGTH).build();
|
||||||
|
|
||||||
HttpToHttp2ConnectionHandler handler = new HttpToHttp2ConnectionHandler(
|
ctx.pipeline().addLast(new HttpToHttp2ConnectionHandler.Builder()
|
||||||
connection,
|
.frameListener(listener)
|
||||||
// Loggers can be activated for debugging purposes
|
// .frameLogger(TilesHttp2ToHttpHandler.logger)
|
||||||
// new Http2InboundFrameLogger(reader, TilesHttp2ToHttpHandler.logger),
|
.build(connection));
|
||||||
// new Http2OutboundFrameLogger(writer, TilesHttp2ToHttpHandler.logger)
|
|
||||||
reader, writer);
|
|
||||||
handler.decoder().frameListener(listener);
|
|
||||||
ctx.pipeline().addLast(handler);
|
|
||||||
ctx.pipeline().addLast(new Http2RequestHandler());
|
ctx.pipeline().addLast(new Http2RequestHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,8 +263,9 @@ public class Http2FrameWriterBenchmark extends AbstractSharedExecutorMicrobenchm
|
|||||||
Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, environment.writer());
|
Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, environment.writer());
|
||||||
Http2ConnectionDecoder decoder =
|
Http2ConnectionDecoder decoder =
|
||||||
new DefaultHttp2ConnectionDecoder(connection, encoder, new DefaultHttp2FrameReader());
|
new DefaultHttp2ConnectionDecoder(connection, encoder, new DefaultHttp2FrameReader());
|
||||||
decoder.frameListener(new Http2FrameAdapter());
|
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler.Builder()
|
||||||
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, encoder);
|
.encoderEnforceMaxConcurrentStreams(false)
|
||||||
|
.frameListener(new Http2FrameAdapter()).build(decoder, encoder);
|
||||||
p.addLast(connectionHandler);
|
p.addLast(connectionHandler);
|
||||||
environment.context(p.lastContext());
|
environment.context(p.lastContext());
|
||||||
// Must wait for context to be set.
|
// Must wait for context to be set.
|
||||||
@ -292,8 +293,9 @@ public class Http2FrameWriterBenchmark extends AbstractSharedExecutorMicrobenchm
|
|||||||
Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, env.writer());
|
Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, env.writer());
|
||||||
Http2ConnectionDecoder decoder =
|
Http2ConnectionDecoder decoder =
|
||||||
new DefaultHttp2ConnectionDecoder(connection, encoder, new DefaultHttp2FrameReader());
|
new DefaultHttp2ConnectionDecoder(connection, encoder, new DefaultHttp2FrameReader());
|
||||||
decoder.frameListener(new Http2FrameAdapter());
|
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler.Builder()
|
||||||
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, encoder);
|
.encoderEnforceMaxConcurrentStreams(false)
|
||||||
|
.frameListener(new Http2FrameAdapter()).build(decoder, encoder);
|
||||||
env.context(new EmbeddedChannelWriteReleaseHandlerContext(alloc, connectionHandler) {
|
env.context(new EmbeddedChannelWriteReleaseHandlerContext(alloc, connectionHandler) {
|
||||||
@Override
|
@Override
|
||||||
protected void handleException(Throwable t) {
|
protected void handleException(Throwable t) {
|
||||||
|
Loading…
Reference in New Issue
Block a user