io.hyperfoil.http.connection.CustomHttp2ConnectionHandler Maven / Gradle / Ivy
package io.hyperfoil.http.connection;
import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception;
import java.io.IOException;
import java.util.function.BiConsumer;
import io.hyperfoil.api.connection.Connection;
import io.hyperfoil.api.session.SessionStopException;
import io.hyperfoil.http.api.HttpClientPool;
import io.hyperfoil.http.api.HttpConnection;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpClientUpgradeHandler;
import io.netty.handler.codec.http2.Http2ConnectionDecoder;
import io.netty.handler.codec.http2.Http2ConnectionEncoder;
import io.netty.handler.codec.http2.Http2Settings;
import io.netty.util.internal.StringUtil;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
class CustomHttp2ConnectionHandler extends io.netty.handler.codec.http2.Http2ConnectionHandler {
private static final Logger log = LoggerFactory.getLogger(CustomHttp2ConnectionHandler.class);
private final BiConsumer activationHandler;
private final HttpClientPool clientPool;
private final boolean isUpgrade;
private Http2Connection connection;
CustomHttp2ConnectionHandler(
HttpClientPool clientPool,
BiConsumer activationHandler,
Http2ConnectionDecoder decoder,
Http2ConnectionEncoder encoder,
Http2Settings initialSettings, boolean isUpgrade) {
super(decoder, encoder, initialSettings);
this.clientPool = clientPool;
this.activationHandler = activationHandler;
this.isUpgrade = isUpgrade;
}
private static String generateName(Class extends ChannelHandler> handlerType) {
return StringUtil.simpleClassName(handlerType) + "#0";
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
super.handlerAdded(ctx);
if (ctx.channel().isActive() && !isUpgrade) {
checkActivated(ctx);
}
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt == HttpClientUpgradeHandler.UpgradeEvent.UPGRADE_SUCCESSFUL) {
checkActivated(ctx);
} else if (evt == HttpClientUpgradeHandler.UpgradeEvent.UPGRADE_REJECTED) {
activationHandler.accept(null, new IOException("H2C upgrade was rejected by server."));
}
super.userEventTriggered(ctx, evt);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
checkActivated(ctx);
}
private void checkActivated(ChannelHandlerContext ctx) {
if (connection == null) {
connection = new Http2Connection(ctx, connection(), encoder(), decoder(), clientPool);
// Use a very large stream window size
connection.incrementConnectionWindowSize(1073676288 - 65535);
if (clientPool.config().rawBytesHandlers()) {
String customeHandlerName = generateName(CustomHttp2ConnectionHandler.class);
ctx.pipeline().addBefore(customeHandlerName, null, new Http2RawResponseHandler(connection));
ctx.pipeline().addBefore(customeHandlerName, null, new RawRequestHandler(connection));
}
activationHandler.accept(connection, null);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (cause != SessionStopException.INSTANCE) {
log.warn("Exception in {}", cause, this);
}
try {
if (getEmbeddedHttp2Exception(cause) != null) {
onError(ctx, false, cause);
} else {
if (connection != null) {
connection.cancelRequests(cause);
}
ctx.close();
}
} catch (Throwable t) {
log.error("Handling exception resulted in another exception", t);
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
connection.cancelRequests(Connection.CLOSED_EXCEPTION);
}
}