Skip to content

Commit

Permalink
[feature] Introduce the autoPong option
Browse files Browse the repository at this point in the history
Add the ability to disable the automatic sending of pong responses to
pings.

Fixes #2186
  • Loading branch information
lpinca committed Dec 26, 2023
1 parent 527ec97 commit 01ba54e
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 2 deletions.
4 changes: 4 additions & 0 deletions doc/ws.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ This class represents a WebSocket server. It extends the `EventEmitter`.
### new WebSocketServer(options[, callback])

- `options` {Object}
- `autoPong` {Boolean} Specifies whether or not to automatically send a pong
in response to a ping. Defaults to `true`.
- `allowSynchronousEvents` {Boolean} Specifies whether any of the `'message'`,
`'ping'`, and `'pong'` events can be emitted multiple times in the same
tick. To improve compatibility with the WHATWG standard, the default value
Expand Down Expand Up @@ -296,6 +298,8 @@ This class represents a WebSocket. It extends the `EventEmitter`.
- `address` {String|url.URL} The URL to which to connect.
- `protocols` {String|Array} The list of subprotocols.
- `options` {Object}
- `autoPong` {Boolean} Specifies whether or not to automatically send a pong
in response to a ping. Defaults to `true`.
- `allowSynchronousEvents` {Boolean} Specifies whether any of the `'message'`,
`'ping'`, and `'pong'` events can be emitted multiple times in the same
tick. To improve compatibility with the WHATWG standard, the default value
Expand Down
5 changes: 4 additions & 1 deletion lib/websocket-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class WebSocketServer extends EventEmitter {
* @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
* any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
* multiple times in the same tick
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
* automatically send a pong in response to a ping
* @param {Number} [options.backlog=511] The maximum length of the queue of
* pending connections
* @param {Boolean} [options.clientTracking=true] Specifies whether or not to
Expand Down Expand Up @@ -59,6 +61,7 @@ class WebSocketServer extends EventEmitter {

options = {
allowSynchronousEvents: false,
autoPong: true,
maxPayload: 100 * 1024 * 1024,
skipUTF8Validation: false,
perMessageDeflate: false,
Expand Down Expand Up @@ -379,7 +382,7 @@ class WebSocketServer extends EventEmitter {
`Sec-WebSocket-Accept: ${digest}`
];

const ws = new this.options.WebSocket(null);
const ws = new this.options.WebSocket(null, undefined, this.options);

if (protocols.size) {
//
Expand Down
8 changes: 7 additions & 1 deletion lib/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class WebSocket extends EventEmitter {

initAsClient(this, address, protocols, options);
} else {
this._autoPong = options.autoPong;
this._isServer = true;
}
}
Expand Down Expand Up @@ -625,6 +626,8 @@ module.exports = WebSocket;
* @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether any
* of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
* times in the same tick
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
* automatically send a pong in response to a ping
* @param {Function} [options.finishRequest] A function which can be used to
* customize the headers of each http request before it is sent
* @param {Boolean} [options.followRedirects=false] Whether or not to follow
Expand All @@ -650,6 +653,7 @@ module.exports = WebSocket;
function initAsClient(websocket, address, protocols, options) {
const opts = {
allowSynchronousEvents: false,
autoPong: true,
protocolVersion: protocolVersions[1],
maxPayload: 100 * 1024 * 1024,
skipUTF8Validation: false,
Expand All @@ -668,6 +672,8 @@ function initAsClient(websocket, address, protocols, options) {
port: undefined
};

websocket._autoPong = opts.autoPong;

if (!protocolVersions.includes(opts.protocolVersion)) {
throw new RangeError(
`Unsupported protocol version: ${opts.protocolVersion} ` +
Expand Down Expand Up @@ -1212,7 +1218,7 @@ function receiverOnMessage(data, isBinary) {
function receiverOnPing(data) {
const websocket = this[kWebSocket];

websocket.pong(data, !websocket._isServer, NOOP);
if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
websocket.emit('ping', data);
}

Expand Down
24 changes: 24 additions & 0 deletions test/websocket-server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,30 @@ describe('WebSocketServer', () => {
wss.close(done);
});
});

it('honors the `autoPong` option', (done) => {
const wss = new WebSocket.Server({ autoPong: false, port: 0 }, () => {
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);

ws.on('open', () => {
ws.ping();
});

ws.on('pong', () => {
done(new Error("Unexpected 'pong' event"));
});
});

wss.on('connection', (ws) => {
ws.on('ping', () => {
ws.close();
});

ws.on('close', () => {
wss.close(done);
});
});
});
});

it('emits an error if http server bind fails', (done) => {
Expand Down
47 changes: 47 additions & 0 deletions test/websocket.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,30 @@ describe('WebSocket', () => {
});
});
});

it('honors the `autoPong` option', (done) => {
const wss = new WebSocket.Server({ port: 0 }, () => {
const ws = new WebSocket(`ws://localhost:${wss.address().port}`, {
autoPong: false
});

ws.on('ping', () => {
ws.close();
});

ws.on('close', () => {
wss.close(done);
});
});

wss.on('connection', (ws) => {
ws.on('pong', () => {
done(new Error("Unexpected 'pong' event"));
});

ws.ping();
});
});
});
});

Expand Down Expand Up @@ -2325,6 +2349,29 @@ describe('WebSocket', () => {
ws.close();
});
});

it('is called automatically when a ping is received', (done) => {
const buf = Buffer.from('hi');
const wss = new WebSocket.Server({ port: 0 }, () => {
const ws = new WebSocket(`ws://localhost:${wss.address().port}`);

ws.on('open', () => {
ws.ping(buf);
});

ws.on('pong', (data) => {
assert.deepStrictEqual(data, buf);
wss.close(done);
});
});

wss.on('connection', (ws) => {
ws.on('ping', (data) => {
assert.deepStrictEqual(data, buf);
ws.close();
});
});
});
});

describe('#resume', () => {
Expand Down

0 comments on commit 01ba54e

Please sign in to comment.