Don't collect a stream before its fin has been sent - #2570
Open
kixelated wants to merge 1 commit into
Open
Conversation
A `fin` carries no bytes of its own, so acking the stream data up to the final offset says nothing about whether the peer learned the final size. SendBuf::is_complete() checked only the acked ranges, which meant a zero-length `fin` written at an already-acked offset reported the send side complete the moment it was written. That is enough for the caller to collect the stream, and collecting it discards the queued `fin` before any frame carrying it is built. The peer reads every byte and never sees the end of the stream, while the sender believes it delivered one. stream_send() returns Ok, so nothing surfaces the loss. Reaching it needs the ack for the stream data to land between the `fin` being written and the next send(), which is routine for an application that writes its payload and finishes the stream on a later turn of its event loop. Track the `fin` ack separately and require it. RESET_STREAM carries the final size in place of a `fin`, so SendBuf::reset() sets the flag too; without that a reset stream would never be collected. Fixes cloudflare#2525 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
(AI generated but reviewed)
A
fincarries no bytes of its own, so acking the stream data up to the final offset says nothing about whether the peer learned the final size. SendBuf::is_complete() checked only the acked ranges, which meant a zero-lengthfinwritten at an already-acked offset reported the send side complete the moment it was written.That is enough for the caller to collect the stream, and collecting it discards the queued
finbefore any frame carrying it is built. The peer reads every byte and never sees the end of the stream, while the sender believes it delivered one. stream_send() returns Ok, so nothing surfaces the loss.Reaching it needs the ack for the stream data to land between the
finbeing written and the next send(), which is routine for an application that writes its payload and finishes the stream on a later turn of its event loop.Track the
finack separately and require it. RESET_STREAM carries the final size in place of afin, so SendBuf::reset() sets the flag too; without that a reset stream would never be collected.Fixes #2525