Conversation
|
Can one of the admins verify this patch? |
…ailure Motivation: When writing an HTTP/2 HEADERS with END_STREAM=1, the application expects the stream to be closed afterward. However, the write can fail locally due to HPACK encoder and similar. When that happens we need to make sure to issue a RST_STREAM otherwise the stream can be closed locally but orphaned remotely. The RST_STREAM is typically handled by Http2ConnectionHandler.onStreamError, which will only send a RST_STREAM if that stream still exists locally. There are two possible flows for trailers, one handled immediately and one going through the flow controller. Previously they behaved differently, with the immedate code calling the error handler after closing the stream. The immediate code also used a listener for calling closeStreamLocal while the flow controlled code did so immediately after the write. The two code paths also differed in their VoidChannelPromise handling, but both were broken. The immediate code path called unvoid() only if END_STREAM=1, however it could always potentially add a listener via notifyLifecycleManagerOnError(). And the flow controlled code path unvoided incorrectly, changing the promise completion behavior. It also passed the wrong promise to closeStreamLocal() in FlowControlledBase. Modifications: Move closeStreamLocal handling after calls to onError. This is the primary change. Now call closeStreamLocal immediately instead of when the future completes. This is the more likely correct behavior as it matches that of DATA frames. Fix all the VoidChannelPromise handling. Result: Http2ConnectionHandler.onStreamError sees the same state as the remote and issues a RST_STREAM, properly cleaning up the stream.
Member
|
@netty-bot add to whitelist. |
d65453e to
3c0bf0a
Compare
Member
|
@netty-bot test this please |
normanmaurer
approved these changes
Sep 27, 2018
Member
Author
Member
|
@bryce-anderson @mosesn would love to have you review as well . |
Member
|
@trustin please check as well |
trustin
approved these changes
Sep 28, 2018
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation:
When writing an HTTP/2 HEADERS with END_STREAM=1, the application expects
the stream to be closed afterward. However, the write can fail locally
due to HPACK encoder and similar. When that happens we need to make sure
to issue a RST_STREAM otherwise the stream can be closed locally but
orphaned remotely. The RST_STREAM is typically handled by
Http2ConnectionHandler.onStreamError, which will only send a RST_STREAM
if that stream still exists locally.
There are two possible flows for trailers, one handled immediately and
one going through the flow controller. Previously they behaved
differently, with the immedate code calling the error handler after
closing the stream. The immediate code also used a listener for calling
closeStreamLocal while the flow controlled code did so immediately after
the write.
The two code paths also differed in their VoidChannelPromise handling,
but both were broken. The immediate code path called unvoid() only if
END_STREAM=1, however it could always potentially add a listener via
notifyLifecycleManagerOnError(). And the flow controlled code path
unvoided incorrectly, changing the promise completion behavior. It also
passed the wrong promise to closeStreamLocal() in FlowControlledBase.
Modifications:
Move closeStreamLocal handling after calls to onError. This is the
primary change.
Now call closeStreamLocal immediately instead of when the future
completes. This is the more likely correct behavior as it matches that
of DATA frames.
Fix all the VoidChannelPromise handling.
Result:
Http2ConnectionHandler.onStreamError sees the same state as the remote
and issues a RST_STREAM, properly cleaning up the stream.
CC @normanmaurer, @Scottmitch
This issue impacts trailers and headers-only responses with malformed headers.
This was breaking a new gRPC test I wrote that tested MAX_HEADER_LIST_SIZE
behavior and caused the client RPC to time out because the server never sent a
response.
This does raise an oddity that we will closeStreamLocal() even if the END_STREAM=1
frame failed. That risks the local and remote states becoming out-of-sync and today
works because of Http2ConnectionHandler's behavior. However, given
Http2ConnectionHandler's current behavior it's not necessary at all to closeStreamLocal()
on failure; the rstStream will do that. Any change there seems like it should be a separate
discussion though.