fix(parse): pause req during async writeHeaders to avoid chunk loss#1093
Open
guimard wants to merge 1 commit intonode-formidable:masterfrom
Open
fix(parse): pause req during async writeHeaders to avoid chunk loss#1093guimard wants to merge 1 commit intonode-formidable:masterfrom
guimard wants to merge 1 commit intonode-formidable:masterfrom
Conversation
Since parse() was made async in 3.3.2, it awaits writeHeaders() before attaching its data listener (req.pipe after node-formidable#1017). If a caller has attached a 'data' listener on the request before calling form.parse() (e.g. for content-length accounting), the request stream is already in flowing mode. Chunks that arrive during the await are emitted and lost before Formidable pipes the stream, causing the first part(s) of a multipart body to be silently dropped. Pause the request at the top of parse() so that chunks are buffered internally until the parser is ready. req.pipe(pipe) resumes the stream, so no explicit resume is needed. Fixes the regression exposed by downstream node-form-data tests (test-ranged-filestream.js), where the caller adds a req.on('data') listener for content-length accounting before form.parse(req).
GrosSacASac
approved these changes
Apr 17, 2026
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.
Summary
Since
parse()was made async in 3.3.2, it awaitswriteHeaders()before attaching its data handling (nowreq.pipe(pipe)after #1017). If a caller has attached a'data'listener on the request before callingform.parse()— a common pattern for content-length accounting or logging — the request stream is already in flowing mode. Chunks that arrive during the microtask yielded by theawaitare emitted and lost before Formidable pipes the stream, causing the first part(s) of a multipart body to be silently dropped.Reproduction
See the added test
test-node/standalone/parse-data-race.test.js. A server attachesreq.on('data', …)for content-length accounting, then callsform.parse(req, cb)with a multipart body containing three fields. Without the fix, only the last field is parsed; with the fix all three arrive.The regression was originally reported downstream via node-form-data's
test-ranged-filestream.js, where areq.on('data')listener for content-length verification causes the first two of five parts to vanish.Fix
Pause the request at the top of
parse()so chunks are buffered in the request's internal queue until the parser is ready.req.pipe(pipe)later resumes the stream, so no explicitresume()is needed.Test plan
test-node/standalone/parse-data-race.test.jspasses with the fix and fails without it