Skip to content

http2: Only first headers cause an event in http2 stream, all following headers are muted. #38258

@elmerbulthuis

Description

@elmerbulthuis

What steps will reproduce the bug?

When making a http2 request, it seems that events are only fired for the first headers in the stream and not the following!

I encountered this problem when waiting for a response after a continue response. The first headers are the continue response so I do get an event for them. But the next headers (the actual response) do not fire an event.

The following code exposes the bug

const http = require("http");
const http2 = require("http2");

main();

async function main(){
    await testHttp();
    await testHttp2();
}

async function testHttp () {
    console.log("http test");

    const server = http.createServer((request, response) => response.end());
    await new Promise(resolve => server.listen(9090, resolve));

    const stream = http.request(
        "http://localhost:9090/",
        {
            headers: {
                "expect": "100-continue",
            },
        });

    const errorPromise = new Promise((resolve, reject) => stream.addListener("error", reject));
    const continuePromise = new Promise(resolve => stream.addListener("continue", resolve));
    const responsePromise = new Promise(resolve => stream.addListener("response", resolve));

    const continueValue = await Promise.race([
        errorPromise,
        continuePromise,
    ]);

    console.log("continue");

    const responseValue = await Promise.race([
        errorPromise,
        responsePromise,
    ]);

    console.log("response");

    await new Promise(
        (resolve, reject) => server.close(error => error ?
            reject(error) :
            resolve()),
    );

    console.log("done");
}

async function testHttp2() {
    console.log("http2 test");

    const server = http2.createServer((request, response) => response.end());
    await new Promise(resolve => server.listen(9090, resolve));

    const session = http2.connect("http://localhost:9090");
    const stream = session.request({
        ":path": "/",
        "expect": "100-continue",
    });

    const errorPromise = new Promise((resolve, reject) => stream.addListener("error", reject));
    const continuePromise = new Promise(resolve => stream.addListener("continue", resolve));
    const responsePromise = new Promise(resolve => stream.addListener("response", resolve));

    const continueValue = await Promise.race([
        errorPromise,
        continuePromise,
    ]);

    console.log("continue");

    const responseValue = await Promise.race([
        errorPromise,
        responsePromise,
    ]);

    // unfortunately we never get to here in node v15.4.0
    console.log("response");

    await new Promise(
        resolve => session.close(resolve),
    );

    await new Promise(
        (resolve, reject) => server.close(error => error ?
            reject(error) :
            resolve()),
    );

    console.log("done");
}

Also tried listening to the headers event of the http2 stream, this event fires only the first time (on the continue response), the next time (actuel response) there is no event.

How often does it reproduce? Is there a required condition?

reproduces every time!

What is the expected behavior?

When receiving a http continue response i expect the continue event to be fired, when receiveing a http response (other than continue) i expect the response event to be fired!

What do you see instead?

only the first headers frame causes an event to be fired. The event is correct, but the second event never happens!

Additional information

Please help! This bug makes the nodejs http2 client useless for our use case!

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues with confirmed bugs.http2Issues or PRs related to the http2 subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions