From 8806aa9a836c3a616c9511adad159c65eeb153b0 Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Tue, 8 Jun 2021 11:29:50 +0200 Subject: [PATCH] [fix] Close the connection cleanly when an error occurs Instead of destroying the socket, try to close the connection cleanly if an error (such as a data framing error) occurs after the opening handshake has completed. Also, to comply with the specification, use the 1006 status code if no close frame is received, even if the connection is closed due to an error. Fixes #1898 --- lib/websocket.js | 5 ++--- test/websocket.test.js | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index 83b471d94..40ab4e86a 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -808,11 +808,10 @@ function receiverOnError(err) { const websocket = this[kWebSocket]; websocket._socket.removeListener('data', socketOnData); + websocket._socket.resume(); - websocket._readyState = WebSocket.CLOSING; - websocket._closeCode = err[kStatusCode]; + websocket.close(err[kStatusCode]); websocket.emit('error', err); - websocket._socket.destroy(); } /** diff --git a/test/websocket.test.js b/test/websocket.test.js index d7cf3aee8..a0557980e 100644 --- a/test/websocket.test.js +++ b/test/websocket.test.js @@ -429,6 +429,7 @@ describe('WebSocket', () => { describe('Events', () => { it("emits an 'error' event if an error occurs", (done) => { + let clientCloseEventEmitted = false; const wss = new WebSocket.Server({ port: 0 }, () => { const ws = new WebSocket(`ws://localhost:${wss.address().port}`); @@ -440,14 +441,21 @@ describe('WebSocket', () => { ); ws.on('close', (code, reason) => { - assert.strictEqual(code, 1002); + clientCloseEventEmitted = true; + assert.strictEqual(code, 1006); assert.strictEqual(reason, ''); - wss.close(done); }); }); }); wss.on('connection', (ws) => { + ws.on('close', (code, reason) => { + assert.ok(clientCloseEventEmitted); + assert.strictEqual(code, 1002); + assert.strictEqual(reason, ''); + wss.close(done); + }); + ws._socket.write(Buffer.from([0x85, 0x00])); }); }); @@ -1410,10 +1418,17 @@ describe('WebSocket', () => { }); it('honors the `mask` option', (done) => { + let serverClientCloseEventEmitted = false; const wss = new WebSocket.Server({ port: 0 }, () => { const ws = new WebSocket(`ws://localhost:${wss.address().port}`); ws.on('open', () => ws.send('hi', { mask: false })); + ws.on('close', (code, reason) => { + assert.ok(serverClientCloseEventEmitted); + assert.strictEqual(code, 1002); + assert.strictEqual(reason, ''); + wss.close(done); + }); }); wss.on('connection', (ws) => { @@ -1434,9 +1449,9 @@ describe('WebSocket', () => { ); ws.on('close', (code, reason) => { - assert.strictEqual(code, 1002); + serverClientCloseEventEmitted = true; + assert.strictEqual(code, 1006); assert.strictEqual(reason, ''); - wss.close(done); }); }); });