Skip to content

fix: preserve res.write() return value so backpressure is not swallowed - #67

Open
IanMcNelly wants to merge 1 commit into
PayU:masterfrom
IanMcNelly:fix/preserve-res-write-return-value
Open

fix: preserve res.write() return value so backpressure is not swallowed#67
IanMcNelly wants to merge 1 commit into
PayU:masterfrom
IanMcNelly:fix/preserve-res-write-return-value

Conversation

@IanMcNelly

@IanMcNelly IanMcNelly commented Aug 21, 2026

Copy link
Copy Markdown

Closes #66

res.write is overridden to capture the response body for auditing, but the override calls oldWrite.apply(res, arguments) without returning its result, so every caller gets undefined instead of the boolean Node's write() contractually returns for backpressure. Anything downstream that honours that return value (if (!res.write(chunk)) await once(res, 'drain'), or a stream's .pipe()) reads the undefined as "buffer full" and waits for a drain event that never comes, since the buffer was never actually full, so the response hangs.

Fix is one line, return what oldWrite.apply returns instead of discarding it:

     res.write = function (chunk) {
         chunks.push(Buffer.from(chunk));
-        oldWrite.apply(res, arguments);
+        return oldWrite.apply(res, arguments);
     };

Added a regression test covering both boolean branches, and a CHANGELOG entry under ## [Unreleased] since I didn't want to guess at a version number, feel free to fold that into whatever heading you cut on release.

Testing: npm ci && npm test && npm run test:coverage on Node 16 and 22, 90 passing both times, express-logger.js at 100/100/100/100 coverage. Also reverted the one-line fix locally to confirm the new test actually fails without it (AssertionError: expected undefined to equal false).

Compatibility: non-breaking. Anyone currently ignoring res.write()'s return value (the common case) is unaffected. Anyone who was checking it and handling undefined as "always backpressured" was already broken by this; they'll now get the real signal instead.

Scoped to res.write only, res.json/res.end have the same discarded-return-value issue but only affect chaining, not control flow, so I left them out to keep the scope small

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

res.write() returns undefined instead of the underlying write's boolean, breaking backpressure

1 participant