http: fix drain event with cork/uncork
Fixes https://github.com/nodejs/node/issues/60432
This is a copy of PR #60437, so credit for the fix goes to @ThierryMT. Sadly that PR was abandoned and I wasn't able to get a response from the author. I've just applied their changes to the latest main, patched up the lint errors, and applied the suggested change to the tests. I've signed the certificate of origin on the basis that the test is based on the reproduction I provided in the original bug report #60432 (hence, created in part by me), but let me know if this is too tenuous and I can write a new test from scratch instead. The fix itself is so trivial that I'm not sure there's a way to write it which isn't effectively the same code.
Original PR description:
When using cork() and uncork() with ServerResponse, the drain event was not reliably emitted after uncorking. This occurred because the uncork() method did not check if a drain was pending (kNeedDrain flag) after flushing the chunked buffer.
The Problem:
- When corked,
write()buffers data inkChunkedBufferinstead of sending immediately - If
write()returnsfalse,kNeedDrainis set totrue - When
uncork()is called, it flushes the buffer by calling_send() - After flushing,
uncork()never checked if drain was needed or emitted the event - This left the response waiting for a
drainevent that would never fire
The Fix:
This commit ensures that when uncork() successfully flushes buffered data and a drain was needed, the drain event is emitted immediately.
Changes:
- Modified
OutgoingMessage.prototype.uncork()inlib/_http_outgoing.js - Capture return value from final
_send()call - Check if drain was pending after successful flush
- Emit
drainevent when appropriate
Testing:
The issue could be reproduced by using cork() with multiple large writes and checking for drain events. With this fix, the drain event now fires correctly after uncork().