Repository navigation
fix(ttstream): ignore late header frame after stream close instead of tearing down mux transport - #2007
Open
linhongyu510 wants to merge 1 commit into
Open
fix(ttstream): ignore late header frame after stream close instead of tearing down mux transport#2007linhongyu510 wants to merge 1 commit into
linhongyu510 wants to merge 1 commit into
Conversation
close() parks a terminal signal (streamSigNone/streamSigInactive) in the buffered headerSig channel before marking the stream inactive. When an in-flight header frame is dispatched afterwards, onReadHeaderFrame fills s.header but fails to send streamSigActive into the now-full channel and hits the select default branch, which returned errUnexpectedHeader. The read loop treats that protocol error as fatal and tears down the whole mux transport connection (deferred Close(err)), taking down all other streams on the connection. In the default branch, if the stream is already inactive, the header is an in-flight frame for an already-closed stream: drop it and return nil so the transport survives. A genuine duplicate header (no close in between) is still rejected, since it either hits the s.header!=nil guard or reaches the default branch on an active stream.
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.
What type of PR is this?
What this PR does / why we need it:
After a client stream is
close()d, an in-flight header frame can still bedispatched to
onReadHeaderFrame. This is a benign late frame, but today itsurfaces as a fatal
errUnexpectedHeader(code 12002), which the read looptreats as a protocol error and uses to tear down the whole mux transport
connection (deferred
Close(err)) — taking down every other stream sharingthe connection.
Root cause
close()parks a terminal signal (streamSigNone/streamSigInactive) intothe buffered
headerSigchannel (size 1) before marking the streaminactive. A late header then:
s.header = fr.header,streamSigActiveinto the now-fullheaderSigchannel,selectdefaultbranch, which returnederrUnexpectedHeader.Fix
In the
defaultbranch, when the stream is alreadystreamStateInactive, theheader is an in-flight frame for an already-closed stream: drop it (
s.header = nil) and returnnilso the mux transport survives.A genuine duplicate header (two header frames, no close in between) still
errors: it either hits the
s.header != nilguard, or reaches thedefaultbranch on an active stream.
Which issue(s) this PR fixes:
N/A (found via race-oracle testing; no linked issue).
Special notes for your reviewer:
atomic.LoadInt32(&s.state) == streamStateInactive,matching the existing state-machine convention in this file.
stream_client_lateheader_test.go:Test_onReadHeaderFrameAfterCloseIsIgnored— late header after close isignored,
s.headernot leaked.Test_onReadDuplicateHeaderStillErrors— true duplicate still returnserrUnexpectedHeader(guards against over-loosening).Test_onReadHeaderFrameRaceWithClose— racesclose()againstonReadHeaderFramefor 200 iterations; never produces a fatal error.main, the late-header and race tests fail with12002 and the duplicate test still passes; with the fix all pass under
-race.go vetclean; cross-compiles for linux/amd64, linux/arm64,darwin/{arm64,amd64}, windows/amd64.