Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http2: fix missing 'timeout' event emit in request and response #20918

Conversation

DaAitch
Copy link
Contributor

@DaAitch DaAitch commented May 23, 2018

A timeout in a http2 stream should emit a 'timeout' event also on
request and response object. If there is no listener on stream,
request or response, stream should immediately be destroyed.

Fixes: #20079

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

A timeout in a http2 stream should emit a 'timeout' event also on
request and response object. If there is no listener on stream,
request or response, stream should immediately be destroyed.

Fixes: nodejs#20079
@nodejs-github-bot nodejs-github-bot added the lib / src Issues and PRs related to general changes in the lib or src directory. label May 23, 2018
Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @DaAitch — thanks for working on this. I would say that this might be the slightly wrong approach. We could simplify this by just listening to the timeout even in req and res. From there we would have to make sure any logic matches what we have on the http side in terms of whether we destroy the stream/session. There are some "complexities" in how the http module handles timeouts in relation to whether the req & res are complete or not.

I'm currently in the midst of travelling but would be happy to provide more info when I have a bit more time.

@DaAitch
Copy link
Contributor Author

DaAitch commented May 25, 2018

We could simplify this by just listening to the timeout even in req and res

I have also investigated on that, but in this case, we cannot find out, if there is no listener to timeout at req and res to destroy the stream. I also read the http module, and they're also not listening on the events, but doing it like

const a = req.emit('timeout');
const b = res.emit('timeout');

if (!a && !b) {
  destroy();
}

@@ -12,6 +12,10 @@ server.on('request', (req, res) => {
req.setTimeout(msecs, common.mustCall(() => {
res.end();
}));

res.on('timeout', common.mustCall());
req.on('timeout', common.mustCall());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add some assertions that verifies that 'timeout'  is not emitted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcollina sure I can. You mean between the setTimeout call and its callback, there should be no timeout events on req and res?

if (component.emit('timeout')) {
hasTimeoutCallback = true;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just check if if(!this.emit('timeout')) { this.session.destroy() }. It would need a test on the change in http2 core behavior.

Copy link
Contributor Author

@DaAitch DaAitch May 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcollina I think, this is not what the docs are saying. We have 3 EventEmitters (req, res, stream) and if all of them return false, which means "there is no timeout listener" (according to the docs), then we can destroy the session.

stream, headers, flags, rawHeaders) {
const server = this;
const request = new ServerRequest(stream, headers, undefined, rawHeaders);
const response = new ServerResponse(stream);

stream[kStreamEventsComposite].push(request);
stream[kStreamEventsComposite].push(response);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding things to an array, I would add an event listener to 'timeout' on the stream.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcollina as I described in the 2nd comment here, if we add a timeout listener to an EventEmitter, the checks with if (...emit(...)) will not work, because they all are always true then.

@apapirovski
Copy link
Member

I'm still thinking about this. Hopefully can provide more insight after the summit.

@jasnell
Copy link
Member

jasnell commented Sep 10, 2018

An alternative fix landed in #22252

@jasnell jasnell closed this Sep 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lib / src Issues and PRs related to general changes in the lib or src directory.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

http2 compat does not emit 'timeout' event on request object
5 participants