From 22a26afbaf666217694bcf782c75cd1d1510b9b9 Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Mon, 22 Nov 2021 21:32:18 +0100 Subject: [PATCH] [fix] Resume the socket in the `CLOSING` state When the value of the `readyState` attribute is `CLOSING`, the internal socket might still be open. Resume it to read any remaining data and to allow the connection to be closed cleanly. --- lib/stream.js | 5 ++++- test/create-websocket-stream.test.js | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/stream.js b/lib/stream.js index b0896ff83..19e1bff4a 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -152,7 +152,10 @@ function createWebSocketStream(ws, options) { }; duplex._read = function () { - if (ws.readyState === ws.OPEN && !resumeOnReceiverDrain) { + if ( + (ws.readyState === ws.OPEN || ws.readyState === ws.CLOSING) && + !resumeOnReceiverDrain + ) { resumeOnReceiverDrain = true; if (!ws._receiver._writableState.needDrain) ws._socket.resume(); } diff --git a/test/create-websocket-stream.test.js b/test/create-websocket-stream.test.js index b96ac9b1b..82fd44f0a 100644 --- a/test/create-websocket-stream.test.js +++ b/test/create-websocket-stream.test.js @@ -538,5 +538,31 @@ describe('createWebSocketStream', () => { }); }); }); + + it('resumes the socket if `readyState` is `CLOSING`', (done) => { + const wss = new WebSocket.Server({ port: 0 }, () => { + const ws = new WebSocket(`ws://localhost:${wss.address().port}`); + const duplex = createWebSocketStream(ws); + + ws.on('message', () => { + assert.ok(ws._socket.isPaused()); + + duplex.on('close', () => { + wss.close(done); + }); + + duplex.end(); + + process.nextTick(() => { + assert.strictEqual(ws.readyState, WebSocket.CLOSING); + duplex.resume(); + }); + }); + }); + + wss.on('connection', (ws) => { + ws.send(randomBytes(16 * 1024)); + }); + }); }); });