update node modules
This commit is contained in:
33
node_modules/ws/lib/buffer-util.js
generated
vendored
33
node_modules/ws/lib/buffer-util.js
generated
vendored
@@ -15,14 +15,16 @@ function concat(list, totalLength) {
|
||||
if (list.length === 1) return list[0];
|
||||
|
||||
const target = Buffer.allocUnsafe(totalLength);
|
||||
var offset = 0;
|
||||
let offset = 0;
|
||||
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const buf = list[i];
|
||||
buf.copy(target, offset);
|
||||
target.set(buf, offset);
|
||||
offset += buf.length;
|
||||
}
|
||||
|
||||
if (offset < totalLength) return target.slice(0, offset);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -37,7 +39,7 @@ function concat(list, totalLength) {
|
||||
* @public
|
||||
*/
|
||||
function _mask(source, mask, output, offset, length) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
for (let i = 0; i < length; i++) {
|
||||
output[offset + i] = source[i] ^ mask[i & 3];
|
||||
}
|
||||
}
|
||||
@@ -52,7 +54,7 @@ function _mask(source, mask, output, offset, length) {
|
||||
function _unmask(buffer, mask) {
|
||||
// Required until https://github.com/nodejs/node/issues/9006 is resolved.
|
||||
const length = buffer.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
for (let i = 0; i < length; i++) {
|
||||
buffer[i] ^= mask[i & 3];
|
||||
}
|
||||
}
|
||||
@@ -85,12 +87,12 @@ function toBuffer(data) {
|
||||
|
||||
if (Buffer.isBuffer(data)) return data;
|
||||
|
||||
var buf;
|
||||
let buf;
|
||||
|
||||
if (data instanceof ArrayBuffer) {
|
||||
buf = Buffer.from(data);
|
||||
} else if (ArrayBuffer.isView(data)) {
|
||||
buf = viewToBuffer(data);
|
||||
buf = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
||||
} else {
|
||||
buf = Buffer.from(data);
|
||||
toBuffer.readOnly = false;
|
||||
@@ -99,23 +101,6 @@ function toBuffer(data) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an `ArrayBuffer` view into a buffer.
|
||||
*
|
||||
* @param {(DataView|TypedArray)} view The view to convert
|
||||
* @return {Buffer} Converted view
|
||||
* @private
|
||||
*/
|
||||
function viewToBuffer(view) {
|
||||
const buf = Buffer.from(view.buffer);
|
||||
|
||||
if (view.byteLength !== view.buffer.byteLength) {
|
||||
return buf.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
try {
|
||||
const bufferUtil = require('bufferutil');
|
||||
const bu = bufferUtil.BufferUtil || bufferUtil;
|
||||
|
39
node_modules/ws/lib/event-target.js
generated
vendored
39
node_modules/ws/lib/event-target.js
generated
vendored
@@ -109,11 +109,16 @@ const EventTarget = {
|
||||
/**
|
||||
* Register an event listener.
|
||||
*
|
||||
* @param {String} method A string representing the event type to listen for
|
||||
* @param {String} type A string representing the event type to listen for
|
||||
* @param {Function} listener The listener to add
|
||||
* @param {Object} options An options object specifies characteristics about
|
||||
* the event listener
|
||||
* @param {Boolean} options.once A `Boolean`` indicating that the listener
|
||||
* should be invoked at most once after being added. If `true`, the
|
||||
* listener would be automatically removed when invoked.
|
||||
* @public
|
||||
*/
|
||||
addEventListener(method, listener) {
|
||||
addEventListener(type, listener, options) {
|
||||
if (typeof listener !== 'function') return;
|
||||
|
||||
function onMessage(data) {
|
||||
@@ -132,36 +137,38 @@ const EventTarget = {
|
||||
listener.call(this, new OpenEvent(this));
|
||||
}
|
||||
|
||||
if (method === 'message') {
|
||||
const method = options && options.once ? 'once' : 'on';
|
||||
|
||||
if (type === 'message') {
|
||||
onMessage._listener = listener;
|
||||
this.on(method, onMessage);
|
||||
} else if (method === 'close') {
|
||||
this[method](type, onMessage);
|
||||
} else if (type === 'close') {
|
||||
onClose._listener = listener;
|
||||
this.on(method, onClose);
|
||||
} else if (method === 'error') {
|
||||
this[method](type, onClose);
|
||||
} else if (type === 'error') {
|
||||
onError._listener = listener;
|
||||
this.on(method, onError);
|
||||
} else if (method === 'open') {
|
||||
this[method](type, onError);
|
||||
} else if (type === 'open') {
|
||||
onOpen._listener = listener;
|
||||
this.on(method, onOpen);
|
||||
this[method](type, onOpen);
|
||||
} else {
|
||||
this.on(method, listener);
|
||||
this[method](type, listener);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an event listener.
|
||||
*
|
||||
* @param {String} method A string representing the event type to remove
|
||||
* @param {String} type A string representing the event type to remove
|
||||
* @param {Function} listener The listener to remove
|
||||
* @public
|
||||
*/
|
||||
removeEventListener(method, listener) {
|
||||
const listeners = this.listeners(method);
|
||||
removeEventListener(type, listener) {
|
||||
const listeners = this.listeners(type);
|
||||
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i] === listener || listeners[i]._listener === listener) {
|
||||
this.removeListener(method, listeners[i]);
|
||||
this.removeListener(type, listeners[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
node_modules/ws/lib/extension.js
generated
vendored
39
node_modules/ws/lib/extension.js
generated
vendored
@@ -34,8 +34,8 @@ const tokenChars = [
|
||||
* @private
|
||||
*/
|
||||
function push(dest, name, elem) {
|
||||
if (Object.prototype.hasOwnProperty.call(dest, name)) dest[name].push(elem);
|
||||
else dest[name] = [elem];
|
||||
if (dest[name] === undefined) dest[name] = [elem];
|
||||
else dest[name].push(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,20 +46,21 @@ function push(dest, name, elem) {
|
||||
* @public
|
||||
*/
|
||||
function parse(header) {
|
||||
const offers = {};
|
||||
const offers = Object.create(null);
|
||||
|
||||
if (header === undefined || header === '') return offers;
|
||||
|
||||
var params = {};
|
||||
var mustUnescape = false;
|
||||
var isEscaping = false;
|
||||
var inQuotes = false;
|
||||
var extensionName;
|
||||
var paramName;
|
||||
var start = -1;
|
||||
var end = -1;
|
||||
let params = Object.create(null);
|
||||
let mustUnescape = false;
|
||||
let isEscaping = false;
|
||||
let inQuotes = false;
|
||||
let extensionName;
|
||||
let paramName;
|
||||
let start = -1;
|
||||
let end = -1;
|
||||
let i = 0;
|
||||
|
||||
for (var i = 0; i < header.length; i++) {
|
||||
for (; i < header.length; i++) {
|
||||
const code = header.charCodeAt(i);
|
||||
|
||||
if (extensionName === undefined) {
|
||||
@@ -76,7 +77,7 @@ function parse(header) {
|
||||
const name = header.slice(start, end);
|
||||
if (code === 0x2c) {
|
||||
push(offers, name, params);
|
||||
params = {};
|
||||
params = Object.create(null);
|
||||
} else {
|
||||
extensionName = name;
|
||||
}
|
||||
@@ -99,7 +100,7 @@ function parse(header) {
|
||||
push(params, header.slice(start, end), true);
|
||||
if (code === 0x2c) {
|
||||
push(offers, extensionName, params);
|
||||
params = {};
|
||||
params = Object.create(null);
|
||||
extensionName = undefined;
|
||||
}
|
||||
|
||||
@@ -146,7 +147,7 @@ function parse(header) {
|
||||
}
|
||||
|
||||
if (end === -1) end = i;
|
||||
var value = header.slice(start, end);
|
||||
let value = header.slice(start, end);
|
||||
if (mustUnescape) {
|
||||
value = value.replace(/\\/g, '');
|
||||
mustUnescape = false;
|
||||
@@ -154,7 +155,7 @@ function parse(header) {
|
||||
push(params, paramName, value);
|
||||
if (code === 0x2c) {
|
||||
push(offers, extensionName, params);
|
||||
params = {};
|
||||
params = Object.create(null);
|
||||
extensionName = undefined;
|
||||
}
|
||||
|
||||
@@ -173,7 +174,7 @@ function parse(header) {
|
||||
if (end === -1) end = i;
|
||||
const token = header.slice(start, end);
|
||||
if (extensionName === undefined) {
|
||||
push(offers, token, {});
|
||||
push(offers, token, params);
|
||||
} else {
|
||||
if (paramName === undefined) {
|
||||
push(params, token, true);
|
||||
@@ -198,14 +199,14 @@ function parse(header) {
|
||||
function format(extensions) {
|
||||
return Object.keys(extensions)
|
||||
.map((extension) => {
|
||||
var configurations = extensions[extension];
|
||||
let configurations = extensions[extension];
|
||||
if (!Array.isArray(configurations)) configurations = [configurations];
|
||||
return configurations
|
||||
.map((params) => {
|
||||
return [extension]
|
||||
.concat(
|
||||
Object.keys(params).map((k) => {
|
||||
var values = params[k];
|
||||
let values = params[k];
|
||||
if (!Array.isArray(values)) values = [values];
|
||||
return values
|
||||
.map((v) => (v === true ? k : `${k}=${v}`))
|
||||
|
54
node_modules/ws/lib/limiter.js
generated
vendored
Normal file
54
node_modules/ws/lib/limiter.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
const kDone = Symbol('kDone');
|
||||
const kRun = Symbol('kRun');
|
||||
|
||||
/**
|
||||
* A very simple job queue with adjustable concurrency. Adapted from
|
||||
* https://github.com/STRML/async-limiter
|
||||
*/
|
||||
class Limiter {
|
||||
/**
|
||||
* Creates a new `Limiter`.
|
||||
*
|
||||
* @param {Number} concurrency The maximum number of jobs allowed to run
|
||||
* concurrently
|
||||
*/
|
||||
constructor(concurrency) {
|
||||
this[kDone] = () => {
|
||||
this.pending--;
|
||||
this[kRun]();
|
||||
};
|
||||
this.concurrency = concurrency || Infinity;
|
||||
this.jobs = [];
|
||||
this.pending = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a job to the queue.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
add(job) {
|
||||
this.jobs.push(job);
|
||||
this[kRun]();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a job from the queue and runs it if possible.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
[kRun]() {
|
||||
if (this.pending === this.concurrency) return;
|
||||
|
||||
if (this.jobs.length) {
|
||||
const job = this.jobs.shift();
|
||||
|
||||
this.pending++;
|
||||
job(this[kDone]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Limiter;
|
60
node_modules/ws/lib/permessage-deflate.js
generated
vendored
60
node_modules/ws/lib/permessage-deflate.js
generated
vendored
@@ -1,14 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
const Limiter = require('async-limiter');
|
||||
const zlib = require('zlib');
|
||||
|
||||
const bufferUtil = require('./buffer-util');
|
||||
const Limiter = require('./limiter');
|
||||
const { kStatusCode, NOOP } = require('./constants');
|
||||
|
||||
const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
|
||||
const EMPTY_BLOCK = Buffer.from([0x00]);
|
||||
|
||||
const kPerMessageDeflate = Symbol('permessage-deflate');
|
||||
const kTotalLength = Symbol('total-length');
|
||||
const kCallback = Symbol('callback');
|
||||
@@ -66,7 +64,7 @@ class PerMessageDeflate {
|
||||
this._options.concurrencyLimit !== undefined
|
||||
? this._options.concurrencyLimit
|
||||
: 10;
|
||||
zlibLimiter = new Limiter({ concurrency });
|
||||
zlibLimiter = new Limiter(concurrency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,8 +131,18 @@ class PerMessageDeflate {
|
||||
}
|
||||
|
||||
if (this._deflate) {
|
||||
const callback = this._deflate[kCallback];
|
||||
|
||||
this._deflate.close();
|
||||
this._deflate = null;
|
||||
|
||||
if (callback) {
|
||||
callback(
|
||||
new Error(
|
||||
'The deflate stream was closed while data was being processed'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +241,7 @@ class PerMessageDeflate {
|
||||
normalizeParams(configurations) {
|
||||
configurations.forEach((params) => {
|
||||
Object.keys(params).forEach((key) => {
|
||||
var value = params[key];
|
||||
let value = params[key];
|
||||
|
||||
if (value.length > 1) {
|
||||
throw new Error(`Parameter "${key}" must have only a single value`);
|
||||
@@ -284,7 +292,7 @@ class PerMessageDeflate {
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress data. Concurrency limited by async-limiter.
|
||||
* Decompress data. Concurrency limited.
|
||||
*
|
||||
* @param {Buffer} data Compressed data
|
||||
* @param {Boolean} fin Specifies whether or not this is the last fragment
|
||||
@@ -292,7 +300,7 @@ class PerMessageDeflate {
|
||||
* @public
|
||||
*/
|
||||
decompress(data, fin, callback) {
|
||||
zlibLimiter.push((done) => {
|
||||
zlibLimiter.add((done) => {
|
||||
this._decompress(data, fin, (err, result) => {
|
||||
done();
|
||||
callback(err, result);
|
||||
@@ -301,7 +309,7 @@ class PerMessageDeflate {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress data. Concurrency limited by async-limiter.
|
||||
* Compress data. Concurrency limited.
|
||||
*
|
||||
* @param {Buffer} data Data to compress
|
||||
* @param {Boolean} fin Specifies whether or not this is the last fragment
|
||||
@@ -309,7 +317,7 @@ class PerMessageDeflate {
|
||||
* @public
|
||||
*/
|
||||
compress(data, fin, callback) {
|
||||
zlibLimiter.push((done) => {
|
||||
zlibLimiter.add((done) => {
|
||||
this._compress(data, fin, (err, result) => {
|
||||
done();
|
||||
callback(err, result);
|
||||
@@ -335,9 +343,10 @@ class PerMessageDeflate {
|
||||
? zlib.Z_DEFAULT_WINDOWBITS
|
||||
: this.params[key];
|
||||
|
||||
this._inflate = zlib.createInflateRaw(
|
||||
Object.assign({}, this._options.zlibInflateOptions, { windowBits })
|
||||
);
|
||||
this._inflate = zlib.createInflateRaw({
|
||||
...this._options.zlibInflateOptions,
|
||||
windowBits
|
||||
});
|
||||
this._inflate[kPerMessageDeflate] = this;
|
||||
this._inflate[kTotalLength] = 0;
|
||||
this._inflate[kBuffers] = [];
|
||||
@@ -386,11 +395,6 @@ class PerMessageDeflate {
|
||||
* @private
|
||||
*/
|
||||
_compress(data, fin, callback) {
|
||||
if (!data || data.length === 0) {
|
||||
process.nextTick(callback, null, EMPTY_BLOCK);
|
||||
return;
|
||||
}
|
||||
|
||||
const endpoint = this._isServer ? 'server' : 'client';
|
||||
|
||||
if (!this._deflate) {
|
||||
@@ -400,9 +404,10 @@ class PerMessageDeflate {
|
||||
? zlib.Z_DEFAULT_WINDOWBITS
|
||||
: this.params[key];
|
||||
|
||||
this._deflate = zlib.createDeflateRaw(
|
||||
Object.assign({}, this._options.zlibDeflateOptions, { windowBits })
|
||||
);
|
||||
this._deflate = zlib.createDeflateRaw({
|
||||
...this._options.zlibDeflateOptions,
|
||||
windowBits
|
||||
});
|
||||
|
||||
this._deflate[kTotalLength] = 0;
|
||||
this._deflate[kBuffers] = [];
|
||||
@@ -417,25 +422,30 @@ class PerMessageDeflate {
|
||||
this._deflate.on('data', deflateOnData);
|
||||
}
|
||||
|
||||
this._deflate[kCallback] = callback;
|
||||
|
||||
this._deflate.write(data);
|
||||
this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
|
||||
if (!this._deflate) {
|
||||
//
|
||||
// This `if` statement is only needed for Node.js < 10.0.0 because as of
|
||||
// commit https://github.com/nodejs/node/commit/5e3f5164, the flush
|
||||
// callback is no longer called if the deflate stream is closed while
|
||||
// data is being processed.
|
||||
// The deflate stream was closed while data was being processed.
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
var data = bufferUtil.concat(
|
||||
let data = bufferUtil.concat(
|
||||
this._deflate[kBuffers],
|
||||
this._deflate[kTotalLength]
|
||||
);
|
||||
|
||||
if (fin) data = data.slice(0, data.length - 4);
|
||||
|
||||
//
|
||||
// Ensure that the callback will not be called again in
|
||||
// `PerMessageDeflate#cleanup()`.
|
||||
//
|
||||
this._deflate[kCallback] = null;
|
||||
|
||||
if (fin && this.params[`${endpoint}_no_context_takeover`]) {
|
||||
this._deflate.close();
|
||||
this._deflate = null;
|
||||
|
27
node_modules/ws/lib/receiver.js
generated
vendored
27
node_modules/ws/lib/receiver.js
generated
vendored
@@ -30,14 +30,17 @@ class Receiver extends Writable {
|
||||
*
|
||||
* @param {String} binaryType The type for binary data
|
||||
* @param {Object} extensions An object containing the negotiated extensions
|
||||
* @param {Boolean} isServer Specifies whether to operate in client or server
|
||||
* mode
|
||||
* @param {Number} maxPayload The maximum allowed message length
|
||||
*/
|
||||
constructor(binaryType, extensions, maxPayload) {
|
||||
constructor(binaryType, extensions, isServer, maxPayload) {
|
||||
super();
|
||||
|
||||
this._binaryType = binaryType || BINARY_TYPES[0];
|
||||
this[kWebSocket] = undefined;
|
||||
this._extensions = extensions || {};
|
||||
this._isServer = !!isServer;
|
||||
this._maxPayload = maxPayload | 0;
|
||||
|
||||
this._bufferedBytes = 0;
|
||||
@@ -65,6 +68,7 @@ class Receiver extends Writable {
|
||||
* @param {Buffer} chunk The chunk of data to write
|
||||
* @param {String} encoding The character encoding of `chunk`
|
||||
* @param {Function} cb Callback
|
||||
* @private
|
||||
*/
|
||||
_write(chunk, encoding, cb) {
|
||||
if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
|
||||
@@ -96,11 +100,12 @@ class Receiver extends Writable {
|
||||
|
||||
do {
|
||||
const buf = this._buffers[0];
|
||||
const offset = dst.length - n;
|
||||
|
||||
if (n >= buf.length) {
|
||||
this._buffers.shift().copy(dst, dst.length - n);
|
||||
dst.set(this._buffers.shift(), offset);
|
||||
} else {
|
||||
buf.copy(dst, dst.length - n, 0, n);
|
||||
dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
|
||||
this._buffers[0] = buf.slice(n);
|
||||
}
|
||||
|
||||
@@ -117,7 +122,7 @@ class Receiver extends Writable {
|
||||
* @private
|
||||
*/
|
||||
startLoop(cb) {
|
||||
var err;
|
||||
let err;
|
||||
this._loop = true;
|
||||
|
||||
do {
|
||||
@@ -224,6 +229,16 @@ class Receiver extends Writable {
|
||||
if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
|
||||
this._masked = (buf[1] & 0x80) === 0x80;
|
||||
|
||||
if (this._isServer) {
|
||||
if (!this._masked) {
|
||||
this._loop = false;
|
||||
return error(RangeError, 'MASK must be set', true, 1002);
|
||||
}
|
||||
} else if (this._masked) {
|
||||
this._loop = false;
|
||||
return error(RangeError, 'MASK must be clear', true, 1002);
|
||||
}
|
||||
|
||||
if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
|
||||
else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
|
||||
else return this.haveLength();
|
||||
@@ -320,7 +335,7 @@ class Receiver extends Writable {
|
||||
* @private
|
||||
*/
|
||||
getData(cb) {
|
||||
var data = EMPTY_BUFFER;
|
||||
let data = EMPTY_BUFFER;
|
||||
|
||||
if (this._payloadLength) {
|
||||
if (this._bufferedBytes < this._payloadLength) {
|
||||
@@ -400,7 +415,7 @@ class Receiver extends Writable {
|
||||
this._fragments = [];
|
||||
|
||||
if (this._opcode === 2) {
|
||||
var data;
|
||||
let data;
|
||||
|
||||
if (this._binaryType === 'nodebuffer') {
|
||||
data = concat(fragments, messageLength);
|
||||
|
56
node_modules/ws/lib/sender.js
generated
vendored
56
node_modules/ws/lib/sender.js
generated
vendored
@@ -1,12 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const { randomBytes } = require('crypto');
|
||||
const { randomFillSync } = require('crypto');
|
||||
|
||||
const PerMessageDeflate = require('./permessage-deflate');
|
||||
const { EMPTY_BUFFER } = require('./constants');
|
||||
const { isValidStatusCode } = require('./validation');
|
||||
const { mask: applyMask, toBuffer } = require('./buffer-util');
|
||||
|
||||
const mask = Buffer.alloc(4);
|
||||
|
||||
/**
|
||||
* HyBi Sender implementation.
|
||||
*/
|
||||
@@ -44,8 +46,8 @@ class Sender {
|
||||
*/
|
||||
static frame(data, options) {
|
||||
const merge = options.mask && options.readOnly;
|
||||
var offset = options.mask ? 6 : 2;
|
||||
var payloadLength = data.length;
|
||||
let offset = options.mask ? 6 : 2;
|
||||
let payloadLength = data.length;
|
||||
|
||||
if (data.length >= 65536) {
|
||||
offset += 8;
|
||||
@@ -71,7 +73,7 @@ class Sender {
|
||||
|
||||
if (!options.mask) return [target, data];
|
||||
|
||||
const mask = randomBytes(4);
|
||||
randomFillSync(mask, 0, 4);
|
||||
|
||||
target[1] |= 0x80;
|
||||
target[offset - 4] = mask[0];
|
||||
@@ -98,7 +100,7 @@ class Sender {
|
||||
* @public
|
||||
*/
|
||||
close(code, data, mask, cb) {
|
||||
var buf;
|
||||
let buf;
|
||||
|
||||
if (code === undefined) {
|
||||
buf = EMPTY_BUFFER;
|
||||
@@ -108,7 +110,13 @@ class Sender {
|
||||
buf = Buffer.allocUnsafe(2);
|
||||
buf.writeUInt16BE(code, 0);
|
||||
} else {
|
||||
buf = Buffer.allocUnsafe(2 + Buffer.byteLength(data));
|
||||
const length = Buffer.byteLength(data);
|
||||
|
||||
if (length > 123) {
|
||||
throw new RangeError('The message must not be greater than 123 bytes');
|
||||
}
|
||||
|
||||
buf = Buffer.allocUnsafe(2 + length);
|
||||
buf.writeUInt16BE(code, 0);
|
||||
buf.write(data, 2);
|
||||
}
|
||||
@@ -152,6 +160,10 @@ class Sender {
|
||||
ping(data, mask, cb) {
|
||||
const buf = toBuffer(data);
|
||||
|
||||
if (buf.length > 125) {
|
||||
throw new RangeError('The data size must not be greater than 125 bytes');
|
||||
}
|
||||
|
||||
if (this._deflating) {
|
||||
this.enqueue([this.doPing, buf, mask, toBuffer.readOnly, cb]);
|
||||
} else {
|
||||
@@ -162,7 +174,7 @@ class Sender {
|
||||
/**
|
||||
* Frames and sends a ping message.
|
||||
*
|
||||
* @param {*} data The message to send
|
||||
* @param {Buffer} data The message to send
|
||||
* @param {Boolean} mask Specifies whether or not to mask `data`
|
||||
* @param {Boolean} readOnly Specifies whether `data` can be modified
|
||||
* @param {Function} cb Callback
|
||||
@@ -192,6 +204,10 @@ class Sender {
|
||||
pong(data, mask, cb) {
|
||||
const buf = toBuffer(data);
|
||||
|
||||
if (buf.length > 125) {
|
||||
throw new RangeError('The data size must not be greater than 125 bytes');
|
||||
}
|
||||
|
||||
if (this._deflating) {
|
||||
this.enqueue([this.doPong, buf, mask, toBuffer.readOnly, cb]);
|
||||
} else {
|
||||
@@ -202,7 +218,7 @@ class Sender {
|
||||
/**
|
||||
* Frames and sends a pong message.
|
||||
*
|
||||
* @param {*} data The message to send
|
||||
* @param {Buffer} data The message to send
|
||||
* @param {Boolean} mask Specifies whether or not to mask `data`
|
||||
* @param {Boolean} readOnly Specifies whether `data` can be modified
|
||||
* @param {Function} cb Callback
|
||||
@@ -236,8 +252,8 @@ class Sender {
|
||||
send(data, options, cb) {
|
||||
const buf = toBuffer(data);
|
||||
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
|
||||
var opcode = options.binary ? 2 : 1;
|
||||
var rsv1 = options.compress;
|
||||
let opcode = options.binary ? 2 : 1;
|
||||
let rsv1 = options.compress;
|
||||
|
||||
if (this._firstFragment) {
|
||||
this._firstFragment = false;
|
||||
@@ -302,8 +318,26 @@ class Sender {
|
||||
|
||||
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
|
||||
|
||||
this._bufferedBytes += data.length;
|
||||
this._deflating = true;
|
||||
perMessageDeflate.compress(data, options.fin, (_, buf) => {
|
||||
if (this._socket.destroyed) {
|
||||
const err = new Error(
|
||||
'The socket was closed while data was being compressed'
|
||||
);
|
||||
|
||||
if (typeof cb === 'function') cb(err);
|
||||
|
||||
for (let i = 0; i < this._queue.length; i++) {
|
||||
const callback = this._queue[i][4];
|
||||
|
||||
if (typeof callback === 'function') callback(err);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._bufferedBytes -= data.length;
|
||||
this._deflating = false;
|
||||
options.readOnly = false;
|
||||
this.sendFrame(Sender.frame(buf, options), cb);
|
||||
@@ -321,7 +355,7 @@ class Sender {
|
||||
const params = this._queue.shift();
|
||||
|
||||
this._bufferedBytes -= params[1].length;
|
||||
params[0].apply(this, params.slice(1));
|
||||
Reflect.apply(params[0], this, params.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
164
node_modules/ws/lib/stream.js
generated
vendored
Normal file
164
node_modules/ws/lib/stream.js
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
'use strict';
|
||||
|
||||
const { Duplex } = require('stream');
|
||||
|
||||
/**
|
||||
* Emits the `'close'` event on a stream.
|
||||
*
|
||||
* @param {stream.Duplex} The stream.
|
||||
* @private
|
||||
*/
|
||||
function emitClose(stream) {
|
||||
stream.emit('close');
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener of the `'end'` event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function duplexOnEnd() {
|
||||
if (!this.destroyed && this._writableState.finished) {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener of the `'error'` event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function duplexOnError(err) {
|
||||
this.removeListener('error', duplexOnError);
|
||||
this.destroy();
|
||||
if (this.listenerCount('error') === 0) {
|
||||
// Do not suppress the throwing behavior.
|
||||
this.emit('error', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a `WebSocket` in a duplex stream.
|
||||
*
|
||||
* @param {WebSocket} ws The `WebSocket` to wrap
|
||||
* @param {Object} options The options for the `Duplex` constructor
|
||||
* @return {stream.Duplex} The duplex stream
|
||||
* @public
|
||||
*/
|
||||
function createWebSocketStream(ws, options) {
|
||||
let resumeOnReceiverDrain = 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({
|
||||
...options,
|
||||
autoDestroy: false,
|
||||
emitClose: false,
|
||||
objectMode: false,
|
||||
writableObjectMode: false
|
||||
});
|
||||
|
||||
ws.on('message', function message(msg) {
|
||||
if (!duplex.push(msg)) {
|
||||
resumeOnReceiverDrain = false;
|
||||
ws._socket.pause();
|
||||
}
|
||||
});
|
||||
|
||||
ws.once('error', function error(err) {
|
||||
if (duplex.destroyed) return;
|
||||
|
||||
duplex.destroy(err);
|
||||
});
|
||||
|
||||
ws.once('close', function close() {
|
||||
if (duplex.destroyed) return;
|
||||
|
||||
duplex.push(null);
|
||||
});
|
||||
|
||||
duplex._destroy = function (err, callback) {
|
||||
if (ws.readyState === ws.CLOSED) {
|
||||
callback(err);
|
||||
process.nextTick(emitClose, duplex);
|
||||
return;
|
||||
}
|
||||
|
||||
let called = false;
|
||||
|
||||
ws.once('error', function error(err) {
|
||||
called = true;
|
||||
callback(err);
|
||||
});
|
||||
|
||||
ws.once('close', function close() {
|
||||
if (!called) callback(err);
|
||||
process.nextTick(emitClose, duplex);
|
||||
});
|
||||
ws.terminate();
|
||||
};
|
||||
|
||||
duplex._final = function (callback) {
|
||||
if (ws.readyState === ws.CONNECTING) {
|
||||
ws.once('open', function open() {
|
||||
duplex._final(callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// If the value of the `_socket` property is `null` it means that `ws` is a
|
||||
// client websocket and the handshake failed. In fact, when this happens, a
|
||||
// socket is never assigned to the websocket. Wait for the `'error'` event
|
||||
// that will be emitted by the websocket.
|
||||
if (ws._socket === null) return;
|
||||
|
||||
if (ws._socket._writableState.finished) {
|
||||
callback();
|
||||
if (duplex._readableState.endEmitted) duplex.destroy();
|
||||
} else {
|
||||
ws._socket.once('finish', function finish() {
|
||||
// `duplex` is not destroyed here because the `'end'` event will be
|
||||
// emitted on `duplex` after this `'finish'` event. The EOF signaling
|
||||
// `null` chunk is, in fact, pushed when the websocket emits `'close'`.
|
||||
callback();
|
||||
});
|
||||
ws.close();
|
||||
}
|
||||
};
|
||||
|
||||
duplex._read = function () {
|
||||
if (ws.readyState === ws.OPEN && !resumeOnReceiverDrain) {
|
||||
resumeOnReceiverDrain = true;
|
||||
if (!ws._receiver._writableState.needDrain) ws._socket.resume();
|
||||
}
|
||||
};
|
||||
|
||||
duplex._write = function (chunk, encoding, callback) {
|
||||
if (ws.readyState === ws.CONNECTING) {
|
||||
ws.once('open', function open() {
|
||||
duplex._write(chunk, encoding, callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send(chunk, callback);
|
||||
};
|
||||
|
||||
duplex.on('end', duplexOnEnd);
|
||||
duplex.on('error', duplexOnError);
|
||||
return duplex;
|
||||
}
|
||||
|
||||
module.exports = createWebSocketStream;
|
2
node_modules/ws/lib/validation.js
generated
vendored
2
node_modules/ws/lib/validation.js
generated
vendored
@@ -21,7 +21,7 @@ try {
|
||||
exports.isValidStatusCode = (code) => {
|
||||
return (
|
||||
(code >= 1000 &&
|
||||
code <= 1013 &&
|
||||
code <= 1014 &&
|
||||
code !== 1004 &&
|
||||
code !== 1005 &&
|
||||
code !== 1006) ||
|
||||
|
81
node_modules/ws/lib/websocket-server.js
generated
vendored
81
node_modules/ws/lib/websocket-server.js
generated
vendored
@@ -1,13 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
const crypto = require('crypto');
|
||||
const http = require('http');
|
||||
const { createHash } = require('crypto');
|
||||
const { createServer, STATUS_CODES } = require('http');
|
||||
|
||||
const PerMessageDeflate = require('./permessage-deflate');
|
||||
const extension = require('./extension');
|
||||
const WebSocket = require('./websocket');
|
||||
const { GUID } = require('./constants');
|
||||
const { format, parse } = require('./extension');
|
||||
const { GUID, kWebSocket } = require('./constants');
|
||||
|
||||
const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
|
||||
|
||||
@@ -25,7 +25,7 @@ class WebSocketServer extends EventEmitter {
|
||||
* connections
|
||||
* @param {Boolean} options.clientTracking Specifies whether or not to track
|
||||
* clients
|
||||
* @param {Function} options.handleProtocols An hook to handle protocols
|
||||
* @param {Function} options.handleProtocols A hook to handle protocols
|
||||
* @param {String} options.host The hostname where to bind the server
|
||||
* @param {Number} options.maxPayload The maximum allowed message size
|
||||
* @param {Boolean} options.noServer Enable no server mode
|
||||
@@ -34,28 +34,26 @@ class WebSocketServer extends EventEmitter {
|
||||
* permessage-deflate
|
||||
* @param {Number} options.port The port where to bind the server
|
||||
* @param {http.Server} options.server A pre-created HTTP/S server to use
|
||||
* @param {Function} options.verifyClient An hook to reject connections
|
||||
* @param {Function} options.verifyClient A hook to reject connections
|
||||
* @param {Function} callback A listener for the `listening` event
|
||||
*/
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
|
||||
options = Object.assign(
|
||||
{
|
||||
maxPayload: 100 * 1024 * 1024,
|
||||
perMessageDeflate: false,
|
||||
handleProtocols: null,
|
||||
clientTracking: true,
|
||||
verifyClient: null,
|
||||
noServer: false,
|
||||
backlog: null, // use default (511 as implemented in net.js)
|
||||
server: null,
|
||||
host: null,
|
||||
path: null,
|
||||
port: null
|
||||
},
|
||||
options
|
||||
);
|
||||
options = {
|
||||
maxPayload: 100 * 1024 * 1024,
|
||||
perMessageDeflate: false,
|
||||
handleProtocols: null,
|
||||
clientTracking: true,
|
||||
verifyClient: null,
|
||||
noServer: false,
|
||||
backlog: null, // use default (511 as implemented in net.js)
|
||||
server: null,
|
||||
host: null,
|
||||
path: null,
|
||||
port: null,
|
||||
...options
|
||||
};
|
||||
|
||||
if (options.port == null && !options.server && !options.noServer) {
|
||||
throw new TypeError(
|
||||
@@ -64,8 +62,8 @@ class WebSocketServer extends EventEmitter {
|
||||
}
|
||||
|
||||
if (options.port != null) {
|
||||
this._server = http.createServer((req, res) => {
|
||||
const body = http.STATUS_CODES[426];
|
||||
this._server = createServer((req, res) => {
|
||||
const body = STATUS_CODES[426];
|
||||
|
||||
res.writeHead(426, {
|
||||
'Content-Length': body.length,
|
||||
@@ -208,7 +206,7 @@ class WebSocketServer extends EventEmitter {
|
||||
);
|
||||
|
||||
try {
|
||||
const offers = extension.parse(req.headers['sec-websocket-extensions']);
|
||||
const offers = parse(req.headers['sec-websocket-extensions']);
|
||||
|
||||
if (offers[PerMessageDeflate.extensionName]) {
|
||||
perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
|
||||
@@ -256,6 +254,7 @@ class WebSocketServer extends EventEmitter {
|
||||
* @param {net.Socket} socket The network socket between the server and client
|
||||
* @param {Buffer} head The first packet of the upgraded stream
|
||||
* @param {Function} cb Callback
|
||||
* @throws {Error} If called more than once with the same socket
|
||||
* @private
|
||||
*/
|
||||
completeUpgrade(key, extensions, req, socket, head, cb) {
|
||||
@@ -264,8 +263,14 @@ class WebSocketServer extends EventEmitter {
|
||||
//
|
||||
if (!socket.readable || !socket.writable) return socket.destroy();
|
||||
|
||||
const digest = crypto
|
||||
.createHash('sha1')
|
||||
if (socket[kWebSocket]) {
|
||||
throw new Error(
|
||||
'server.handleUpgrade() was called more than once with the same ' +
|
||||
'socket, possibly due to a misconfiguration'
|
||||
);
|
||||
}
|
||||
|
||||
const digest = createHash('sha1')
|
||||
.update(key + GUID)
|
||||
.digest('base64');
|
||||
|
||||
@@ -277,7 +282,7 @@ class WebSocketServer extends EventEmitter {
|
||||
];
|
||||
|
||||
const ws = new WebSocket(null);
|
||||
var protocol = req.headers['sec-websocket-protocol'];
|
||||
let protocol = req.headers['sec-websocket-protocol'];
|
||||
|
||||
if (protocol) {
|
||||
protocol = protocol.trim().split(/ *, */);
|
||||
@@ -299,7 +304,7 @@ class WebSocketServer extends EventEmitter {
|
||||
|
||||
if (extensions[PerMessageDeflate.extensionName]) {
|
||||
const params = extensions[PerMessageDeflate.extensionName].params;
|
||||
const value = extension.format({
|
||||
const value = format({
|
||||
[PerMessageDeflate.extensionName]: [params]
|
||||
});
|
||||
headers.push(`Sec-WebSocket-Extensions: ${value}`);
|
||||
@@ -376,18 +381,16 @@ function socketOnError() {
|
||||
*/
|
||||
function abortHandshake(socket, code, message, headers) {
|
||||
if (socket.writable) {
|
||||
message = message || http.STATUS_CODES[code];
|
||||
headers = Object.assign(
|
||||
{
|
||||
Connection: 'close',
|
||||
'Content-type': 'text/html',
|
||||
'Content-Length': Buffer.byteLength(message)
|
||||
},
|
||||
headers
|
||||
);
|
||||
message = message || STATUS_CODES[code];
|
||||
headers = {
|
||||
Connection: 'close',
|
||||
'Content-Type': 'text/html',
|
||||
'Content-Length': Buffer.byteLength(message),
|
||||
...headers
|
||||
};
|
||||
|
||||
socket.write(
|
||||
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
|
||||
`HTTP/1.1 ${code} ${STATUS_CODES[code]}\r\n` +
|
||||
Object.keys(headers)
|
||||
.map((h) => `${h}: ${headers[h]}`)
|
||||
.join('\r\n') +
|
||||
|
252
node_modules/ws/lib/websocket.js
generated
vendored
252
node_modules/ws/lib/websocket.js
generated
vendored
@@ -1,16 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
const crypto = require('crypto');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const net = require('net');
|
||||
const tls = require('tls');
|
||||
const url = require('url');
|
||||
const { randomBytes, createHash } = require('crypto');
|
||||
const { URL } = require('url');
|
||||
|
||||
const PerMessageDeflate = require('./permessage-deflate');
|
||||
const EventTarget = require('./event-target');
|
||||
const extension = require('./extension');
|
||||
const Receiver = require('./receiver');
|
||||
const Sender = require('./sender');
|
||||
const {
|
||||
@@ -21,6 +19,9 @@ const {
|
||||
kWebSocket,
|
||||
NOOP
|
||||
} = require('./constants');
|
||||
const { addEventListener, removeEventListener } = require('./event-target');
|
||||
const { format, parse } = require('./extension');
|
||||
const { toBuffer } = require('./buffer-util');
|
||||
|
||||
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
|
||||
const protocolVersions = [8, 13];
|
||||
@@ -35,7 +36,7 @@ class WebSocket extends EventEmitter {
|
||||
/**
|
||||
* Create a new `WebSocket`.
|
||||
*
|
||||
* @param {(String|url.Url|url.URL)} address The URL to which to connect
|
||||
* @param {(String|url.URL)} address The URL to which to connect
|
||||
* @param {(String|String[])} protocols The subprotocols
|
||||
* @param {Object} options Connection options
|
||||
*/
|
||||
@@ -57,6 +58,7 @@ class WebSocket extends EventEmitter {
|
||||
this._socket = null;
|
||||
|
||||
if (address !== null) {
|
||||
this._bufferedAmount = 0;
|
||||
this._isServer = false;
|
||||
this._redirects = 0;
|
||||
|
||||
@@ -112,12 +114,9 @@ class WebSocket extends EventEmitter {
|
||||
* @type {Number}
|
||||
*/
|
||||
get bufferedAmount() {
|
||||
if (!this._socket) return 0;
|
||||
if (!this._socket) return this._bufferedAmount;
|
||||
|
||||
//
|
||||
// `socket.bufferSize` is `undefined` if the socket is closed.
|
||||
//
|
||||
return (this._socket.bufferSize || 0) + this._sender._bufferedBytes;
|
||||
return this._socket._writableState.length + this._sender._bufferedBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,6 +138,7 @@ class WebSocket extends EventEmitter {
|
||||
const receiver = new Receiver(
|
||||
this._binaryType,
|
||||
this._extensions,
|
||||
this._isServer,
|
||||
maxPayload
|
||||
);
|
||||
|
||||
@@ -176,9 +176,8 @@ class WebSocket extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
emitClose() {
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
|
||||
if (!this._socket) {
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
this.emit('close', this._closeCode, this._closeMessage);
|
||||
return;
|
||||
}
|
||||
@@ -188,6 +187,7 @@ class WebSocket extends EventEmitter {
|
||||
}
|
||||
|
||||
this._receiver.removeAllListeners();
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
this.emit('close', this._closeCode, this._closeMessage);
|
||||
}
|
||||
|
||||
@@ -252,6 +252,10 @@ class WebSocket extends EventEmitter {
|
||||
* @public
|
||||
*/
|
||||
ping(data, mask, cb) {
|
||||
if (this.readyState === WebSocket.CONNECTING) {
|
||||
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
|
||||
}
|
||||
|
||||
if (typeof data === 'function') {
|
||||
cb = data;
|
||||
data = mask = undefined;
|
||||
@@ -260,17 +264,13 @@ class WebSocket extends EventEmitter {
|
||||
mask = undefined;
|
||||
}
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
const err = new Error(
|
||||
`WebSocket is not open: readyState ${this.readyState} ` +
|
||||
`(${readyStates[this.readyState]})`
|
||||
);
|
||||
if (typeof data === 'number') data = data.toString();
|
||||
|
||||
if (cb) return cb(err);
|
||||
throw err;
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
sendAfterClose(this, data, cb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof data === 'number') data = data.toString();
|
||||
if (mask === undefined) mask = !this._isServer;
|
||||
this._sender.ping(data || EMPTY_BUFFER, mask, cb);
|
||||
}
|
||||
@@ -284,6 +284,10 @@ class WebSocket extends EventEmitter {
|
||||
* @public
|
||||
*/
|
||||
pong(data, mask, cb) {
|
||||
if (this.readyState === WebSocket.CONNECTING) {
|
||||
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
|
||||
}
|
||||
|
||||
if (typeof data === 'function') {
|
||||
cb = data;
|
||||
data = mask = undefined;
|
||||
@@ -292,17 +296,13 @@ class WebSocket extends EventEmitter {
|
||||
mask = undefined;
|
||||
}
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
const err = new Error(
|
||||
`WebSocket is not open: readyState ${this.readyState} ` +
|
||||
`(${readyStates[this.readyState]})`
|
||||
);
|
||||
if (typeof data === 'number') data = data.toString();
|
||||
|
||||
if (cb) return cb(err);
|
||||
throw err;
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
sendAfterClose(this, data, cb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof data === 'number') data = data.toString();
|
||||
if (mask === undefined) mask = !this._isServer;
|
||||
this._sender.pong(data || EMPTY_BUFFER, mask, cb);
|
||||
}
|
||||
@@ -312,7 +312,8 @@ class WebSocket extends EventEmitter {
|
||||
*
|
||||
* @param {*} data The message to send
|
||||
* @param {Object} options Options object
|
||||
* @param {Boolean} options.compress Specifies whether or not to compress `data`
|
||||
* @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.fin Specifies whether the fragment is the last one
|
||||
* @param {Boolean} options.mask Specifies whether or not to mask `data`
|
||||
@@ -320,32 +321,29 @@ class WebSocket extends EventEmitter {
|
||||
* @public
|
||||
*/
|
||||
send(data, options, cb) {
|
||||
if (this.readyState === WebSocket.CONNECTING) {
|
||||
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
|
||||
}
|
||||
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
const err = new Error(
|
||||
`WebSocket is not open: readyState ${this.readyState} ` +
|
||||
`(${readyStates[this.readyState]})`
|
||||
);
|
||||
|
||||
if (cb) return cb(err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (typeof data === 'number') data = data.toString();
|
||||
|
||||
const opts = Object.assign(
|
||||
{
|
||||
binary: typeof data !== 'string',
|
||||
mask: !this._isServer,
|
||||
compress: true,
|
||||
fin: true
|
||||
},
|
||||
options
|
||||
);
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
sendAfterClose(this, data, cb);
|
||||
return;
|
||||
}
|
||||
|
||||
const opts = {
|
||||
binary: typeof data !== 'string',
|
||||
mask: !this._isServer,
|
||||
compress: true,
|
||||
fin: true,
|
||||
...options
|
||||
};
|
||||
|
||||
if (!this._extensions[PerMessageDeflate.extensionName]) {
|
||||
opts.compress = false;
|
||||
@@ -391,7 +389,7 @@ readyStates.forEach((readyState, i) => {
|
||||
*/
|
||||
get() {
|
||||
const listeners = this.listeners(method);
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i]._listener) return listeners[i]._listener;
|
||||
}
|
||||
|
||||
@@ -405,7 +403,7 @@ readyStates.forEach((readyState, i) => {
|
||||
*/
|
||||
set(listener) {
|
||||
const listeners = this.listeners(method);
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
//
|
||||
// Remove only the listeners added via `addEventListener`.
|
||||
//
|
||||
@@ -416,8 +414,8 @@ readyStates.forEach((readyState, i) => {
|
||||
});
|
||||
});
|
||||
|
||||
WebSocket.prototype.addEventListener = EventTarget.addEventListener;
|
||||
WebSocket.prototype.removeEventListener = EventTarget.removeEventListener;
|
||||
WebSocket.prototype.addEventListener = addEventListener;
|
||||
WebSocket.prototype.removeEventListener = removeEventListener;
|
||||
|
||||
module.exports = WebSocket;
|
||||
|
||||
@@ -425,7 +423,7 @@ module.exports = WebSocket;
|
||||
* Initialize a WebSocket client.
|
||||
*
|
||||
* @param {WebSocket} websocket The client to initialize
|
||||
* @param {(String|url.Url|url.URL)} address The URL to which to connect
|
||||
* @param {(String|url.URL)} address The URL to which to connect
|
||||
* @param {String} protocols The subprotocols
|
||||
* @param {Object} options Connection options
|
||||
* @param {(Boolean|Object)} options.perMessageDeflate Enable/disable
|
||||
@@ -442,28 +440,23 @@ module.exports = WebSocket;
|
||||
* @private
|
||||
*/
|
||||
function initAsClient(websocket, address, protocols, options) {
|
||||
const opts = Object.assign(
|
||||
{
|
||||
protocolVersion: protocolVersions[1],
|
||||
maxPayload: 100 * 1024 * 1024,
|
||||
perMessageDeflate: true,
|
||||
followRedirects: false,
|
||||
maxRedirects: 10
|
||||
},
|
||||
options,
|
||||
{
|
||||
createConnection: undefined,
|
||||
socketPath: undefined,
|
||||
hostname: undefined,
|
||||
protocol: undefined,
|
||||
timeout: undefined,
|
||||
method: undefined,
|
||||
auth: undefined,
|
||||
host: undefined,
|
||||
path: undefined,
|
||||
port: undefined
|
||||
}
|
||||
);
|
||||
const opts = {
|
||||
protocolVersion: protocolVersions[1],
|
||||
maxPayload: 100 * 1024 * 1024,
|
||||
perMessageDeflate: true,
|
||||
followRedirects: false,
|
||||
maxRedirects: 10,
|
||||
...options,
|
||||
createConnection: undefined,
|
||||
socketPath: undefined,
|
||||
hostname: undefined,
|
||||
protocol: undefined,
|
||||
timeout: undefined,
|
||||
method: undefined,
|
||||
host: undefined,
|
||||
path: undefined,
|
||||
port: undefined
|
||||
};
|
||||
|
||||
if (!protocolVersions.includes(opts.protocolVersion)) {
|
||||
throw new RangeError(
|
||||
@@ -472,16 +465,13 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
);
|
||||
}
|
||||
|
||||
var parsedUrl;
|
||||
let parsedUrl;
|
||||
|
||||
if (typeof address === 'object' && address.href !== undefined) {
|
||||
if (address instanceof URL) {
|
||||
parsedUrl = address;
|
||||
websocket.url = address.href;
|
||||
} else {
|
||||
//
|
||||
// The WHATWG URL constructor is not available on Node.js < 6.13.0
|
||||
//
|
||||
parsedUrl = url.URL ? new url.URL(address) : url.parse(address);
|
||||
parsedUrl = new URL(address);
|
||||
websocket.url = address;
|
||||
}
|
||||
|
||||
@@ -494,12 +484,9 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
const isSecure =
|
||||
parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:';
|
||||
const defaultPort = isSecure ? 443 : 80;
|
||||
const key = crypto.randomBytes(16).toString('base64');
|
||||
const key = randomBytes(16).toString('base64');
|
||||
const get = isSecure ? https.get : http.get;
|
||||
const path = parsedUrl.search
|
||||
? `${parsedUrl.pathname || '/'}${parsedUrl.search}`
|
||||
: parsedUrl.pathname || '/';
|
||||
var perMessageDeflate;
|
||||
let perMessageDeflate;
|
||||
|
||||
opts.createConnection = isSecure ? tlsConnect : netConnect;
|
||||
opts.defaultPort = opts.defaultPort || defaultPort;
|
||||
@@ -507,16 +494,14 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
opts.host = parsedUrl.hostname.startsWith('[')
|
||||
? parsedUrl.hostname.slice(1, -1)
|
||||
: parsedUrl.hostname;
|
||||
opts.headers = Object.assign(
|
||||
{
|
||||
'Sec-WebSocket-Version': opts.protocolVersion,
|
||||
'Sec-WebSocket-Key': key,
|
||||
Connection: 'Upgrade',
|
||||
Upgrade: 'websocket'
|
||||
},
|
||||
opts.headers
|
||||
);
|
||||
opts.path = path;
|
||||
opts.headers = {
|
||||
'Sec-WebSocket-Version': opts.protocolVersion,
|
||||
'Sec-WebSocket-Key': key,
|
||||
Connection: 'Upgrade',
|
||||
Upgrade: 'websocket',
|
||||
...opts.headers
|
||||
};
|
||||
opts.path = parsedUrl.pathname + parsedUrl.search;
|
||||
opts.timeout = opts.handshakeTimeout;
|
||||
|
||||
if (opts.perMessageDeflate) {
|
||||
@@ -525,7 +510,7 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
false,
|
||||
opts.maxPayload
|
||||
);
|
||||
opts.headers['Sec-WebSocket-Extensions'] = extension.format({
|
||||
opts.headers['Sec-WebSocket-Extensions'] = format({
|
||||
[PerMessageDeflate.extensionName]: perMessageDeflate.offer()
|
||||
});
|
||||
}
|
||||
@@ -539,20 +524,18 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
opts.headers.Origin = opts.origin;
|
||||
}
|
||||
}
|
||||
if (parsedUrl.auth) {
|
||||
opts.auth = parsedUrl.auth;
|
||||
} else if (parsedUrl.username || parsedUrl.password) {
|
||||
if (parsedUrl.username || parsedUrl.password) {
|
||||
opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
|
||||
}
|
||||
|
||||
if (isUnixSocket) {
|
||||
const parts = path.split(':');
|
||||
const parts = opts.path.split(':');
|
||||
|
||||
opts.socketPath = parts[0];
|
||||
opts.path = parts[1];
|
||||
}
|
||||
|
||||
var req = (websocket._req = get(opts));
|
||||
let req = (websocket._req = get(opts));
|
||||
|
||||
if (opts.timeout) {
|
||||
req.on('timeout', () => {
|
||||
@@ -586,9 +569,7 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
|
||||
req.abort();
|
||||
|
||||
const addr = url.URL
|
||||
? new url.URL(location, address)
|
||||
: url.resolve(address, location);
|
||||
const addr = new URL(location, address);
|
||||
|
||||
initAsClient(websocket, addr, protocols, options);
|
||||
} else if (!websocket.emit('unexpected-response', req, res)) {
|
||||
@@ -611,8 +592,7 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
|
||||
req = websocket._req = null;
|
||||
|
||||
const digest = crypto
|
||||
.createHash('sha1')
|
||||
const digest = createHash('sha1')
|
||||
.update(key + GUID)
|
||||
.digest('base64');
|
||||
|
||||
@@ -623,7 +603,7 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
|
||||
const serverProt = res.headers['sec-websocket-protocol'];
|
||||
const protList = (protocols || '').split(/, */);
|
||||
var protError;
|
||||
let protError;
|
||||
|
||||
if (!protocols && serverProt) {
|
||||
protError = 'Server sent a subprotocol but none was requested';
|
||||
@@ -642,9 +622,7 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
|
||||
if (perMessageDeflate) {
|
||||
try {
|
||||
const extensions = extension.parse(
|
||||
res.headers['sec-websocket-extensions']
|
||||
);
|
||||
const extensions = parse(res.headers['sec-websocket-extensions']);
|
||||
|
||||
if (extensions[PerMessageDeflate.extensionName]) {
|
||||
perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
|
||||
@@ -674,13 +652,7 @@ function initAsClient(websocket, address, protocols, options) {
|
||||
* @private
|
||||
*/
|
||||
function netConnect(options) {
|
||||
//
|
||||
// Override `options.path` only if `options` is a copy of the original options
|
||||
// object. This is always true on Node.js >= 8 but not on Node.js 6 where
|
||||
// `options.socketPath` might be `undefined` even if the `socketPath` option
|
||||
// was originally set.
|
||||
//
|
||||
if (options.protocolVersion) options.path = options.socketPath;
|
||||
options.path = options.socketPath;
|
||||
return net.connect(options);
|
||||
}
|
||||
|
||||
@@ -693,7 +665,11 @@ function netConnect(options) {
|
||||
*/
|
||||
function tlsConnect(options) {
|
||||
options.path = undefined;
|
||||
options.servername = options.servername || options.host;
|
||||
|
||||
if (!options.servername && options.servername !== '') {
|
||||
options.servername = options.host;
|
||||
}
|
||||
|
||||
return tls.connect(options);
|
||||
}
|
||||
|
||||
@@ -723,6 +699,38 @@ function abortHandshake(websocket, stream, message) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cases where the `ping()`, `pong()`, or `send()` methods are called
|
||||
* when the `readyState` attribute is `CLOSING` or `CLOSED`.
|
||||
*
|
||||
* @param {WebSocket} websocket The WebSocket instance
|
||||
* @param {*} data The data to send
|
||||
* @param {Function} cb Callback
|
||||
* @private
|
||||
*/
|
||||
function sendAfterClose(websocket, data, cb) {
|
||||
if (data) {
|
||||
const length = toBuffer(data).length;
|
||||
|
||||
//
|
||||
// The `_bufferedAmount` property is used only when the peer is a client and
|
||||
// the opening handshake fails. Under these circumstances, in fact, the
|
||||
// `setSocket()` method is not called, so the `_socket` and `_sender`
|
||||
// properties are set to `null`.
|
||||
//
|
||||
if (websocket._socket) websocket._sender._bufferedBytes += length;
|
||||
else websocket._bufferedAmount += length;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
const err = new Error(
|
||||
`WebSocket is not open: readyState ${websocket.readyState} ` +
|
||||
`(${readyStates[websocket.readyState]})`
|
||||
);
|
||||
cb(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener of the `Receiver` `'conclude'` event.
|
||||
*
|
||||
@@ -890,6 +898,8 @@ function socketOnError() {
|
||||
this.removeListener('error', socketOnError);
|
||||
this.on('error', NOOP);
|
||||
|
||||
websocket.readyState = WebSocket.CLOSING;
|
||||
this.destroy();
|
||||
if (websocket) {
|
||||
websocket.readyState = WebSocket.CLOSING;
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user