-
Notifications
You must be signed in to change notification settings - Fork 29.2k
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
fix(http2): check content-length, fix sending RST #53160
base: main
Are you sure you want to change the base?
Conversation
Review requested:
|
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.
Wow. congrats! It would really be better if the patch was landed, yes.
The linter and commit validator are failing, could you check? |
This comment was marked as resolved.
This comment was marked as resolved.
@jasnell could you reach out to the nghttp2 maintainers and ask about the status of that PR? I would sincerely hope we wouldn't have to maintain a floating patch. |
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.
Therefore the best change - although breaking - is to make it emit an error by default.
The reason why .destroy()
does not emit an error by default is that it's a Stream API. .destroy()
without error is supposed to be "safe" to call.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as outdated.
This comment was marked as outdated.
Have you tried pinging nghttp2? |
This comment was marked as resolved.
This comment was marked as resolved.
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
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
…fter_header_block_received
I just found a race after enabling RST_STREAM and GOAWAY in the same packet. When the server sends both RST_STREAM and a terminating GOAWAY in a single frame, the client might send its GOAWAY just after parsing RST_STREAM because it no longer needs the session, but before acknowledging that there's still a GOAWAY to parse. Currently the client sends the GOAWAY, but the server doesn't read it, resulting in stall by the client side as it waits for the server to acknowledge the client's GOAWAY packet, which will never happen. I am yet to figure out a solution to this problem. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #53160 +/- ##
==========================================
+ Coverage 88.23% 88.40% +0.17%
==========================================
Files 651 652 +1
Lines 183863 186639 +2776
Branches 35824 36075 +251
==========================================
+ Hits 162235 165002 +2767
+ Misses 14932 14909 -23
- Partials 6696 6728 +32
|
If the above is true then I believe it should send TCP RST when it sends GOAWAY and receives a GOAWAY afterwards to prevent stalling. |
Hmm... it seems that once the session is closed nghttp2 won't resume parsing the GOAWAY, so we won't know that there was a GOAWAY from the server. In that case there are two options:
The downside with RST is that it won't be retransmitted if it isn't delivered. With FIN instead it would be delivered, but the connection would be stalled as the client's GOAWAY would be never ACKed. So the first could be better... |
Also the drawback with the first one is that the GOAWAY does not have to be necessarily in the same packet where the client decides to end the connection. So, to properly do this it would need to still parse frames and ignore all except GOAWAY. I'll go with always sending an RST after sending a terminating GOAWAY. |
Fixes #35209
Closes #35378
Time spent: 68h
Caution
These bug fixes are potentially
semver-major
!stream.close(NGHTTP2_CANCEL)
closing with0
akaNGHTTP2_NO_ERROR
.serverStream.destroy()
closed with0
, nowNGHTTP2_INTERNAL_ERROR
.clientStream.destroy()
closed with0
, nowNGHTTP2_CANCEL
.content-length
now throwsNGHTTP2_PROTOCOL_ERROR
as according to the spec.GOAWAY
(server -> client) being greeted withGOAWAY
(client -> server) as it's against the spec.NGHTTP2_CANCEL
on socket close, now respectsgoawayCode
anddestroyCode
.For client, the default remains
NGHTTP2_CANCEL
.For server, the default now is
NGHTTP2_INTERNAL_ERROR
.stream.rstCode
being 0 while active - docs say it should be undefined.sessionCode
overrstCode
when destroying a stream with an error.NO_ERROR
if session receivedGOAWAY
withNO_ERROR
and remote closed connection.NO_ERROR
if session sentGOAWAY
withNO_ERROR
and destroyed.GOAWAY
preventingRST_STREAM
from being sent beforeGOAWAY
.nghttp2 correctly assumes that it should prevent
RST_STREAM
from being sent but incorretly applies it to all frames in a packet instead of frames defined afterGOAWAY
. This is not the only thing that nghttp2 does wrong:benchmark/http2/headers.js
callingclient.destroy()
(resulting in dropped requests).Now calls
client.close()
which closes gracefully.connectStreamSocket.destroy()
now closes withNGHTTP2_CONNECT_ERROR
.GOAWAY
onsession.close()
.Http2Session::Close()
and previous writes weren't finished yet.RST_STREAM
on idle streams (to reproduce 16. needs to be fixed).Sorry so many bugs are fixed in a single PR but it's impossible to fix one without fixing them all!
Best if nghttp2/nghttp2#1508 got merged before this, but it has been open for years 😢
Hence the patch for
nghttp2_session.c
/cc @jasnell