Skip to content

Commit 22a26af

Browse files
committed
[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.
1 parent 73dec34 commit 22a26af

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

lib/stream.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,10 @@ function createWebSocketStream(ws, options) {
152152
};
153153

154154
duplex._read = function () {
155-
if (ws.readyState === ws.OPEN && !resumeOnReceiverDrain) {
155+
if (
156+
(ws.readyState === ws.OPEN || ws.readyState === ws.CLOSING) &&
157+
!resumeOnReceiverDrain
158+
) {
156159
resumeOnReceiverDrain = true;
157160
if (!ws._receiver._writableState.needDrain) ws._socket.resume();
158161
}

test/create-websocket-stream.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,5 +538,31 @@ describe('createWebSocketStream', () => {
538538
});
539539
});
540540
});
541+
542+
it('resumes the socket if `readyState` is `CLOSING`', (done) => {
543+
const wss = new WebSocket.Server({ port: 0 }, () => {
544+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);
545+
const duplex = createWebSocketStream(ws);
546+
547+
ws.on('message', () => {
548+
assert.ok(ws._socket.isPaused());
549+
550+
duplex.on('close', () => {
551+
wss.close(done);
552+
});
553+
554+
duplex.end();
555+
556+
process.nextTick(() => {
557+
assert.strictEqual(ws.readyState, WebSocket.CLOSING);
558+
duplex.resume();
559+
});
560+
});
561+
});
562+
563+
wss.on('connection', (ws) => {
564+
ws.send(randomBytes(16 * 1024));
565+
});
566+
});
541567
});
542568
});

0 commit comments

Comments
 (0)