Netty HTTP2 Request is timeout #6165

Closed
zmyer opened this Issue Dec 30, 2016 · 8 comments

Projects

None yet

3 participants

@zmyer
zmyer commented Dec 30, 2016

Expected behavior

When I run Netty Http2 helloworld example, it happened timeout request, How to do that, the example all run in localhost, and timeout set 5 seconds. It seem Netty Http2 codec module not too stable.

Actual behavior

Message received for unknown stream id 864103
Exception in thread "main" java.lang.IllegalStateException: Timed out waiting for response on stream id 864103
at io.netty.example.http2.helloworld.client.HttpResponseHandler.awaitResponses(HttpResponseHandler.java:77)
at io.netty.example.http2.helloworld.client.Http2Client.main(Http2Client.java:126)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Steps to reproduce

Minimal yet complete reproducer code (or URL to code)

Netty version

4.1.6.Final

JVM version (e.g. java -version)

jdk1.8.0_91-b14

OS version (e.g. uname -a)

Mac OS X EI Capitan 10.11.1

@Scottmitch
Member

@zmyer - Can you please list the steps to reproduce this issue? Are you running the http2-server and http2-client on the same host? If so how are you running them and with what arguments?

@zmyer
zmyer commented Jan 2, 2017

@Scottmitch, yes, in the same host and all in default. I run http2 example repeatedly. My IDE is IDEA 2016.

@Scottmitch
Member

I am unable to reproduce this issue. Please explicitly list the steps required to reproduce this issue.

@Scottmitch Scottmitch self-assigned this Jan 3, 2017
@zmyer
zmyer commented Jan 4, 2017 edited

en, Ok, now I show such example below, and you can run it much more time.
at such example, I run in local, exception still happen,
Message received for unknown stream id 1857213
Exception in thread "main" java.lang.IllegalStateException: Timed out waiting for response on stream id 1857213
at io.netty.example.http2.helloworld.client.HttpResponseHandler.awaitResponses(HttpResponseHandler.java:81)
at io.netty.example.http2.helloworld.client.Http2Client.main(Http2Client.java:126)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

public final class Http2Client {

    static final boolean SSL = System.getProperty("ssl") != null;
    static final String HOST = System.getProperty("host", "127.0.0.1");
    static final int PORT = Integer.parseInt(System.getProperty("port", SSL ? "8443" : "19991"));
    static final String URL = System.getProperty("url", "/whatever");
    static final String URL2 = System.getProperty("url2");
    static final String URL2DATA = System.getProperty("url2data", "test data!");

    public static void main(String[] args) throws Exception {
        // Configure SSL.
        final SslContext sslCtx;
        if (SSL) {
            SslProvider provider = OpenSsl.isAlpnSupported() ? SslProvider.OPENSSL : SslProvider.JDK;
            sslCtx = SslContextBuilder.forClient()
                    .sslProvider(provider)
                /* NOTE: the cipher filter may not include all ciphers required by the HTTP/2 specification.
                 * Please refer to the HTTP/2 specification for cipher requirements. */
                    .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
                    .trustManager(InsecureTrustManagerFactory.INSTANCE)
                    .applicationProtocolConfig(new ApplicationProtocolConfig(
                            Protocol.ALPN,
                            // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers.
                            SelectorFailureBehavior.NO_ADVERTISE,
                            // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers.
                            SelectedListenerFailureBehavior.ACCEPT,
                            ApplicationProtocolNames.HTTP_2,
                            ApplicationProtocolNames.HTTP_1_1))
                    .build();
        } else {
            sslCtx = null;
        }

        EventLoopGroup workerGroup = new NioEventLoopGroup();
        Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx, Integer.MAX_VALUE);

        try {
            // Configure the client.
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.remoteAddress(HOST, PORT);
            b.handler(initializer);

            // Start the client.
            Channel channel = b.connect().syncUninterruptibly().channel();
            System.out.println("Connected to [" + HOST + ':' + PORT + ']');

            // Wait for the HTTP/2 upgrade to occur.
            Http2SettingsHandler http2SettingsHandler = initializer.settingsHandler();
            http2SettingsHandler.awaitSettings(5, TimeUnit.SECONDS);

            HttpResponseHandler responseHandler = initializer.responseHandler();
            int streamId = 3;
            HttpScheme scheme = SSL ? HttpScheme.HTTPS : HttpScheme.HTTP;
            AsciiString hostName = new AsciiString(HOST + ':' + PORT);
            System.err.println("Sending request(s)...");
            for (int index = 0; index < 100000000; index++) {
                if (URL != null) {
                    // Create a simple GET request.
                    FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, URL);
                    request.headers().add(HttpHeaderNames.HOST, hostName);
                    request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name());
                    request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
                    request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
                    responseHandler.put(streamId, channel.writeAndFlush(request), channel.newPromise());
                    streamId += 2;
                }
                if (URL2 != null) {
                    // Create a simple POST request with a body.
                    FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, URL2,
                            Unpooled.copiedBuffer(URL2DATA.getBytes(CharsetUtil.UTF_8)));
                    request.headers().add(HttpHeaderNames.HOST, hostName);
                    request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name());
                    request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
                    request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
                    responseHandler.put(streamId, channel.writeAndFlush(request), channel.newPromise());
                    streamId += 2;
                }
                responseHandler.awaitResponses(5, TimeUnit.SECONDS);
            }
            System.out.println("Finished HTTP/2 request(s)");
            // Wait until the connection is closed.
            channel.close().syncUninterruptibly();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
}
@Scottmitch
Member
Scottmitch commented Jan 4, 2017 edited

I was able to reproduce with 4.1.6.Final (on stream id 697) but I made it past stream id 5,000,000 with HEAD on the 4.1 branch and was unable to reproduce. Can you reproduce with HEAD on the 4.1 branch?

@zmyer
zmyer commented Jan 4, 2017

@Scottmitch , yes, When I change with HEAD on the 4.1 branch, it still happen.

@vongosling

I've had a similar problem :-)

@Scottmitch Scottmitch added defect and removed needs info labels Jan 7, 2017
@Scottmitch Scottmitch added this to the 4.1.7.Final milestone Jan 7, 2017
@Scottmitch
Member

I found some issues in the client example ... standby for a PR.

@Scottmitch Scottmitch added a commit to Scottmitch/netty that referenced this issue Jan 10, 2017
@Scottmitch Scottmitch HTTP/2 HelloWorld Client Example Bug
Motivation:
The HTTP/2 helloworld client example has 2 bugs:
1. HttpResponseHandler has a map which is accessed from multiple threads, but the map is not thread safe.
2. Requests are flushed and maybe completely written and the responses may be received/processed by Netty before an element is inserted into the HttpResponseHandler map. This may result in an 'unexpected message' error even though the message has actually been sent.

Modifications:
- HttpResponseHandler should use a thread safe map
- Http2Client shouldn't flush until entries are added to the HttpResponseHandler map

Result:
Fixes netty#6165.
2a8f2ee
@Scottmitch Scottmitch added a commit that closed this issue Jan 11, 2017
@Scottmitch Scottmitch HTTP/2 HelloWorld Client Example Bug
Motivation:
The HTTP/2 helloworld client example has 2 bugs:
1. HttpResponseHandler has a map which is accessed from multiple threads, but the map is not thread safe.
2. Requests are flushed and maybe completely written and the responses may be received/processed by Netty before an element is inserted into the HttpResponseHandler map. This may result in an 'unexpected message' error even though the message has actually been sent.

Modifications:
- HttpResponseHandler should use a thread safe map
- Http2Client shouldn't flush until entries are added to the HttpResponseHandler map

Result:
Fixes #6165.
d771526
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment