Skip to content

Commit 01ba54e

Browse files
committedDec 26, 2023
[feature] Introduce the autoPong option
Add the ability to disable the automatic sending of pong responses to pings. Fixes #2186
1 parent 527ec97 commit 01ba54e

File tree

5 files changed

+86
-2
lines changed

5 files changed

+86
-2
lines changed
 

‎doc/ws.md

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ This class represents a WebSocket server. It extends the `EventEmitter`.
7272
### new WebSocketServer(options[, callback])
7373

7474
- `options` {Object}
75+
- `autoPong` {Boolean} Specifies whether or not to automatically send a pong
76+
in response to a ping. Defaults to `true`.
7577
- `allowSynchronousEvents` {Boolean} Specifies whether any of the `'message'`,
7678
`'ping'`, and `'pong'` events can be emitted multiple times in the same
7779
tick. To improve compatibility with the WHATWG standard, the default value
@@ -296,6 +298,8 @@ This class represents a WebSocket. It extends the `EventEmitter`.
296298
- `address` {String|url.URL} The URL to which to connect.
297299
- `protocols` {String|Array} The list of subprotocols.
298300
- `options` {Object}
301+
- `autoPong` {Boolean} Specifies whether or not to automatically send a pong
302+
in response to a ping. Defaults to `true`.
299303
- `allowSynchronousEvents` {Boolean} Specifies whether any of the `'message'`,
300304
`'ping'`, and `'pong'` events can be emitted multiple times in the same
301305
tick. To improve compatibility with the WHATWG standard, the default value

‎lib/websocket-server.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class WebSocketServer extends EventEmitter {
3232
* @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
3333
* any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
3434
* multiple times in the same tick
35+
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
36+
* automatically send a pong in response to a ping
3537
* @param {Number} [options.backlog=511] The maximum length of the queue of
3638
* pending connections
3739
* @param {Boolean} [options.clientTracking=true] Specifies whether or not to
@@ -59,6 +61,7 @@ class WebSocketServer extends EventEmitter {
5961

6062
options = {
6163
allowSynchronousEvents: false,
64+
autoPong: true,
6265
maxPayload: 100 * 1024 * 1024,
6366
skipUTF8Validation: false,
6467
perMessageDeflate: false,
@@ -379,7 +382,7 @@ class WebSocketServer extends EventEmitter {
379382
`Sec-WebSocket-Accept: ${digest}`
380383
];
381384

382-
const ws = new this.options.WebSocket(null);
385+
const ws = new this.options.WebSocket(null, undefined, this.options);
383386

384387
if (protocols.size) {
385388
//

‎lib/websocket.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class WebSocket extends EventEmitter {
8484

8585
initAsClient(this, address, protocols, options);
8686
} else {
87+
this._autoPong = options.autoPong;
8788
this._isServer = true;
8889
}
8990
}
@@ -625,6 +626,8 @@ module.exports = WebSocket;
625626
* @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether any
626627
* of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
627628
* times in the same tick
629+
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
630+
* automatically send a pong in response to a ping
628631
* @param {Function} [options.finishRequest] A function which can be used to
629632
* customize the headers of each http request before it is sent
630633
* @param {Boolean} [options.followRedirects=false] Whether or not to follow
@@ -650,6 +653,7 @@ module.exports = WebSocket;
650653
function initAsClient(websocket, address, protocols, options) {
651654
const opts = {
652655
allowSynchronousEvents: false,
656+
autoPong: true,
653657
protocolVersion: protocolVersions[1],
654658
maxPayload: 100 * 1024 * 1024,
655659
skipUTF8Validation: false,
@@ -668,6 +672,8 @@ function initAsClient(websocket, address, protocols, options) {
668672
port: undefined
669673
};
670674

675+
websocket._autoPong = opts.autoPong;
676+
671677
if (!protocolVersions.includes(opts.protocolVersion)) {
672678
throw new RangeError(
673679
`Unsupported protocol version: ${opts.protocolVersion} ` +
@@ -1212,7 +1218,7 @@ function receiverOnMessage(data, isBinary) {
12121218
function receiverOnPing(data) {
12131219
const websocket = this[kWebSocket];
12141220

1215-
websocket.pong(data, !websocket._isServer, NOOP);
1221+
if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
12161222
websocket.emit('ping', data);
12171223
}
12181224

‎test/websocket-server.test.js

+24
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,30 @@ describe('WebSocketServer', () => {
116116
wss.close(done);
117117
});
118118
});
119+
120+
it('honors the `autoPong` option', (done) => {
121+
const wss = new WebSocket.Server({ autoPong: false, port: 0 }, () => {
122+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);
123+
124+
ws.on('open', () => {
125+
ws.ping();
126+
});
127+
128+
ws.on('pong', () => {
129+
done(new Error("Unexpected 'pong' event"));
130+
});
131+
});
132+
133+
wss.on('connection', (ws) => {
134+
ws.on('ping', () => {
135+
ws.close();
136+
});
137+
138+
ws.on('close', () => {
139+
wss.close(done);
140+
});
141+
});
142+
});
119143
});
120144

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

‎test/websocket.test.js

+47
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,30 @@ describe('WebSocket', () => {
197197
});
198198
});
199199
});
200+
201+
it('honors the `autoPong` option', (done) => {
202+
const wss = new WebSocket.Server({ port: 0 }, () => {
203+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`, {
204+
autoPong: false
205+
});
206+
207+
ws.on('ping', () => {
208+
ws.close();
209+
});
210+
211+
ws.on('close', () => {
212+
wss.close(done);
213+
});
214+
});
215+
216+
wss.on('connection', (ws) => {
217+
ws.on('pong', () => {
218+
done(new Error("Unexpected 'pong' event"));
219+
});
220+
221+
ws.ping();
222+
});
223+
});
200224
});
201225
});
202226

@@ -2325,6 +2349,29 @@ describe('WebSocket', () => {
23252349
ws.close();
23262350
});
23272351
});
2352+
2353+
it('is called automatically when a ping is received', (done) => {
2354+
const buf = Buffer.from('hi');
2355+
const wss = new WebSocket.Server({ port: 0 }, () => {
2356+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);
2357+
2358+
ws.on('open', () => {
2359+
ws.ping(buf);
2360+
});
2361+
2362+
ws.on('pong', (data) => {
2363+
assert.deepStrictEqual(data, buf);
2364+
wss.close(done);
2365+
});
2366+
});
2367+
2368+
wss.on('connection', (ws) => {
2369+
ws.on('ping', (data) => {
2370+
assert.deepStrictEqual(data, buf);
2371+
ws.close();
2372+
});
2373+
});
2374+
});
23282375
});
23292376

23302377
describe('#resume', () => {

0 commit comments

Comments
 (0)
Please sign in to comment.