-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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 endless loop when write an empty string #18673
Conversation
lib/internal/http2/core.js
Outdated
@@ -1609,6 +1609,9 @@ class Http2Stream extends Duplex { | |||
return; | |||
} | |||
|
|||
if ((typeof data === 'string' || Buffer.isBuffer(data)) && !data.length) | |||
return; |
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.
The first piece of the conditional is always true; Also, you’d still need to call cb
.
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 confused that is the logic below the same?
req.write('');
req.end();
vs
req.end();
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.
That means can I actully ignore empty string stream?
lib/internal/http2/core.js
Outdated
@@ -1645,6 +1648,9 @@ class Http2Stream extends Duplex { | |||
return; | |||
} | |||
|
|||
if ((typeof data === 'string' || Buffer.isBuffer(data)) && !data.length) |
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.
(Basically the same comment, except that the first piece of the conditional is never true; data is an array)
If we do `req.write("")` (an empty string) on Http2Stream, the gather logic will be messed up: ``` while ((src_length = nghttp2_session_mem_send(session_, &src)) > 0) { printf("write\n"); DEBUG_HTTP2SESSION2(this, "nghttp2 has %d bytes to send", src_length); CopyDataIntoOutgoing(src, src_length); } ``` The logic above is in function `Http2Session::SendPendingData` under src/node_http2.cc. This `while` will be endless when an empty string is inside because `src_length` will always be 9. And then the main event loop thread will be blocked and the memory used will be larger and larger. This pull request is to ignore empty string or buffer in `_write()` and `_writev()` of Http2Stream. Fixes: nodejs#18169 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661
@addaleax I've updated the code. |
@XadillaX But this still wouldn’t send out an empty frame, like we’d expect, right? I think this line is the reason why we don’t tell nghttp2 to defer the frames: Line 2232 in a1bab82
The queue isn’t empty when we schedule an empty write, even though we don’t have any data available. Maybe we can just drop the last check in that conditional? |
@XadillaX You’re right, and this way is certainly an approach to fix this bug. I’d have a preference for fixing it on the native level, though:
If you want, you can still make the case for not sending empty data frames on the HTTP/2 level, but that should still be done as part of the implementation, not part of the streams API. |
Hm … @XadillaX any further thoughts on this one? |
@addaleax Sorry for late reply because of Chinese Spring Festival. I think you're right, if we can solve this issue in C++, then in C++. |
PR-URL: #18924 Fixes: #18169 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: #18673 PR-URL: #18924 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
PR-URL: nodejs#18924 Fixes: nodejs#18169 Refs: nodejs#18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: nodejs#18673 PR-URL: nodejs#18924 Refs: nodejs#18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
PR-URL: nodejs#18924 Fixes: nodejs#18169 Refs: nodejs#18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: nodejs#18673 PR-URL: nodejs#18924 Refs: nodejs#18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Backport-PR-URL: #20456 PR-URL: #18924 Fixes: #18169 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: #18673 Backport-PR-URL: #20456 PR-URL: #18924 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
PR-URL: nodejs#18924 Fixes: nodejs#18169 Refs: nodejs#18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: nodejs#18673 PR-URL: nodejs#18924 Refs: nodejs#18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Backport-PR-URL: #20456 PR-URL: #18924 Fixes: #18169 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: #18673 Backport-PR-URL: #20456 PR-URL: #18924 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Backport-PR-URL: #20456 PR-URL: #18924 Fixes: #18169 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Refs: #18673 Backport-PR-URL: #20456 PR-URL: #18924 Refs: #18673 Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484 Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
If we do
req.write("")
(an empty string) on Http2Stream, the gatherlogic will be messed up:
The logic above is in function
Http2Session::SendPendingData
undersrc/node_http2.cc. This
while
will be endless when an empty string isinside because
src_length
will always be 9.And then the main event loop thread will be blocked and the memory used
will be larger and larger.
This pull request is to ignore empty string or buffer in
_write()
and_writev()
of Http2Stream.Fixes: #18169
Refs: https://github.com/nodejs/node/blob/v9.5.0/src/node_http2.cc#L1481-L1484
Refs: https://github.com/nodejs/node/blob/v9.5.0/lib/_http_outgoing.js#L659-L661
Checklist
make -j4 test
passesAffected core subsystem(s)
http2