use of io.netty.handler.codec.http2.Http2Exception in project netty by netty.
the class InboundHttp2ToHttpAdapterTest method clientRequestSingleHeaderCookieSplitIntoMultipleEntries.
@Test
public void clientRequestSingleHeaderCookieSplitIntoMultipleEntries() throws Exception {
boostrapEnv(1, 1, 1);
final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/path/resource2", true);
try {
HttpHeaders httpHeaders = request.headers();
httpHeaders.set(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), "https");
httpHeaders.set(HttpHeaderNames.HOST, "example.org");
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")).add(HttpHeaderNames.COOKIE, "a=b").add(HttpHeaderNames.COOKIE, "c=d").add(HttpHeaderNames.COOKIE, "e=f");
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
clientChannel.flush();
}
});
awaitRequests();
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
verify(serverListener).messageReceived(requestCaptor.capture());
capturedRequests = requestCaptor.getAllValues();
assertEquals(request, capturedRequests.get(0));
} finally {
request.release();
}
}
use of io.netty.handler.codec.http2.Http2Exception in project zuul by Netflix.
the class Http2ConnectionCloseHandler method gracefullyWithDelay.
/**
* WARNING: Found the OkHttp client gets confused by this behaviour (it ends up putting itself in a bad shutdown state
* after receiving the first goaway frame, and then dropping any inflight responses but also timing out waiting for them).
*
* And worried that other http/2 stacks may be similar, so for now we should NOT use this.
*
* This is unfortunate, as FTL wanted this, and it is correct according to the spec.
*
* See this code in okhttp where it drops response header frame if state is already shutdown:
* https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/http2/Http2Connection.java#L609
*/
private void gracefullyWithDelay(EventExecutor executor, Channel parent, ChannelPromise promise) {
// See javadoc for explanation of why this may be disabled.
boolean allowGracefulDelayed = ConnectionCloseChannelAttributes.allowGracefulDelayed(parent);
if (!allowGracefulDelayed) {
immediate(parent, promise);
return;
}
if (!parent.isActive()) {
promise.setSuccess();
return;
}
// First send a 'graceful shutdown' GOAWAY frame.
/*
"A server that is attempting to gracefully shut down a connection SHOULD send an initial GOAWAY frame with
the last stream identifier set to 231-1 and a NO_ERROR code. This signals to the client that a shutdown is
imminent and that initiating further requests is prohibited."
-- https://http2.github.io/http2-spec/#GOAWAY
*/
DefaultHttp2GoAwayFrame goaway = new DefaultHttp2GoAwayFrame(Http2Error.NO_ERROR);
goaway.setExtraStreamIds(Integer.MAX_VALUE);
parent.writeAndFlush(goaway);
LOG.debug("gracefullyWithDelay: flushed initial go_away frame. channel=" + parent.id().asShortText());
// In N secs time, throw an error that causes the http2 codec to send another GOAWAY frame
// (this time with accurate lastStreamId) and then close the connection.
int gracefulCloseDelay = ConnectionCloseChannelAttributes.gracefulCloseDelay(parent);
executor.schedule(() -> {
// Check that the client hasn't already closed the connection (due to the earlier goaway we sent).
if (parent.isActive()) {
// NOTE - the netty Http2ConnectionHandler specifically does not send another goaway when we call
// channel.close() if one has already been sent .... so when we want more than one sent, we need to do it
// explicitly ourselves like this.
LOG.debug("gracefullyWithDelay: firing graceful_shutdown event to make netty send a final go_away frame and then close connection. channel=" + parent.id().asShortText());
Http2Exception h2e = new Http2Exception(Http2Error.NO_ERROR, Http2Exception.ShutdownHint.GRACEFUL_SHUTDOWN);
parent.pipeline().fireExceptionCaught(h2e);
parent.close().addListener(future -> {
promise.setSuccess();
});
} else {
promise.setSuccess();
}
}, gracefulCloseDelay, TimeUnit.SECONDS);
}
use of io.netty.handler.codec.http2.Http2Exception in project grpc-java by grpc.
the class NettyClientHandler method forcefulClose.
private void forcefulClose(final ChannelHandlerContext ctx, final ForcefulCloseCommand msg, ChannelPromise promise) throws Exception {
connection().forEachActiveStream(new Http2StreamVisitor() {
@Override
public boolean visit(Http2Stream stream) throws Http2Exception {
NettyClientStream.TransportState clientStream = clientStream(stream);
Tag tag = clientStream != null ? clientStream.tag() : PerfMark.createTag();
PerfMark.startTask("NettyClientHandler.forcefulClose", tag);
PerfMark.linkIn(msg.getLink());
try {
if (clientStream != null) {
clientStream.transportReportStatus(msg.getStatus(), true, new Metadata());
resetStream(ctx, stream.id(), Http2Error.CANCEL.code(), ctx.newPromise());
}
stream.close();
return true;
} finally {
PerfMark.stopTask("NettyClientHandler.forcefulClose", tag);
}
}
});
close(ctx, promise);
}
use of io.netty.handler.codec.http2.Http2Exception in project grpc-java by grpc.
the class NettyClientHandler method goingAway.
/**
* Handler for a GOAWAY being received. Fails any streams created after the
* last known stream. May only be called during a read.
*/
private void goingAway(long errorCode, byte[] debugData) {
Status finalStatus = statusFromH2Error(Status.Code.UNAVAILABLE, "GOAWAY shut down transport", errorCode, debugData);
lifecycleManager.notifyGracefulShutdown(finalStatus);
abruptGoAwayStatus = statusFromH2Error(Status.Code.UNAVAILABLE, "Abrupt GOAWAY closed unsent stream", errorCode, debugData);
// While this _should_ be UNAVAILABLE, Netty uses the wrong stream id in the GOAWAY when it
// fails streams due to HPACK failures (e.g., header list too large). To be more conservative,
// we assume any sent streams may be related to the GOAWAY. This should rarely impact users
// since the main time servers should use abrupt GOAWAYs is if there is a protocol error, and if
// there wasn't a protocol error the error code was probably NO_ERROR which is mapped to
// UNAVAILABLE. https://github.com/netty/netty/issues/10670
final Status abruptGoAwayStatusConservative = statusFromH2Error(null, "Abrupt GOAWAY closed sent stream", errorCode, debugData);
final boolean mayBeHittingNettyBug = errorCode != Http2Error.NO_ERROR.code();
// Try to allocate as many in-flight streams as possible, to reduce race window of
// https://github.com/grpc/grpc-java/issues/2562 . To be of any help, the server has to
// gracefully shut down the connection with two GOAWAYs. gRPC servers generally send a PING
// after the first GOAWAY, so they can very precisely detect when the GOAWAY has been
// processed and thus this processing must be in-line before processing additional reads.
// This can cause reentrancy, but should be minor since it is normal to handle writes in
// response to a read. Also, the call stack is rather shallow at this point
clientWriteQueue.drainNow();
if (lifecycleManager.notifyShutdown(finalStatus)) {
// This is for the only RPCs that are actually covered by the GOAWAY error code. All other
// RPCs were not observed by the remote and so should be UNAVAILABLE.
channelInactiveReason = statusFromH2Error(null, "Connection closed after GOAWAY", errorCode, debugData);
}
final int lastKnownStream = connection().local().lastStreamKnownByPeer();
try {
connection().forEachActiveStream(new Http2StreamVisitor() {
@Override
public boolean visit(Http2Stream stream) throws Http2Exception {
if (stream.id() > lastKnownStream) {
NettyClientStream.TransportState clientStream = clientStream(stream);
if (clientStream != null) {
// RpcProgress _should_ be REFUSED, but are being conservative. See comment for
// abruptGoAwayStatusConservative. This does reduce our ability to perform transparent
// retries, but only if something else caused a connection failure.
RpcProgress progress = mayBeHittingNettyBug ? RpcProgress.PROCESSED : RpcProgress.REFUSED;
clientStream.transportReportStatus(abruptGoAwayStatusConservative, progress, false, new Metadata());
}
stream.close();
}
return true;
}
});
} catch (Http2Exception e) {
throw new RuntimeException(e);
}
}
use of io.netty.handler.codec.http2.Http2Exception in project grpc-java by grpc.
the class NettyClientHandler method channelInactive.
/**
* Handler for the Channel shutting down.
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
try {
logger.fine("Network channel is closed");
Status status = Status.UNAVAILABLE.withDescription("Network closed for unknown reason");
lifecycleManager.notifyShutdown(status);
final Status streamStatus;
if (channelInactiveReason != null) {
streamStatus = channelInactiveReason;
} else {
streamStatus = lifecycleManager.getShutdownStatus();
}
try {
cancelPing(lifecycleManager.getShutdownThrowable());
// Report status to the application layer for any open streams
connection().forEachActiveStream(new Http2StreamVisitor() {
@Override
public boolean visit(Http2Stream stream) throws Http2Exception {
NettyClientStream.TransportState clientStream = clientStream(stream);
if (clientStream != null) {
clientStream.transportReportStatus(streamStatus, false, new Metadata());
}
return true;
}
});
} finally {
lifecycleManager.notifyTerminated(status);
}
} finally {
// Close any open streams
super.channelInactive(ctx);
if (keepAliveManager != null) {
keepAliveManager.onTransportTermination();
}
}
}
Aggregations