Skip to content

fix(engine.io): run the polling write callback when the client aborts a compressed response - #5540

Open
chuanghiduoc wants to merge 1 commit into
socketio:mainfrom
chuanghiduoc:fix/polling-compression-abort-callback
Open

fix(engine.io): run the polling write callback when the client aborts a compressed response#5540
chuanghiduoc wants to merge 1 commit into
socketio:mainfrom
chuanghiduoc:fix/polling-compression-abort-callback

Conversation

@chuanghiduoc

Copy link
Copy Markdown

Problem

Since 91dd763 ("perf(eio): stream compressed polling responses"), doWrite() invokes its callback only from the response's 'finish' handler. If the client aborts the polling request while a large compressed payload is still streaming, 'finish' never fires — and nothing errors on the zlib pipeline either, because writes into the destroyed socket just become no-ops.

Consequences of the lost callback (write() in polling.ts):

  • req.cleanup() never runs for that request
  • this.emit("drain") never fires, so the send callbacks queued for that batch (sentCallbackFn) are dropped

Before 91dd763, the whole payload was buffered and the callback ran unconditionally right after res.end(), so this could not happen.

Reproduction: new test packages/engine.io/test/compression-abort.js — a client opens a polling request with Accept-Encoding: gzip, the server keeps sending incompressible random data (threshold 0), and the client destroys the request as soon as the response headers arrive. On current main, the server-side send callback of that batch is never invoked; with this PR it always is (verified by stashing the fix and re-running).

Fix

The callback now also runs on the response's 'close' event, with a guard so it still runs exactly once ('close' also fires after normal completion):

this.res.once("finish", done);
this.res.once("close", done);

Testing

  • new test: packages/engine.io/test/compression-abort.js (fails without the fix, passes with it)
  • existing suites unaffected

… a compressed response

Since 91dd763 the write callback of doWrite() only ran on the response's
'finish' event. When the client aborted mid-stream, 'finish' never fired
and the zlib pipeline reported no error, so the callback was lost: the
pending request was not cleaned up and the send callbacks queued for that
batch were never invoked.

The callback now also runs on 'close', guarded so it still fires exactly
once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant