fix(fetch): dump the body of a 3xx response that will be followed - #5729
Open
zeexzeex wants to merge 1 commit into
Open
fix(fetch): dump the body of a 3xx response that will be followed#5729zeexzeex wants to merge 1 commit into
zeexzeex wants to merge 1 commit into
Conversation
The body of a redirect response is never exposed when the redirect is followed, so nothing ever reads the stream it is pushed into. Once the buffered body exceeds the stream highWaterMark the socket is paused and never resumed, which keeps the connection in a running state. With a pooled dispatcher every redirect pins a connection until the pool is exhausted. The dispatcher path already discards 3xx bodies in RedirectHandler, so do the same in the fetch path. The flag lives on the dispatch handler rather than on the fetch controller because the controller is shared across the whole redirect chain, and setting it there would also discard the final response body. Signed-off-by: Avocado <ujubongbong@gmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5729 +/- ##
==========================================
- Coverage 93.47% 93.46% -0.01%
==========================================
Files 110 110
Lines 38908 38915 +7
==========================================
+ Hits 36368 36372 +4
- Misses 2540 2543 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
This relates to...
Fixes #5728
Rationale
When
fetch()follows a redirect, the body of the 3xx response is pushed into aReadablethat nothing ever reads. Once the buffered body exceeds the stream highWaterMark,push()returnsfalseand the socket is paused.Nothing resumes it. The call that resumes the socket lives in that stream's
read(), andread()only fires when a consumer pulls from the stream. For a followed redirect the response is never exposed to the caller, so no consumer is ever attached: resuming the socket requires reading the body, and the reader only appears once the redirect chain has been followed. The connection stays in a running state and is never returned to the pool.With a pooled dispatcher this is worse than a single stalled request, since every redirect pins a connection until the
connectionslimit is exhausted. In the reported case a 301 carrying a 128 KiB body withAgent({ connections: 1 })makesfetch()never settle, and the follow-up request never reaches the server at all.RedirectHandleralready discards 3xx bodies on the dispatcher path, citing RFC 7231 section 6.4. This applies the same behaviour to the fetch path.Changes
The fix reuses the
willFollowvalue thatonResponseStartalready computes for content-encoding handling, and discards the chunks inonResponseDatainstead of pushing them into the stream.The flag is stored on the dispatch handler rather than on
fetchParams.controller. The controller is created once perfetch()call and shared across the whole redirect chain, so settingdumpthere would also discard the final response body. The handler object is created per dispatch, which scopes the change to the redirect response alone.Features
N/A
Bug Fixes
Breaking Changes and Deprecations
N/A
Status