-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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 compat stream read handling, add tests #15503
Conversation
const onfinish = this[kFinish].bind(this); | ||
stream.on('streamClosed', onfinish); | ||
stream.on('finish', onfinish); | ||
this.on('pause', onRequestPause); | ||
this.on('resume', onRequestResume); | ||
this.on('drain', onRequestDrain); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't an event on Readable.
lib/internal/http2/compat.js
Outdated
@@ -221,7 +222,7 @@ class Http2ServerRequest extends Readable { | |||
_read(nread) { | |||
const stream = this[kStream]; | |||
if (stream !== undefined) { | |||
stream.resume(); | |||
process.nextTick(() => stream.resume()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a race condition where pause
can get evaluated in between resume
being called and actually running (basically after resumeScheduled: true
and before nextTick). This fixes it and passes all our tests (plus a new one that failed before).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should not create a closure here, but rather use a top level function and pass the stream in there.
function onStreamClosedRequest() { | ||
this[kRequest].push(null); | ||
} | ||
|
||
// TODO Http2Stream does not emit 'close' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can remove these comments but I wanted it clear that these two don't run as things are. It's a bit confusing otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasnell can we remove those then? Or do you prefer if we add 'close' to Http2Stream?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with removing the comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh lol... heh Matteo pointed out that I didn't understand the comments :-) This is true, I missed that.
I'm thinking we need to refactor this so that streamClosed
and close
are one and the same and that close
is emitted appropriately. The one bit we'd have to account for is the code
that is reported in streamClosed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be wrong but I think @mcollina is asking about removing the functions which the comments refer to. If a 'close' event will be added to Http2Stream at some point then they should be kept but if that's not going to happen then we can safely remove. too slow lol
4ae899a
to
05de543
Compare
if (this.writable) { | ||
this.emit('close'); | ||
const response = this[kResponse]; | ||
if (response[kState].closed === false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writable
is currently always true since Http2Stream
doesn't emit a 'close' event but also this seems more correct, as far as I can reason about it and compare it to http1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -158,13 +160,12 @@ class Http2ServerRequest extends Readable { | |||
stream.on('end', onStreamEnd); | |||
stream.on('error', onStreamError); | |||
stream.on('close', onStreamClosedRequest); | |||
stream.on('aborted', onStreamAbortedRequest.bind(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any bind
in here is expensive. I think only binding the most crucial things that are almost guaranteed to run (that being onfinish
) is smart.
lib/internal/http2/compat.js
Outdated
res.writable = false; | ||
res.emit('finish'); | ||
const response = this[kResponse]; | ||
response.writable = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove setting writable = false
. This would break pump. See #15029
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work, a couple of nits.
lib/internal/http2/compat.js
Outdated
@@ -221,7 +222,7 @@ class Http2ServerRequest extends Readable { | |||
_read(nread) { | |||
const stream = this[kStream]; | |||
if (stream !== undefined) { | |||
stream.resume(); | |||
process.nextTick(() => stream.resume()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should not create a closure here, but rather use a top level function and pass the stream in there.
Handle edge case where stream pause is called between resume being called and actually evaluated. Other minor adjustments to avoid various edge cases around stream events. Add new tests that cover all changes. Fixes: nodejs#15491
05de543
to
e1af8b9
Compare
Thanks for the review! Great spot re: the closure. All fixed now and ready for review/CI. |
Sorry, just to confirm — anything I need to change or is this approved? Thanks! (Want to make sure this gets into 8.6.0 since without it people can't use HTTP2 compatibility layer very well, at least not for sending bigger amounts of data.) Also, looks like CI was all good — failures are related to existing known issues reported elsewhere. |
@apapirovski I understood @jasnell would like to have https://github.com/nodejs/node/pull/15503/files#r140291319 sorted before landing. IMHO leaving around functions that are not called is not a good thing. We can land this as it is right now, and send another PR to fix the 'streamClosed' problem, I'm ok with that as well. @jasnell what do you think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I mean, this PR didn't change that behaviour (it just documents it) and it fixes a legitimate, serious bug. Would be nice to get it into 8.6.0. I can't imagine we'll have a resolution for standardizing streamClosed and close before then. (I'm happy to take a look at that next btw.) |
I'm good with getting this landed now and included in 8.6.0, we can resolve the other issues separately |
Handle edge case where stream pause is called between resume being called and actually evaluated. Other minor adjustments to avoid various edge cases around stream events. Add new tests that cover all changes. Fixes: #15491 PR-URL: #15503 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Landed in c705f10 |
cherry-picking into v8.x-staging next |
Handle edge case where stream pause is called between resume being called and actually evaluated. Other minor adjustments to avoid various edge cases around stream events. Add new tests that cover all changes. Fixes: #15491 PR-URL: #15503 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Landed in v8.x-staging... |
Handle edge case where stream pause is called between resume being called and actually evaluated. Other minor adjustments to avoid various edge cases around stream events. Add new tests that cover all changes. Fixes: #15491 PR-URL: #15503 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Handle edge case where stream pause is called between resume being called and actually evaluated. Other minor adjustments to avoid various edge cases around stream events. Add new tests that cover all changes. Fixes: nodejs/node#15491 PR-URL: nodejs/node#15503 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
This PR is mostly about fixing #15491 but also includes some minor changes to improve overall reliability of the various stream events. Test cases for everything are included. (Some notes to follow directly in code.)
Thanks for reviewing!
cc @mcollina, @jasnell
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
http2, test