Skip to content

Commit 2799793

Browse files
committedAug 28, 2021
[fix] Resume the socket in the next tick
Ensure that `socket.resume()` is called after `socket.pause()`. Fixes #1940
1 parent 76087fb commit 2799793

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed
 

‎lib/websocket.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */
2+
13
'use strict';
24

35
const EventEmitter = require('events');
@@ -6,6 +8,7 @@ const http = require('http');
68
const net = require('net');
79
const tls = require('tls');
810
const { randomBytes, createHash } = require('crypto');
11+
const { Readable } = require('stream');
912
const { URL } = require('url');
1013

1114
const PerMessageDeflate = require('./permessage-deflate');
@@ -916,7 +919,7 @@ function receiverOnConclude(code, reason) {
916919
const websocket = this[kWebSocket];
917920

918921
websocket._socket.removeListener('data', socketOnData);
919-
websocket._socket.resume();
922+
process.nextTick(resume, websocket._socket);
920923

921924
websocket._closeFrameReceived = true;
922925
websocket._closeMessage = reason;
@@ -945,7 +948,12 @@ function receiverOnError(err) {
945948
const websocket = this[kWebSocket];
946949

947950
websocket._socket.removeListener('data', socketOnData);
948-
websocket._socket.resume();
951+
952+
//
953+
// On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
954+
// https://github.com/websockets/ws/issues/1940.
955+
//
956+
process.nextTick(resume, websocket._socket);
949957

950958
websocket.close(err[kStatusCode]);
951959
websocket.emit('error', err);
@@ -993,6 +1001,16 @@ function receiverOnPong(data) {
9931001
this[kWebSocket].emit('pong', data);
9941002
}
9951003

1004+
/**
1005+
* Resume a readable stream
1006+
*
1007+
* @param {Readable} stream The readable stream
1008+
* @private
1009+
*/
1010+
function resume(stream) {
1011+
stream.resume();
1012+
}
1013+
9961014
/**
9971015
* The listener of the `net.Socket` `'close'` event.
9981016
*

‎test/websocket.test.js

+56-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const { URL } = require('url');
1212

1313
const Sender = require('../lib/sender');
1414
const WebSocket = require('..');
15-
const { GUID, NOOP } = require('../lib/constants');
15+
const { EMPTY_BUFFER, GUID, NOOP } = require('../lib/constants');
1616

1717
class CustomAgent extends http.Agent {
1818
addRequest() {}
@@ -3053,7 +3053,7 @@ describe('WebSocket', () => {
30533053
});
30543054
});
30553055

3056-
describe('Connection close edge cases', () => {
3056+
describe('Connection close', () => {
30573057
it('closes cleanly after simultaneous errors (1/2)', (done) => {
30583058
let clientCloseEventEmitted = false;
30593059
let serverClientCloseEventEmitted = false;
@@ -3165,5 +3165,59 @@ describe('WebSocket', () => {
31653165
});
31663166
});
31673167
});
3168+
3169+
it('resumes the socket when an error occurs', (done) => {
3170+
const maxPayload = 16 * 1024;
3171+
const wss = new WebSocket.Server({ maxPayload, port: 0 }, () => {
3172+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);
3173+
});
3174+
3175+
wss.on('connection', (ws) => {
3176+
const list = [
3177+
...Sender.frame(Buffer.alloc(maxPayload + 1), {
3178+
fin: true,
3179+
opcode: 0x02,
3180+
mask: true,
3181+
readOnly: false
3182+
})
3183+
];
3184+
3185+
ws.on('error', (err) => {
3186+
assert.ok(err instanceof RangeError);
3187+
assert.strictEqual(err.code, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH');
3188+
assert.strictEqual(err.message, 'Max payload size exceeded');
3189+
3190+
ws.on('close', (code, reason) => {
3191+
assert.strictEqual(code, 1006);
3192+
assert.strictEqual(reason, '');
3193+
wss.close(done);
3194+
});
3195+
});
3196+
3197+
ws._socket.push(Buffer.concat(list));
3198+
});
3199+
});
3200+
3201+
it('resumes the socket when the close frame is received', (done) => {
3202+
const wss = new WebSocket.Server({ port: 0 }, () => {
3203+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);
3204+
});
3205+
3206+
wss.on('connection', (ws) => {
3207+
const opts = { fin: true, mask: true, readOnly: false };
3208+
const list = [
3209+
...Sender.frame(Buffer.alloc(16 * 1024), { opcode: 0x02, ...opts }),
3210+
...Sender.frame(EMPTY_BUFFER, { opcode: 0x08, ...opts })
3211+
];
3212+
3213+
ws.on('close', (code, reason) => {
3214+
assert.strictEqual(code, 1005);
3215+
assert.strictEqual(reason, '');
3216+
wss.close(done);
3217+
});
3218+
3219+
ws._socket.push(Buffer.concat(list));
3220+
});
3221+
});
31683222
});
31693223
});

0 commit comments

Comments
 (0)
Please sign in to comment.