Skip to content

Commit bb60b5b

Browse files
committed
Make the option work on the server, add JSDoc, and simplify tests
1 parent 851f1fc commit bb60b5b

File tree

6 files changed

+49
-40
lines changed

6 files changed

+49
-40
lines changed

doc/ws.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ This class represents a WebSocket server. It extends the `EventEmitter`.
8080
in response to a ping. Defaults to `true`.
8181
- `backlog` {Number} The maximum length of the queue of pending connections.
8282
- `clientTracking` {Boolean} Specifies whether or not to track clients.
83-
- `closeTimeout` {Number} Timeout in milliseconds for graceful close.
83+
- `closeTimeout` {Number} Timeout in milliseconds for graceful close. Defaults
84+
to 30000.
8485
- `handleProtocols` {Function} A function which can be used to handle the
8586
WebSocket subprotocols. See description below.
8687
- `host` {String} The hostname where to bind the server.
@@ -305,7 +306,8 @@ This class represents a WebSocket. It extends the `EventEmitter`.
305306
the WHATWG standardbut may negatively impact performance.
306307
- `autoPong` {Boolean} Specifies whether or not to automatically send a pong
307308
in response to a ping. Defaults to `true`.
308-
- `closeTimeout` {Number} Timeout in milliseconds for graceful close.
309+
- `closeTimeout` {Number} Timeout in milliseconds for graceful close. Defaults
310+
to 30000.
309311
- `finishRequest` {Function} A function which can be used to customize the
310312
headers of each HTTP request before it is sent. See description below.
311313
- `followRedirects` {Boolean} Whether or not to follow redirects. Defaults to

lib/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ if (hasBlob) BINARY_TYPES.push('blob');
77

88
module.exports = {
99
BINARY_TYPES,
10+
CLOSE_TIMEOUT: 30000,
1011
EMPTY_BUFFER: Buffer.alloc(0),
1112
GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
1213
hasBlob,

lib/websocket-server.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const extension = require('./extension');
1111
const PerMessageDeflate = require('./permessage-deflate');
1212
const subprotocol = require('./subprotocol');
1313
const WebSocket = require('./websocket');
14-
const { GUID, kWebSocket } = require('./constants');
14+
const { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');
1515

1616
const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
1717

@@ -38,6 +38,8 @@ class WebSocketServer extends EventEmitter {
3838
* pending connections
3939
* @param {Boolean} [options.clientTracking=true] Specifies whether or not to
4040
* track clients
41+
* @param {Number} [options.closeTimeout=30000] Timeout in milliseconds for
42+
* graceful close
4143
* @param {Function} [options.handleProtocols] A hook to handle protocols
4244
* @param {String} [options.host] The hostname where to bind the server
4345
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
@@ -67,6 +69,7 @@ class WebSocketServer extends EventEmitter {
6769
perMessageDeflate: false,
6870
handleProtocols: null,
6971
clientTracking: true,
72+
closeTimeout: CLOSE_TIMEOUT,
7073
verifyClient: null,
7174
noServer: false,
7275
backlog: null, // use default (511 as implemented in net.js)

lib/websocket.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const { isBlob } = require('./validation');
1818

1919
const {
2020
BINARY_TYPES,
21+
CLOSE_TIMEOUT,
2122
EMPTY_BUFFER,
2223
GUID,
2324
kForOnEventAttribute,
@@ -32,7 +33,6 @@ const {
3233
const { format, parse } = require('./extension');
3334
const { toBuffer } = require('./buffer-util');
3435

35-
const closeTimeout = 30 * 1000;
3636
const kAborted = Symbol('kAborted');
3737
const protocolVersions = [8, 13];
3838
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
@@ -88,6 +88,7 @@ class WebSocket extends EventEmitter {
8888
initAsClient(this, address, protocols, options);
8989
} else {
9090
this._autoPong = options.autoPong;
91+
this._closeTimeout = options.closeTimeout;
9192
this._isServer = true;
9293
}
9394
}
@@ -629,6 +630,8 @@ module.exports = WebSocket;
629630
* times in the same tick
630631
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
631632
* automatically send a pong in response to a ping
633+
* @param {Number} [options.closeTimeout=30000] Timeout in milliseconds for
634+
* graceful close
632635
* @param {Function} [options.finishRequest] A function which can be used to
633636
* customize the headers of each http request before it is sent
634637
* @param {Boolean} [options.followRedirects=false] Whether or not to follow
@@ -655,6 +658,7 @@ function initAsClient(websocket, address, protocols, options) {
655658
const opts = {
656659
allowSynchronousEvents: true,
657660
autoPong: true,
661+
closeTimeout: CLOSE_TIMEOUT,
658662
protocolVersion: protocolVersions[1],
659663
maxPayload: 100 * 1024 * 1024,
660664
skipUTF8Validation: false,
@@ -1291,7 +1295,7 @@ function senderOnError(err) {
12911295
function setCloseTimer(websocket) {
12921296
websocket._closeTimer = setTimeout(
12931297
websocket._socket.destroy.bind(websocket._socket),
1294-
websocket._closeTimeout || closeTimeout
1298+
websocket._closeTimeout
12951299
);
12961300
}
12971301

test/websocket-server.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,22 @@ describe('WebSocketServer', () => {
140140
});
141141
});
142142
});
143+
144+
it('honors the `closeTimeout` option', (done) => {
145+
const closeTimeout = 1000;
146+
const wss = new WebSocket.Server({ closeTimeout, port: 0 }, () => {
147+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);
148+
});
149+
150+
wss.on('connection', (ws) => {
151+
ws.on('close', () => {
152+
wss.close(done);
153+
});
154+
155+
ws.close();
156+
assert.strictEqual(ws._closeTimer._idleTimeout, closeTimeout);
157+
});
158+
});
143159
});
144160

145161
it('emits an error if http server bind fails', (done) => {

test/websocket.test.js

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,24 @@ describe('WebSocket', () => {
232232
ws.ping();
233233
});
234234
});
235+
236+
it('honors the `closeTimeout` option', (done) => {
237+
const wss = new WebSocket.Server({ port: 0 }, () => {
238+
const closeTimeout = 1000;
239+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`, {
240+
closeTimeout
241+
});
242+
243+
ws.on('open', () => {
244+
ws.close();
245+
assert.strictEqual(ws._closeTimer._idleTimeout, closeTimeout);
246+
});
247+
248+
ws.on('close', () => {
249+
wss.close(done);
250+
});
251+
});
252+
});
235253
});
236254
});
237255

@@ -3454,41 +3472,6 @@ describe('WebSocket', () => {
34543472
});
34553473
});
34563474
});
3457-
3458-
it('uses closeTimeout milliseconds for the close timer', (done) => {
3459-
const timeoutMs = 5 * 1000;
3460-
3461-
const wss = new WebSocket.Server({ port: 0, closeTimeout: timeoutMs}, () => {
3462-
const ws = new WebSocket(`ws://localhost:${wss.address().port}`, undefined, {closeTimeout: timeoutMs});
3463-
3464-
assert.strictEqual(ws._closeTimeout, timeoutMs);
3465-
3466-
ws.on('close', (code, reason) => {
3467-
assert.strictEqual(code, 1000);
3468-
assert.deepStrictEqual(reason, Buffer.from('some reason'));
3469-
wss.close(done);
3470-
});
3471-
3472-
ws.on('open', () => {
3473-
let callbackCalled = false;
3474-
3475-
assert.strictEqual(ws._closeTimer, null);
3476-
3477-
ws.send('foo', () => {
3478-
callbackCalled = true;
3479-
});
3480-
3481-
ws.close(1000, 'some reason');
3482-
3483-
//
3484-
// Check that the close timer is set even if the `Sender.close()`
3485-
// callback is not called.
3486-
//
3487-
assert.strictEqual(callbackCalled, false);
3488-
assert.strictEqual(ws._closeTimer._idleTimeout, timeoutMs);
3489-
});
3490-
});
3491-
});
34923475
});
34933476

34943477
describe('#terminate', () => {

0 commit comments

Comments
 (0)