-
-
Notifications
You must be signed in to change notification settings - Fork 16.3k
HTTP/2 stream initialization fails on incoming preface of max concurrent stream = 1 #8692
Copy link
Copy link
Closed
Description
Expected behavior
No error.
Actual behavior
IllegalStateException is fired.
Steps to reproduce
This error happens with hosts that sends a preface with max concurrent stream = 1, which was api.development.push.apple.com in my case.
Digging the code, I found frameStreamToInitialize is not null opposed to the assertion at https://github.com/netty/netty/blob/netty-4.1.29.Final/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodec.java#L363
Stacktrace:
WARN 2018-12-28T13:47:55,732 [nioEventLoopGroup-2-1] DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.IllegalStateException: Stream object required for identifier: 131
at io.netty.handler.codec.http2.Http2FrameCodec$FrameListener.requireStream(Http2FrameCodec.java:578) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2FrameCodec$FrameListener.onHeadersRead(Http2FrameCodec.java:541) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2FrameCodec$FrameListener.onHeadersRead(Http2FrameCodec.java:534) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onHeadersRead(DefaultHttp2ConnectionDecoder.java:317) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onHeadersRead(DefaultHttp2ConnectionDecoder.java:265) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2InboundFrameLogger$1.onHeadersRead(Http2InboundFrameLogger.java:56) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2FrameReader$2.processFragment(DefaultHttp2FrameReader.java:483) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readHeadersFrame(DefaultHttp2FrameReader.java:491) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2FrameReader.processPayloadState(DefaultHttp2FrameReader.java:254) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readFrame(DefaultHttp2FrameReader.java:160) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2InboundFrameLogger.readFrame(Http2InboundFrameLogger.java:41) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder.decodeFrame(DefaultHttp2ConnectionDecoder.java:118) ~[netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2ConnectionHandler$FrameDecoder.decode(Http2ConnectionHandler.java:390) [netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:450) [netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) [netty-codec-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) [netty-codec-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) [netty-codec-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.http2.Http2MultiplexCodec.channelRead(Http2MultiplexCodec.java:400) [netty-codec-http2-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1429) [netty-handler-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.ssl.SslHandler.decodeNonJdkCompatible(SslHandler.java:1211) [netty-handler-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1245) [netty-handler-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) [netty-codec-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) [netty-codec-4.1.29.Final.jar:4.1.29.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) [netty-codec-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:628) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:528) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:482) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:442) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at java.lang.Thread.run(Thread.java:834) [?:?]
Minimal yet complete reproducer code (or URL to code)
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http2.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.ssl.*;
import io.netty.util.concurrent.FutureListener;
import javax.net.ssl.SSLException;
import java.util.concurrent.CountDownLatch;
final class TestCase {
public static void main(String[] args) throws InterruptedException, SSLException {
ApplicationProtocolConfig apConfig = new ApplicationProtocolConfig(
ApplicationProtocolConfig.Protocol.ALPN,
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
ApplicationProtocolNames.HTTP_2);
SslContext sslContext = SslContextBuilder.forClient()
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
.applicationProtocolConfig(apConfig)
.build();
NioEventLoopGroup group = new NioEventLoopGroup(1);
try {
Channel channel = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<>() {
@Override
protected void initChannel(Channel ch) {
Http2MultiplexCodecBuilder builder = Http2MultiplexCodecBuilder.forClient(new ChannelInitializer<>() {
@Override
protected void initChannel(Channel ch) {
}
});
Http2MultiplexCodec codec = builder
.encoderEnforceMaxConcurrentStreams(true)
.frameLogger(new Http2FrameLogger(LogLevel.INFO))
.build();
ch.pipeline().addLast(sslContext.newHandler(ch.alloc()), codec);
}
})
.connect("api.development.push.apple.com", 443)
.sync()
.channel();
channel.pipeline().get(SslHandler.class).handshakeFuture().sync();
int attempts = 100;
CountDownLatch latch = new CountDownLatch(attempts);
for (int i = 0; i < attempts; i++) {
Http2StreamChannelBootstrap bs = new Http2StreamChannelBootstrap(channel).handler(new ChannelInitializer<>() {
@Override
protected void initChannel(Channel ch) {
}
});
bs.open().addListener((FutureListener<Http2StreamChannel>) future -> {
if (future.isSuccess()) {
Http2StreamChannel ch = future.getNow();
Http2Headers headers = new DefaultHttp2Headers().method(HttpMethod.GET.asciiName()).path("/");
ch.write(new DefaultHttp2HeadersFrame(headers), ch.voidPromise());
ch.writeAndFlush(new DefaultHttp2DataFrame(Unpooled.EMPTY_BUFFER, true), ch.voidPromise());
ch.closeFuture().addListener((ChannelFutureListener) f -> latch.countDown());
} else {
future.cause().printStackTrace();
latch.countDown();
}
});
}
latch.await();
channel.close();
channel.closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
Netty version
4.1.29
JVM version (e.g. java -version)
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
and 11.0.1
OS version (e.g. uname -a)
Darwin localhost 18.2.0 Darwin Kernel Version 18.2.0: Fri Oct 5 19:41:49 PDT 2018; root:xnu-4903.221.2~2/RELEASE_X86_64 x86_64
and some linux machines.
Reactions are currently unavailable