Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ws

Package Overview
Dependencies
Maintainers
4
Versions
169
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ws - npm Package Compare versions

Comparing version 8.4.0 to 8.0.0

3

index.js

@@ -10,5 +10,2 @@ 'use strict';

WebSocket.WebSocket = WebSocket;
WebSocket.WebSocketServer = WebSocket.Server;
module.exports = WebSocket;

16

lib/permessage-deflate.js

@@ -33,14 +33,10 @@ 'use strict';

* @param {Object} [options] Configuration options
* @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
* for, or request, a custom client window size
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
* disabling of server context takeover
* @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
* acknowledge disabling of client context takeover
* @param {Number} [options.concurrencyLimit=10] The number of concurrent
* calls to zlib
* @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
* use of a custom server window size
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
* disabling of server context takeover
* @param {Number} [options.threshold=1024] Size (in bytes) below which
* messages should not be compressed if context takeover is disabled
* @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
* for, or request, a custom client window size
* @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on

@@ -50,2 +46,6 @@ * deflate

* inflate
* @param {Number} [options.threshold=1024] Size (in bytes) below which
* messages should not be compressed
* @param {Number} [options.concurrencyLimit=10] The number of concurrent
* calls to zlib
* @param {Boolean} [isServer=false] Create the instance in either server or

@@ -52,0 +52,0 @@ * client mode

@@ -31,21 +31,16 @@ 'use strict';

*
* @param {Object} [options] Options object
* @param {String} [options.binaryType=nodebuffer] The type for binary data
* @param {Object} [options.extensions] An object containing the negotiated
* extensions
* @param {Boolean} [options.isServer=false] Specifies whether to operate in
* client or server mode
* @param {Number} [options.maxPayload=0] The maximum allowed message length
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
* not to skip UTF-8 validation for text and close messages
* @param {String} [binaryType=nodebuffer] The type for binary data
* @param {Object} [extensions] An object containing the negotiated extensions
* @param {Boolean} [isServer=false] Specifies whether to operate in client or
* server mode
* @param {Number} [maxPayload=0] The maximum allowed message length
*/
constructor(options = {}) {
constructor(binaryType, extensions, isServer, maxPayload) {
super();
this._binaryType = options.binaryType || BINARY_TYPES[0];
this._extensions = options.extensions || {};
this._isServer = !!options.isServer;
this._maxPayload = options.maxPayload | 0;
this._skipUTF8Validation = !!options.skipUTF8Validation;
this._binaryType = binaryType || BINARY_TYPES[0];
this[kWebSocket] = undefined;
this._extensions = extensions || {};
this._isServer = !!isServer;
this._maxPayload = maxPayload | 0;

@@ -421,9 +416,3 @@ this._bufferedBytes = 0;

data = this.consume(this._payloadLength);
if (
this._masked &&
(this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0
) {
unmask(data, this._mask);
}
if (this._masked) unmask(data, this._mask);
}

@@ -441,3 +430,3 @@

//
// This message is not compressed so its length is the sum of the payload
// This message is not compressed so its lenght is the sum of the payload
// length of all fragments.

@@ -520,3 +509,3 @@ //

if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
if (!isValidUTF8(buf)) {
this._loop = false;

@@ -576,3 +565,3 @@ return error(

if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
if (!isValidUTF8(buf)) {
return error(

@@ -579,0 +568,0 @@ Error,

@@ -14,3 +14,3 @@ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^net|tls$" }] */

const maskBuffer = Buffer.alloc(4);
const mask = Buffer.alloc(4);

@@ -26,13 +26,5 @@ /**

* @param {Object} [extensions] An object containing the negotiated extensions
* @param {Function} [generateMask] The function used to generate the masking
* key
*/
constructor(socket, extensions, generateMask) {
constructor(socket, extensions) {
this._extensions = extensions || {};
if (generateMask) {
this._generateMask = generateMask;
this._maskBuffer = Buffer.alloc(4);
}
this._socket = socket;

@@ -53,13 +45,9 @@

* @param {Object} options Options object
* @param {Number} options.opcode The opcode
* @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
* modified
* @param {Boolean} [options.fin=false] Specifies whether or not to set the
* FIN bit
* @param {Function} [options.generateMask] The function used to generate the
* masking key
* @param {Boolean} [options.mask=false] Specifies whether or not to mask
* `data`
* @param {Buffer} [options.maskBuffer] The buffer used to store the masking
* key
* @param {Number} options.opcode The opcode
* @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
* modified
* @param {Boolean} [options.rsv1=false] Specifies whether or not to set the

@@ -71,22 +59,4 @@ * RSV1 bit

static frame(data, options) {
let mask;
let merge = false;
let offset = 2;
let skipMasking = false;
if (options.mask) {
mask = options.maskBuffer || maskBuffer;
if (options.generateMask) {
options.generateMask(mask);
} else {
randomFillSync(mask, 0, 4);
}
skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
if (options.readOnly && !skipMasking) merge = true;
offset = 6;
}
const merge = options.mask && options.readOnly;
let offset = options.mask ? 6 : 2;
let payloadLength = data.length;

@@ -112,4 +82,4 @@

} else if (payloadLength === 127) {
target[2] = target[3] = 0;
target.writeUIntBE(data.length, 4, 6);
target.writeUInt32BE(0, 2);
target.writeUInt32BE(data.length, 6);
}

@@ -119,2 +89,4 @@

randomFillSync(mask, 0, 4);
target[1] |= 0x80;

@@ -126,4 +98,2 @@ target[offset - 4] = mask[0];

if (skipMasking) return [target, data];
if (merge) {

@@ -196,4 +166,2 @@ applyMask(data, mask, target, offset, data.length);

mask,
maskBuffer: this._maskBuffer,
generateMask: this._generateMask,
readOnly: false

@@ -243,4 +211,2 @@ }),

mask,
maskBuffer: this._maskBuffer,
generateMask: this._generateMask,
readOnly

@@ -290,4 +256,2 @@ }),

mask,
maskBuffer: this._maskBuffer,
generateMask: this._generateMask,
readOnly

@@ -304,6 +268,6 @@ }),

* @param {Object} options Options object
* @param {Boolean} [options.compress=false] Specifies whether or not to
* compress `data`
* @param {Boolean} [options.binary=false] Specifies whether `data` is binary
* or text
* @param {Boolean} [options.compress=false] Specifies whether or not to
* compress `data`
* @param {Boolean} [options.fin=false] Specifies whether the fragment is the

@@ -324,11 +288,3 @@ * last one

this._firstFragment = false;
if (
rsv1 &&
perMessageDeflate &&
perMessageDeflate.params[
perMessageDeflate._isServer
? 'server_no_context_takeover'
: 'client_no_context_takeover'
]
) {
if (rsv1 && perMessageDeflate) {
rsv1 = buf.length >= perMessageDeflate._threshold;

@@ -350,4 +306,2 @@ }

mask: options.mask,
maskBuffer: this._maskBuffer,
generateMask: this._generateMask,
readOnly: toBuffer.readOnly

@@ -368,4 +322,2 @@ };

mask: options.mask,
maskBuffer: this._maskBuffer,
generateMask: this._generateMask,
readOnly: toBuffer.readOnly

@@ -386,12 +338,8 @@ }),

* @param {Number} options.opcode The opcode
* @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
* modified
* @param {Boolean} [options.fin=false] Specifies whether or not to set the
* FIN bit
* @param {Function} [options.generateMask] The function used to generate the
* masking key
* @param {Boolean} [options.mask=false] Specifies whether or not to mask
* `data`
* @param {Buffer} [options.maskBuffer] The buffer used to store the masking
* key
* @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
* modified
* @param {Boolean} [options.rsv1=false] Specifies whether or not to set the

@@ -398,0 +346,0 @@ * RSV1 bit

@@ -50,4 +50,19 @@ 'use strict';

function createWebSocketStream(ws, options) {
let resumeOnReceiverDrain = true;
let terminateOnDestroy = true;
function receiverOnDrain() {
if (resumeOnReceiverDrain) ws._socket.resume();
}
if (ws.readyState === ws.CONNECTING) {
ws.once('open', function open() {
ws._receiver.removeAllListeners('drain');
ws._receiver.on('drain', receiverOnDrain);
});
} else {
ws._receiver.removeAllListeners('drain');
ws._receiver.on('drain', receiverOnDrain);
}
const duplex = new Duplex({

@@ -65,3 +80,6 @@ ...options,

if (!duplex.push(data)) ws.pause();
if (!duplex.push(data)) {
resumeOnReceiverDrain = false;
ws._socket.pause();
}
});

@@ -142,3 +160,6 @@

duplex._read = function () {
if (ws.isPaused) ws.resume();
if (ws.readyState === ws.OPEN && !resumeOnReceiverDrain) {
resumeOnReceiverDrain = true;
if (!ws._receiver._writableState.needDrain) ws._socket.resume();
}
};

@@ -145,0 +166,0 @@

@@ -49,4 +49,2 @@ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^net|tls|https$" }] */

* server to use
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
* not to skip UTF-8 validation for text and close messages
* @param {Function} [options.verifyClient] A hook to reject connections

@@ -60,3 +58,2 @@ * @param {Function} [callback] A listener for the `listening` event

maxPayload: 100 * 1024 * 1024,
skipUTF8Validation: false,
perMessageDeflate: false,

@@ -394,6 +391,3 @@ handleProtocols: null,

ws.setSocket(socket, head, {
maxPayload: this.options.maxPayload,
skipUTF8Validation: this.options.skipUTF8Validation
});
ws.setSocket(socket, head, this.options.maxPayload);

@@ -400,0 +394,0 @@ if (this.clients) {

@@ -1,3 +0,1 @@

/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */
'use strict';

@@ -11,3 +9,2 @@

const { randomBytes, createHash } = require('crypto');
const { Readable } = require('stream');
const { URL } = require('url');

@@ -62,3 +59,2 @@

this._extensions = {};
this._paused = false;
this._protocol = '';

@@ -131,9 +127,2 @@ this._readyState = WebSocket.CONNECTING;

/**
* @type {Boolean}
*/
get isPaused() {
return this._paused;
}
/**
* @type {Function}

@@ -197,20 +186,14 @@ */

* @param {Buffer} head The first packet of the upgraded stream
* @param {Object} options Options object
* @param {Function} [options.generateMask] The function used to generate the
* masking key
* @param {Number} [options.maxPayload=0] The maximum allowed message size
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
* not to skip UTF-8 validation for text and close messages
* @param {Number} [maxPayload=0] The maximum allowed message size
* @private
*/
setSocket(socket, head, options) {
const receiver = new Receiver({
binaryType: this.binaryType,
extensions: this._extensions,
isServer: this._isServer,
maxPayload: options.maxPayload,
skipUTF8Validation: options.skipUTF8Validation
});
setSocket(socket, head, maxPayload) {
const receiver = new Receiver(
this.binaryType,
this._extensions,
this._isServer,
maxPayload
);
this._sender = new Sender(socket, this._extensions, options.generateMask);
this._sender = new Sender(socket, this._extensions);
this._receiver = receiver;

@@ -330,19 +313,2 @@ this._socket = socket;

/**
* Pause the socket.
*
* @public
*/
pause() {
if (
this.readyState === WebSocket.CONNECTING ||
this.readyState === WebSocket.CLOSED
) {
return;
}
this._paused = true;
this._socket.pause();
}
/**
* Send a ping.

@@ -412,19 +378,2 @@ *

/**
* Resume the socket.
*
* @public
*/
resume() {
if (
this.readyState === WebSocket.CONNECTING ||
this.readyState === WebSocket.CLOSED
) {
return;
}
this._paused = false;
if (!this._receiver._writableState.needDrain) this._socket.resume();
}
/**
* Send a data message.

@@ -434,6 +383,6 @@ *

* @param {Object} [options] Options object
* @param {Boolean} [options.compress] Specifies whether or not to compress
* `data`
* @param {Boolean} [options.binary] Specifies whether `data` is binary or
* text
* @param {Boolean} [options.compress] Specifies whether or not to compress
* `data`
* @param {Boolean} [options.fin=true] Specifies whether the fragment is the

@@ -572,3 +521,2 @@ * last one

'extensions',
'isPaused',
'protocol',

@@ -624,20 +572,16 @@ 'readyState',

* @param {Object} [options] Connection options
* @param {Boolean} [options.followRedirects=false] Whether or not to follow
* redirects
* @param {Function} [options.generateMask] The function used to generate the
* masking key
* @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
* permessage-deflate
* @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
* handshake request
* @param {Number} [options.protocolVersion=13] Value of the
* `Sec-WebSocket-Version` header
* @param {String} [options.origin] Value of the `Origin` or
* `Sec-WebSocket-Origin` header
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
* size
* @param {Boolean} [options.followRedirects=false] Whether or not to follow
* redirects
* @param {Number} [options.maxRedirects=10] The maximum number of redirects
* allowed
* @param {String} [options.origin] Value of the `Origin` or
* `Sec-WebSocket-Origin` header
* @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
* permessage-deflate
* @param {Number} [options.protocolVersion=13] Value of the
* `Sec-WebSocket-Version` header
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
* not to skip UTF-8 validation for text and close messages
* @private

@@ -649,3 +593,2 @@ */

maxPayload: 100 * 1024 * 1024,
skipUTF8Validation: false,
perMessageDeflate: true,

@@ -690,22 +633,15 @@ followRedirects: false,

const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
let invalidURLMessage;
if (parsedUrl.protocol !== 'ws:' && !isSecure && !isUnixSocket) {
invalidURLMessage =
'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"';
} else if (isUnixSocket && !parsedUrl.pathname) {
invalidURLMessage = "The URL's pathname is empty";
} else if (parsedUrl.hash) {
invalidURLMessage = 'The URL contains a fragment identifier';
throw new SyntaxError(
'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"'
);
}
if (invalidURLMessage) {
const err = new SyntaxError(invalidURLMessage);
if (isUnixSocket && !parsedUrl.pathname) {
throw new SyntaxError("The URL's pathname is empty");
}
if (websocket._redirects === 0) {
throw err;
} else {
emitErrorAndClose(websocket, err);
return;
}
if (parsedUrl.hash) {
throw new SyntaxError('The URL contains a fragment identifier');
}

@@ -792,3 +728,5 @@

req = websocket._req = null;
emitErrorAndClose(websocket, err);
websocket._readyState = WebSocket.CLOSING;
websocket.emit('error', err);
websocket.emitClose();
});

@@ -813,12 +751,4 @@

let addr;
const addr = new URL(location, address);
try {
addr = new URL(location, address);
} catch (e) {
const err = new SyntaxError(`Invalid URL: ${location}`);
emitErrorAndClose(websocket, err);
return;
}
initAsClient(websocket, addr, protocols, options);

@@ -857,3 +787,3 @@ } else if (!websocket.emit('unexpected-response', req, res)) {

if (serverProt !== undefined) {
if (serverProt) {
if (!protocolSet.size) {

@@ -919,7 +849,3 @@ protError = 'Server sent a subprotocol but none was requested';

websocket.setSocket(socket, head, {
generateMask: opts.generateMask,
maxPayload: opts.maxPayload,
skipUTF8Validation: opts.skipUTF8Validation
});
websocket.setSocket(socket, head, opts.maxPayload);
});

@@ -929,15 +855,2 @@ }

/**
* Emit the `'error'` and `'close'` event.
*
* @param {WebSocket} websocket The WebSocket instance
* @param {Error} The error to emit
* @private
*/
function emitErrorAndClose(websocket, err) {
websocket._readyState = WebSocket.CLOSING;
websocket.emit('error', err);
websocket.emitClose();
}
/**
* Create a `net.Socket` and initiate a connection.

@@ -1049,2 +962,5 @@ *

websocket._socket.removeListener('data', socketOnData);
websocket._socket.resume();
websocket._closeFrameReceived = true;

@@ -1054,7 +970,2 @@ websocket._closeMessage = reason;

if (websocket._socket[kWebSocket] === undefined) return;
websocket._socket.removeListener('data', socketOnData);
process.nextTick(resume, websocket._socket);
if (code === 1005) websocket.close();

@@ -1070,5 +981,3 @@ else websocket.close(code, reason);

function receiverOnDrain() {
const websocket = this[kWebSocket];
if (!websocket.isPaused) websocket._socket.resume();
this[kWebSocket]._socket.resume();
}

@@ -1085,14 +994,6 @@

if (websocket._socket[kWebSocket] !== undefined) {
websocket._socket.removeListener('data', socketOnData);
websocket._socket.removeListener('data', socketOnData);
websocket._socket.resume();
//
// On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
// https://github.com/websockets/ws/issues/1940.
//
process.nextTick(resume, websocket._socket);
websocket.close(err[kStatusCode]);
}
websocket.close(err[kStatusCode]);
websocket.emit('error', err);

@@ -1145,12 +1046,2 @@ }

/**
* Resume a readable stream
*
* @param {Readable} stream The readable stream
* @private
*/
function resume(stream) {
stream.resume();
}
/**
* The listener of the `net.Socket` `'close'` event.

@@ -1164,3 +1055,2 @@ *

this.removeListener('close', socketOnClose);
this.removeListener('data', socketOnData);
this.removeListener('end', socketOnEnd);

@@ -1170,4 +1060,2 @@

let chunk;
//

@@ -1180,15 +1068,9 @@ // The close frame might not have been received or the `'end'` event emitted,

// will return `null`. If instead, the socket is paused, any possible buffered
// data will be read as a single chunk.
// data will be read as a single chunk and emitted synchronously in a single
// `'data'` event.
//
if (
!this._readableState.endEmitted &&
!websocket._closeFrameReceived &&
!websocket._receiver._writableState.errorEmitted &&
(chunk = websocket._socket.read()) !== null
) {
websocket._receiver.write(chunk);
}
websocket._socket.read();
websocket._receiver.end();
this.removeListener('data', socketOnData);
this[kWebSocket] = undefined;

@@ -1195,0 +1077,0 @@

{
"name": "ws",
"version": "8.4.0",
"version": "8.0.0",
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",

@@ -53,5 +53,5 @@ "keywords": [

"bufferutil": "^4.0.1",
"eslint": "^8.0.0",
"eslint": "^7.2.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-prettier": "^3.0.1",
"mocha": "^8.4.0",

@@ -58,0 +58,0 @@ "nyc": "^15.0.0",

# ws: a Node.js WebSocket library
[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws)
[![CI](https://img.shields.io/github/workflow/status/websockets/ws/CI/master?label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster)
[![Build](https://img.shields.io/github/workflow/status/websockets/ws/CI/master?label=build&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster)
[![Windows x86 Build](https://img.shields.io/appveyor/ci/lpinca/ws/master.svg?logo=appveyor)](https://ci.appveyor.com/project/lpinca/ws)
[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws)

@@ -121,3 +122,3 @@

threshold: 1024 // Size (in bytes) below which messages
// should not be compressed if context takeover is disabled.
// should not be compressed.
}

@@ -152,4 +153,4 @@ });

ws.on('message', function message(data) {
console.log('received: %s', data);
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});

@@ -184,4 +185,4 @@ ```

wss.on('connection', function connection(ws) {
ws.on('message', function message(data) {
console.log('received: %s', data);
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});

@@ -207,4 +208,4 @@

wss.on('connection', function connection(ws) {
ws.on('message', function message(data) {
console.log('received: %s', data);
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});

@@ -266,4 +267,4 @@

wss.on('connection', function connection(ws, request, client) {
ws.on('message', function message(data) {
console.log(`Received message ${data} from user ${client}`);
ws.on('message', function message(msg) {
console.log(`Received message ${msg} from user ${client}`);
});

@@ -274,3 +275,3 @@ });

// This function is not defined on purpose. Implement it with your own logic.
authenticate(request, function next(err, client) {
authenticate(request, (err, client) => {
if (err || !client) {

@@ -304,3 +305,3 @@ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');

wss.on('connection', function connection(ws) {
ws.on('message', function message(data, isBinary) {
ws.on('message', function incoming(data, isBinary) {
wss.clients.forEach(function each(client) {

@@ -324,3 +325,3 @@ if (client.readyState === WebSocket.OPEN) {

wss.on('connection', function connection(ws) {
ws.on('message', function message(data, isBinary) {
ws.on('message', function incoming(data, isBinary) {
wss.clients.forEach(function each(client) {

@@ -353,3 +354,3 @@ if (client !== ws && client.readyState === WebSocket.OPEN) {

ws.on('message', function message(data) {
ws.on('message', function incoming(data) {
console.log(`Roundtrip time: ${Date.now() - data} ms`);

@@ -422,2 +423,4 @@

function noop() {}
function heartbeat() {

@@ -439,3 +442,3 @@ this.isAlive = true;

ws.isAlive = false;
ws.ping();
ws.ping(noop);
});

@@ -442,0 +445,0 @@ }, 30000);

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc