Search code examples
nettyhttp2push-promise

Netty HTTP/2 writePushPromise makes browser to loop indefinitely


I'm trying to test HTTP/2 push promise with Netty, but doesn't seem to work. Use case is as simple as:

  1. Request home/index page
  2. Index page depends on a index.js file so I want to send a PUSH_PROMISE for index.js
  3. Write and flush content for index page.

Here is what I did:

int nextStreamId = encoder.connection().local().incrementAndGetNextStreamId();
String authority = request.headers().get("host");
Http2Headers pushHeaders = new DefaultHttp2Headers()
    .method("GET")
    .path("/assets/index.js")
    .authority(authority)
    .scheme("https");

encoder.writePushPromise(ctx, Integer.parseInt(streamId), nextStreamId, pushHeaders, 0, ctx.newPromise());

It successfully send a PUSH_PROMISE to the browser but then the /assets/index.js file isn't loaded at all (browser waits indefinitely for a response)

This only happens when I send the PUSH_PROMISE, if I remove those line everything works fine and both files (HTML+js) are served properly via H2.

A full demo is available here (it uses a self-signed certificate so you must accept the unsafe warning)

The source code for PUSH_PROMISE is here.

Am I doing something wrong?

Thanks.


Solution

  • Your server is sending a PUSH_PROMISE but then it is never actually sending the data to complete the promised stream. The PUSH_PROMISE contract is the server saying to the client "I think you will make a request for this data in the future, so instead of you having to make a request I am already working on sending you this data". Notice the difference in the browser's behavior when you DO NOT sent the PUSH_PROMISE. In this case you get at least 2 requests:

    1. /
    2. /assets/index.js
    3. [Your browser may also request /favicon.ico]

    Now contrast this behavior against when your server sends the PUSH_PROMISE:

    1. /
    2. [Your browser may also request /favicon.ico]

    Notice the browser doesn't even request "/assets/index.js" because you told the browser you already anticipated this request and are working on sending the result. So if you send the data for "/assets/index.js" after the PUSH_PROMSIE the browser will be happy.