mirror of
				https://github.com/musix-org/musix-oss
				synced 2025-11-04 09:49:32 +00:00 
			
		
		
		
	Updated everything
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								node_modules/ws/lib/.DS_Store
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								node_modules/ws/lib/.DS_Store
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										65
									
								
								node_modules/ws/lib/buffer-util.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								node_modules/ws/lib/buffer-util.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,65 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const safeBuffer = require('safe-buffer');
 | 
			
		||||
 | 
			
		||||
const Buffer = safeBuffer.Buffer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Merges an array of buffers into a new buffer.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Buffer[]} list The array of buffers to concat
 | 
			
		||||
 * @param {Number} totalLength The total length of buffers in the list
 | 
			
		||||
 * @return {Buffer} The resulting buffer
 | 
			
		||||
 * @public
 | 
			
		||||
 */
 | 
			
		||||
const concat = (list, totalLength) => {
 | 
			
		||||
  const target = Buffer.allocUnsafe(totalLength);
 | 
			
		||||
  var offset = 0;
 | 
			
		||||
 | 
			
		||||
  for (var i = 0; i < list.length; i++) {
 | 
			
		||||
    const buf = list[i];
 | 
			
		||||
    buf.copy(target, offset);
 | 
			
		||||
    offset += buf.length;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return target;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
  const bufferUtil = require('bufferutil');
 | 
			
		||||
 | 
			
		||||
  module.exports = Object.assign({ concat }, bufferUtil.BufferUtil || bufferUtil);
 | 
			
		||||
} catch (e) /* istanbul ignore next */ {
 | 
			
		||||
  /**
 | 
			
		||||
   * Masks a buffer using the given mask.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} source The buffer to mask
 | 
			
		||||
   * @param {Buffer} mask The mask to use
 | 
			
		||||
   * @param {Buffer} output The buffer where to store the result
 | 
			
		||||
   * @param {Number} offset The offset at which to start writing
 | 
			
		||||
   * @param {Number} length The number of bytes to mask.
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  const mask = (source, mask, output, offset, length) => {
 | 
			
		||||
    for (var i = 0; i < length; i++) {
 | 
			
		||||
      output[offset + i] = source[i] ^ mask[i & 3];
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Unmasks a buffer using the given mask.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} buffer The buffer to unmask
 | 
			
		||||
   * @param {Buffer} mask The mask to use
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  const 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++) {
 | 
			
		||||
      buffer[i] ^= mask[i & 3];
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  module.exports = { concat, mask, unmask };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								node_modules/ws/lib/constants.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								node_modules/ws/lib/constants.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,10 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const safeBuffer = require('safe-buffer');
 | 
			
		||||
 | 
			
		||||
const Buffer = safeBuffer.Buffer;
 | 
			
		||||
 | 
			
		||||
exports.BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];
 | 
			
		||||
exports.GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
 | 
			
		||||
exports.EMPTY_BUFFER = Buffer.alloc(0);
 | 
			
		||||
exports.NOOP = () => {};
 | 
			
		||||
							
								
								
									
										170
									
								
								node_modules/ws/lib/event-target.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										170
									
								
								node_modules/ws/lib/event-target.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,170 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing an event.
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
class Event {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new `Event`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {String} type The name of the event
 | 
			
		||||
   * @param {Object} target A reference to the target to which the event was dispatched
 | 
			
		||||
   */
 | 
			
		||||
  constructor (type, target) {
 | 
			
		||||
    this.target = target;
 | 
			
		||||
    this.type = type;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing a message event.
 | 
			
		||||
 *
 | 
			
		||||
 * @extends Event
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
class MessageEvent extends Event {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new `MessageEvent`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data
 | 
			
		||||
   * @param {WebSocket} target A reference to the target to which the event was dispatched
 | 
			
		||||
   */
 | 
			
		||||
  constructor (data, target) {
 | 
			
		||||
    super('message', target);
 | 
			
		||||
 | 
			
		||||
    this.data = data;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing a close event.
 | 
			
		||||
 *
 | 
			
		||||
 * @extends Event
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
class CloseEvent extends Event {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new `CloseEvent`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Number} code The status code explaining why the connection is being closed
 | 
			
		||||
   * @param {String} reason A human-readable string explaining why the connection is closing
 | 
			
		||||
   * @param {WebSocket} target A reference to the target to which the event was dispatched
 | 
			
		||||
   */
 | 
			
		||||
  constructor (code, reason, target) {
 | 
			
		||||
    super('close', target);
 | 
			
		||||
 | 
			
		||||
    this.wasClean = target._closeFrameReceived && target._closeFrameSent;
 | 
			
		||||
    this.reason = reason;
 | 
			
		||||
    this.code = code;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing an open event.
 | 
			
		||||
 *
 | 
			
		||||
 * @extends Event
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
class OpenEvent extends Event {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new `OpenEvent`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {WebSocket} target A reference to the target to which the event was dispatched
 | 
			
		||||
   */
 | 
			
		||||
  constructor (target) {
 | 
			
		||||
    super('open', target);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing an error event.
 | 
			
		||||
 *
 | 
			
		||||
 * @extends Event
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
class ErrorEvent extends Event {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new `ErrorEvent`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Object} error The error that generated this event
 | 
			
		||||
   * @param {WebSocket} target A reference to the target to which the event was dispatched
 | 
			
		||||
   */
 | 
			
		||||
  constructor (error, target) {
 | 
			
		||||
    super('error', target);
 | 
			
		||||
 | 
			
		||||
    this.message = error.message;
 | 
			
		||||
    this.error = error;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This provides methods for emulating the `EventTarget` interface. It's not
 | 
			
		||||
 * meant to be used directly.
 | 
			
		||||
 *
 | 
			
		||||
 * @mixin
 | 
			
		||||
 */
 | 
			
		||||
const EventTarget = {
 | 
			
		||||
  /**
 | 
			
		||||
   * Register an event listener.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {String} method A string representing the event type to listen for
 | 
			
		||||
   * @param {Function} listener The listener to add
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  addEventListener (method, listener) {
 | 
			
		||||
    if (typeof listener !== 'function') return;
 | 
			
		||||
 | 
			
		||||
    function onMessage (data) {
 | 
			
		||||
      listener.call(this, new MessageEvent(data, this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onClose (code, message) {
 | 
			
		||||
      listener.call(this, new CloseEvent(code, message, this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onError (error) {
 | 
			
		||||
      listener.call(this, new ErrorEvent(error, this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onOpen () {
 | 
			
		||||
      listener.call(this, new OpenEvent(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (method === 'message') {
 | 
			
		||||
      onMessage._listener = listener;
 | 
			
		||||
      this.on(method, onMessage);
 | 
			
		||||
    } else if (method === 'close') {
 | 
			
		||||
      onClose._listener = listener;
 | 
			
		||||
      this.on(method, onClose);
 | 
			
		||||
    } else if (method === 'error') {
 | 
			
		||||
      onError._listener = listener;
 | 
			
		||||
      this.on(method, onError);
 | 
			
		||||
    } else if (method === 'open') {
 | 
			
		||||
      onOpen._listener = listener;
 | 
			
		||||
      this.on(method, onOpen);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.on(method, listener);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Remove an event listener.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {String} method A string representing the event type to remove
 | 
			
		||||
   * @param {Function} listener The listener to remove
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  removeEventListener (method, listener) {
 | 
			
		||||
    const listeners = this.listeners(method);
 | 
			
		||||
 | 
			
		||||
    for (var i = 0; i < listeners.length; i++) {
 | 
			
		||||
      if (listeners[i] === listener || listeners[i]._listener === listener) {
 | 
			
		||||
        this.removeListener(method, listeners[i]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = EventTarget;
 | 
			
		||||
							
								
								
									
										211
									
								
								node_modules/ws/lib/extension.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										211
									
								
								node_modules/ws/lib/extension.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,211 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Allowed token characters:
 | 
			
		||||
//
 | 
			
		||||
// '!', '#', '$', '%', '&', ''', '*', '+', '-',
 | 
			
		||||
// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
 | 
			
		||||
//
 | 
			
		||||
// tokenChars[32] === 0 // ' '
 | 
			
		||||
// tokenChars[33] === 1 // '!'
 | 
			
		||||
// tokenChars[34] === 0 // '"'
 | 
			
		||||
// ...
 | 
			
		||||
//
 | 
			
		||||
const tokenChars = [
 | 
			
		||||
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
 | 
			
		||||
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
 | 
			
		||||
  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
 | 
			
		||||
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
 | 
			
		||||
  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
 | 
			
		||||
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
 | 
			
		||||
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
 | 
			
		||||
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adds an offer to the map of extension offers or a parameter to the map of
 | 
			
		||||
 * parameters.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Object} dest The map of extension offers or parameters
 | 
			
		||||
 * @param {String} name The extension or parameter name
 | 
			
		||||
 * @param {(Object|Boolean|String)} elem The extension parameters or the
 | 
			
		||||
 *     parameter value
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function push (dest, name, elem) {
 | 
			
		||||
  if (Object.prototype.hasOwnProperty.call(dest, name)) dest[name].push(elem);
 | 
			
		||||
  else dest[name] = [elem];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parses the `Sec-WebSocket-Extensions` header into an object.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} header The field value of the header
 | 
			
		||||
 * @return {Object} The parsed object
 | 
			
		||||
 * @public
 | 
			
		||||
 */
 | 
			
		||||
function parse (header) {
 | 
			
		||||
  const offers = {};
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  for (var i = 0; i < header.length; i++) {
 | 
			
		||||
    const code = header.charCodeAt(i);
 | 
			
		||||
 | 
			
		||||
    if (extensionName === undefined) {
 | 
			
		||||
      if (end === -1 && tokenChars[code] === 1) {
 | 
			
		||||
        if (start === -1) start = i;
 | 
			
		||||
      } else if (code === 0x20/* ' ' */|| code === 0x09/* '\t' */) {
 | 
			
		||||
        if (end === -1 && start !== -1) end = i;
 | 
			
		||||
      } else if (code === 0x3b/* ';' */ || code === 0x2c/* ',' */) {
 | 
			
		||||
        if (start === -1) {
 | 
			
		||||
          throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (end === -1) end = i;
 | 
			
		||||
        const name = header.slice(start, end);
 | 
			
		||||
        if (code === 0x2c) {
 | 
			
		||||
          push(offers, name, params);
 | 
			
		||||
          params = {};
 | 
			
		||||
        } else {
 | 
			
		||||
          extensionName = name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        start = end = -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (paramName === undefined) {
 | 
			
		||||
      if (end === -1 && tokenChars[code] === 1) {
 | 
			
		||||
        if (start === -1) start = i;
 | 
			
		||||
      } else if (code === 0x20 || code === 0x09) {
 | 
			
		||||
        if (end === -1 && start !== -1) end = i;
 | 
			
		||||
      } else if (code === 0x3b || code === 0x2c) {
 | 
			
		||||
        if (start === -1) {
 | 
			
		||||
          throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (end === -1) end = i;
 | 
			
		||||
        push(params, header.slice(start, end), true);
 | 
			
		||||
        if (code === 0x2c) {
 | 
			
		||||
          push(offers, extensionName, params);
 | 
			
		||||
          params = {};
 | 
			
		||||
          extensionName = undefined;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        start = end = -1;
 | 
			
		||||
      } else if (code === 0x3d/* '=' */&& start !== -1 && end === -1) {
 | 
			
		||||
        paramName = header.slice(start, i);
 | 
			
		||||
        start = end = -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      //
 | 
			
		||||
      // The value of a quoted-string after unescaping must conform to the
 | 
			
		||||
      // token ABNF, so only token characters are valid.
 | 
			
		||||
      // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
 | 
			
		||||
      //
 | 
			
		||||
      if (isEscaping) {
 | 
			
		||||
        if (tokenChars[code] !== 1) {
 | 
			
		||||
          throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
        }
 | 
			
		||||
        if (start === -1) start = i;
 | 
			
		||||
        else if (!mustUnescape) mustUnescape = true;
 | 
			
		||||
        isEscaping = false;
 | 
			
		||||
      } else if (inQuotes) {
 | 
			
		||||
        if (tokenChars[code] === 1) {
 | 
			
		||||
          if (start === -1) start = i;
 | 
			
		||||
        } else if (code === 0x22/* '"' */ && start !== -1) {
 | 
			
		||||
          inQuotes = false;
 | 
			
		||||
          end = i;
 | 
			
		||||
        } else if (code === 0x5c/* '\' */) {
 | 
			
		||||
          isEscaping = true;
 | 
			
		||||
        } else {
 | 
			
		||||
          throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
        }
 | 
			
		||||
      } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
 | 
			
		||||
        inQuotes = true;
 | 
			
		||||
      } else if (end === -1 && tokenChars[code] === 1) {
 | 
			
		||||
        if (start === -1) start = i;
 | 
			
		||||
      } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
 | 
			
		||||
        if (end === -1) end = i;
 | 
			
		||||
      } else if (code === 0x3b || code === 0x2c) {
 | 
			
		||||
        if (start === -1) {
 | 
			
		||||
          throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (end === -1) end = i;
 | 
			
		||||
        var value = header.slice(start, end);
 | 
			
		||||
        if (mustUnescape) {
 | 
			
		||||
          value = value.replace(/\\/g, '');
 | 
			
		||||
          mustUnescape = false;
 | 
			
		||||
        }
 | 
			
		||||
        push(params, paramName, value);
 | 
			
		||||
        if (code === 0x2c) {
 | 
			
		||||
          push(offers, extensionName, params);
 | 
			
		||||
          params = {};
 | 
			
		||||
          extensionName = undefined;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        paramName = undefined;
 | 
			
		||||
        start = end = -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new SyntaxError(`Unexpected character at index ${i}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (start === -1 || inQuotes) {
 | 
			
		||||
    throw new SyntaxError('Unexpected end of input');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (end === -1) end = i;
 | 
			
		||||
  const token = header.slice(start, end);
 | 
			
		||||
  if (extensionName === undefined) {
 | 
			
		||||
    push(offers, token, {});
 | 
			
		||||
  } else {
 | 
			
		||||
    if (paramName === undefined) {
 | 
			
		||||
      push(params, token, true);
 | 
			
		||||
    } else if (mustUnescape) {
 | 
			
		||||
      push(params, paramName, token.replace(/\\/g, ''));
 | 
			
		||||
    } else {
 | 
			
		||||
      push(params, paramName, token);
 | 
			
		||||
    }
 | 
			
		||||
    push(offers, extensionName, params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return offers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Builds the `Sec-WebSocket-Extensions` header field value.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Object} extensions The map of extensions and parameters to format
 | 
			
		||||
 * @return {String} A string representing the given object
 | 
			
		||||
 * @public
 | 
			
		||||
 */
 | 
			
		||||
function format (extensions) {
 | 
			
		||||
  return Object.keys(extensions).map((extension) => {
 | 
			
		||||
    var 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];
 | 
			
		||||
        if (!Array.isArray(values)) values = [values];
 | 
			
		||||
        return values.map((v) => v === true ? k : `${k}=${v}`).join('; ');
 | 
			
		||||
      })).join('; ');
 | 
			
		||||
    }).join(', ');
 | 
			
		||||
  }).join(', ');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = { format, parse };
 | 
			
		||||
							
								
								
									
										521
									
								
								node_modules/ws/lib/permessage-deflate.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										521
									
								
								node_modules/ws/lib/permessage-deflate.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,521 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const safeBuffer = require('safe-buffer');
 | 
			
		||||
const Limiter = require('async-limiter');
 | 
			
		||||
const zlib = require('zlib');
 | 
			
		||||
 | 
			
		||||
const bufferUtil = require('./buffer-util');
 | 
			
		||||
 | 
			
		||||
const Buffer = safeBuffer.Buffer;
 | 
			
		||||
 | 
			
		||||
const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
 | 
			
		||||
const EMPTY_BLOCK = Buffer.from([0x00]);
 | 
			
		||||
 | 
			
		||||
const kWriteInProgress = Symbol('write-in-progress');
 | 
			
		||||
const kPendingClose = Symbol('pending-close');
 | 
			
		||||
const kTotalLength = Symbol('total-length');
 | 
			
		||||
const kCallback = Symbol('callback');
 | 
			
		||||
const kBuffers = Symbol('buffers');
 | 
			
		||||
const kError = Symbol('error');
 | 
			
		||||
const kOwner = Symbol('owner');
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// We limit zlib concurrency, which prevents severe memory fragmentation
 | 
			
		||||
// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
 | 
			
		||||
// and https://github.com/websockets/ws/issues/1202
 | 
			
		||||
//
 | 
			
		||||
// Intentionally global; it's the global thread pool that's an issue.
 | 
			
		||||
//
 | 
			
		||||
let zlibLimiter;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * permessage-deflate implementation.
 | 
			
		||||
 */
 | 
			
		||||
class PerMessageDeflate {
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates a PerMessageDeflate instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Object} options Configuration options
 | 
			
		||||
   * @param {Boolean} options.serverNoContextTakeover Request/accept disabling
 | 
			
		||||
   *     of server context takeover
 | 
			
		||||
   * @param {Boolean} options.clientNoContextTakeover Advertise/acknowledge
 | 
			
		||||
   *     disabling of client context takeover
 | 
			
		||||
   * @param {(Boolean|Number)} options.serverMaxWindowBits Request/confirm the
 | 
			
		||||
   *     use of a custom server window size
 | 
			
		||||
   * @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 deflate
 | 
			
		||||
   * @param {Object} options.zlibInflateOptions Options to pass to zlib on inflate
 | 
			
		||||
   * @param {Number} options.threshold Size (in bytes) below which messages
 | 
			
		||||
   *     should not be compressed
 | 
			
		||||
   * @param {Number} options.concurrencyLimit The number of concurrent calls to
 | 
			
		||||
   *     zlib
 | 
			
		||||
   * @param {Boolean} isServer Create the instance in either server or client
 | 
			
		||||
   *     mode
 | 
			
		||||
   * @param {Number} maxPayload The maximum allowed message length
 | 
			
		||||
   */
 | 
			
		||||
  constructor (options, isServer, maxPayload) {
 | 
			
		||||
    this._maxPayload = maxPayload | 0;
 | 
			
		||||
    this._options = options || {};
 | 
			
		||||
    this._threshold = this._options.threshold !== undefined
 | 
			
		||||
      ? this._options.threshold
 | 
			
		||||
      : 1024;
 | 
			
		||||
    this._isServer = !!isServer;
 | 
			
		||||
    this._deflate = null;
 | 
			
		||||
    this._inflate = null;
 | 
			
		||||
 | 
			
		||||
    this.params = null;
 | 
			
		||||
 | 
			
		||||
    if (!zlibLimiter) {
 | 
			
		||||
      const concurrency = this._options.concurrencyLimit !== undefined
 | 
			
		||||
        ? this._options.concurrencyLimit
 | 
			
		||||
        : 10;
 | 
			
		||||
      zlibLimiter = new Limiter({ concurrency });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @type {String}
 | 
			
		||||
   */
 | 
			
		||||
  static get extensionName () {
 | 
			
		||||
    return 'permessage-deflate';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Create an extension negotiation offer.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {Object} Extension parameters
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  offer () {
 | 
			
		||||
    const params = {};
 | 
			
		||||
 | 
			
		||||
    if (this._options.serverNoContextTakeover) {
 | 
			
		||||
      params.server_no_context_takeover = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (this._options.clientNoContextTakeover) {
 | 
			
		||||
      params.client_no_context_takeover = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (this._options.serverMaxWindowBits) {
 | 
			
		||||
      params.server_max_window_bits = this._options.serverMaxWindowBits;
 | 
			
		||||
    }
 | 
			
		||||
    if (this._options.clientMaxWindowBits) {
 | 
			
		||||
      params.client_max_window_bits = this._options.clientMaxWindowBits;
 | 
			
		||||
    } else if (this._options.clientMaxWindowBits == null) {
 | 
			
		||||
      params.client_max_window_bits = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Accept an extension negotiation offer/response.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Array} configurations The extension negotiation offers/reponse
 | 
			
		||||
   * @return {Object} Accepted configuration
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  accept (configurations) {
 | 
			
		||||
    configurations = this.normalizeParams(configurations);
 | 
			
		||||
 | 
			
		||||
    this.params = this._isServer
 | 
			
		||||
      ? this.acceptAsServer(configurations)
 | 
			
		||||
      : this.acceptAsClient(configurations);
 | 
			
		||||
 | 
			
		||||
    return this.params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Releases all resources used by the extension.
 | 
			
		||||
   *
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  cleanup () {
 | 
			
		||||
    if (this._inflate) {
 | 
			
		||||
      if (this._inflate[kWriteInProgress]) {
 | 
			
		||||
        this._inflate[kPendingClose] = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        this._inflate.close();
 | 
			
		||||
        this._inflate = null;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (this._deflate) {
 | 
			
		||||
      if (this._deflate[kWriteInProgress]) {
 | 
			
		||||
        this._deflate[kPendingClose] = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        this._deflate.close();
 | 
			
		||||
        this._deflate = null;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   *  Accept an extension negotiation offer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Array} offers The extension negotiation offers
 | 
			
		||||
   * @return {Object} Accepted configuration
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  acceptAsServer (offers) {
 | 
			
		||||
    const opts = this._options;
 | 
			
		||||
    const accepted = offers.find((params) => {
 | 
			
		||||
      if (
 | 
			
		||||
        (opts.serverNoContextTakeover === false &&
 | 
			
		||||
          params.server_no_context_takeover) ||
 | 
			
		||||
        (params.server_max_window_bits &&
 | 
			
		||||
          (opts.serverMaxWindowBits === false ||
 | 
			
		||||
            (typeof opts.serverMaxWindowBits === 'number' &&
 | 
			
		||||
              opts.serverMaxWindowBits > params.server_max_window_bits))) ||
 | 
			
		||||
        (typeof opts.clientMaxWindowBits === 'number' &&
 | 
			
		||||
          !params.client_max_window_bits)
 | 
			
		||||
      ) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!accepted) {
 | 
			
		||||
      throw new Error('None of the extension offers can be accepted');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (opts.serverNoContextTakeover) {
 | 
			
		||||
      accepted.server_no_context_takeover = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (opts.clientNoContextTakeover) {
 | 
			
		||||
      accepted.client_no_context_takeover = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof opts.serverMaxWindowBits === 'number') {
 | 
			
		||||
      accepted.server_max_window_bits = opts.serverMaxWindowBits;
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof opts.clientMaxWindowBits === 'number') {
 | 
			
		||||
      accepted.client_max_window_bits = opts.clientMaxWindowBits;
 | 
			
		||||
    } else if (
 | 
			
		||||
      accepted.client_max_window_bits === true ||
 | 
			
		||||
      opts.clientMaxWindowBits === false
 | 
			
		||||
    ) {
 | 
			
		||||
      delete accepted.client_max_window_bits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return accepted;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Accept the extension negotiation response.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Array} response The extension negotiation response
 | 
			
		||||
   * @return {Object} Accepted configuration
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  acceptAsClient (response) {
 | 
			
		||||
    const params = response[0];
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      this._options.clientNoContextTakeover === false &&
 | 
			
		||||
      params.client_no_context_takeover
 | 
			
		||||
    ) {
 | 
			
		||||
      throw new Error('Unexpected parameter "client_no_context_takeover"');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!params.client_max_window_bits) {
 | 
			
		||||
      if (typeof this._options.clientMaxWindowBits === 'number') {
 | 
			
		||||
        params.client_max_window_bits = this._options.clientMaxWindowBits;
 | 
			
		||||
      }
 | 
			
		||||
    } else if (
 | 
			
		||||
      this._options.clientMaxWindowBits === false ||
 | 
			
		||||
      (typeof this._options.clientMaxWindowBits === 'number' &&
 | 
			
		||||
        params.client_max_window_bits > this._options.clientMaxWindowBits)
 | 
			
		||||
    ) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        'Unexpected or invalid parameter "client_max_window_bits"'
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return params;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Normalize parameters.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Array} configurations The extension negotiation offers/reponse
 | 
			
		||||
   * @return {Array} The offers/response with normalized parameters
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  normalizeParams (configurations) {
 | 
			
		||||
    configurations.forEach((params) => {
 | 
			
		||||
      Object.keys(params).forEach((key) => {
 | 
			
		||||
        var value = params[key];
 | 
			
		||||
 | 
			
		||||
        if (value.length > 1) {
 | 
			
		||||
          throw new Error(`Parameter "${key}" must have only a single value`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        value = value[0];
 | 
			
		||||
 | 
			
		||||
        if (key === 'client_max_window_bits') {
 | 
			
		||||
          if (value !== true) {
 | 
			
		||||
            const num = +value;
 | 
			
		||||
            if (!Number.isInteger(num) || num < 8 || num > 15) {
 | 
			
		||||
              throw new TypeError(
 | 
			
		||||
                `Invalid value for parameter "${key}": ${value}`
 | 
			
		||||
              );
 | 
			
		||||
            }
 | 
			
		||||
            value = num;
 | 
			
		||||
          } else if (!this._isServer) {
 | 
			
		||||
            throw new TypeError(
 | 
			
		||||
              `Invalid value for parameter "${key}": ${value}`
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
        } else if (key === 'server_max_window_bits') {
 | 
			
		||||
          const num = +value;
 | 
			
		||||
          if (!Number.isInteger(num) || num < 8 || num > 15) {
 | 
			
		||||
            throw new TypeError(
 | 
			
		||||
              `Invalid value for parameter "${key}": ${value}`
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
          value = num;
 | 
			
		||||
        } else if (
 | 
			
		||||
          key === 'client_no_context_takeover' ||
 | 
			
		||||
          key === 'server_no_context_takeover'
 | 
			
		||||
        ) {
 | 
			
		||||
          if (value !== true) {
 | 
			
		||||
            throw new TypeError(
 | 
			
		||||
              `Invalid value for parameter "${key}": ${value}`
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          throw new Error(`Unknown parameter "${key}"`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        params[key] = value;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return configurations;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Decompress data. Concurrency limited by async-limiter.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data Compressed data
 | 
			
		||||
   * @param {Boolean} fin Specifies whether or not this is the last fragment
 | 
			
		||||
   * @param {Function} callback Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  decompress (data, fin, callback) {
 | 
			
		||||
    zlibLimiter.push((done) => {
 | 
			
		||||
      this._decompress(data, fin, (err, result) => {
 | 
			
		||||
        done();
 | 
			
		||||
        callback(err, result);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Compress data. Concurrency limited by async-limiter.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data Data to compress
 | 
			
		||||
   * @param {Boolean} fin Specifies whether or not this is the last fragment
 | 
			
		||||
   * @param {Function} callback Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  compress (data, fin, callback) {
 | 
			
		||||
    zlibLimiter.push((done) => {
 | 
			
		||||
      this._compress(data, fin, (err, result) => {
 | 
			
		||||
        done();
 | 
			
		||||
        callback(err, result);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Decompress data.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data Compressed data
 | 
			
		||||
   * @param {Boolean} fin Specifies whether or not this is the last fragment
 | 
			
		||||
   * @param {Function} callback Callback
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  _decompress (data, fin, callback) {
 | 
			
		||||
    const endpoint = this._isServer ? 'client' : 'server';
 | 
			
		||||
 | 
			
		||||
    if (!this._inflate) {
 | 
			
		||||
      const key = `${endpoint}_max_window_bits`;
 | 
			
		||||
      const windowBits = typeof this.params[key] !== 'number'
 | 
			
		||||
        ? zlib.Z_DEFAULT_WINDOWBITS
 | 
			
		||||
        : this.params[key];
 | 
			
		||||
 | 
			
		||||
      this._inflate = zlib.createInflateRaw(
 | 
			
		||||
        Object.assign(
 | 
			
		||||
          {},
 | 
			
		||||
          this._options.zlibInflateOptions,
 | 
			
		||||
          { windowBits }
 | 
			
		||||
        )
 | 
			
		||||
      );
 | 
			
		||||
      this._inflate[kTotalLength] = 0;
 | 
			
		||||
      this._inflate[kBuffers] = [];
 | 
			
		||||
      this._inflate[kOwner] = this;
 | 
			
		||||
      this._inflate.on('error', inflateOnError);
 | 
			
		||||
      this._inflate.on('data', inflateOnData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._inflate[kCallback] = callback;
 | 
			
		||||
    this._inflate[kWriteInProgress] = true;
 | 
			
		||||
 | 
			
		||||
    this._inflate.write(data);
 | 
			
		||||
    if (fin) this._inflate.write(TRAILER);
 | 
			
		||||
 | 
			
		||||
    this._inflate.flush(() => {
 | 
			
		||||
      const err = this._inflate[kError];
 | 
			
		||||
 | 
			
		||||
      if (err) {
 | 
			
		||||
        this._inflate.close();
 | 
			
		||||
        this._inflate = null;
 | 
			
		||||
        callback(err);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const data = bufferUtil.concat(
 | 
			
		||||
        this._inflate[kBuffers],
 | 
			
		||||
        this._inflate[kTotalLength]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (
 | 
			
		||||
        (fin && this.params[`${endpoint}_no_context_takeover`]) ||
 | 
			
		||||
        this._inflate[kPendingClose]
 | 
			
		||||
      ) {
 | 
			
		||||
        this._inflate.close();
 | 
			
		||||
        this._inflate = null;
 | 
			
		||||
      } else {
 | 
			
		||||
        this._inflate[kWriteInProgress] = false;
 | 
			
		||||
        this._inflate[kTotalLength] = 0;
 | 
			
		||||
        this._inflate[kBuffers] = [];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      callback(null, data);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Compress data.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data Data to compress
 | 
			
		||||
   * @param {Boolean} fin Specifies whether or not this is the last fragment
 | 
			
		||||
   * @param {Function} callback Callback
 | 
			
		||||
   * @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) {
 | 
			
		||||
      const key = `${endpoint}_max_window_bits`;
 | 
			
		||||
      const windowBits = typeof this.params[key] !== 'number'
 | 
			
		||||
        ? zlib.Z_DEFAULT_WINDOWBITS
 | 
			
		||||
        : this.params[key];
 | 
			
		||||
 | 
			
		||||
      this._deflate = zlib.createDeflateRaw(
 | 
			
		||||
        Object.assign(
 | 
			
		||||
          // TODO deprecate memLevel/level and recommend zlibDeflateOptions instead
 | 
			
		||||
          {
 | 
			
		||||
            memLevel: this._options.memLevel,
 | 
			
		||||
            level: this._options.level
 | 
			
		||||
          },
 | 
			
		||||
          this._options.zlibDeflateOptions,
 | 
			
		||||
          { windowBits }
 | 
			
		||||
        )
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      this._deflate[kTotalLength] = 0;
 | 
			
		||||
      this._deflate[kBuffers] = [];
 | 
			
		||||
 | 
			
		||||
      //
 | 
			
		||||
      // `zlib.DeflateRaw` emits an `'error'` event only when an attempt to use
 | 
			
		||||
      // it is made after it has already been closed. This cannot happen here,
 | 
			
		||||
      // so we only add a listener for the `'data'` event.
 | 
			
		||||
      //
 | 
			
		||||
      this._deflate.on('data', deflateOnData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._deflate[kWriteInProgress] = true;
 | 
			
		||||
 | 
			
		||||
    this._deflate.write(data);
 | 
			
		||||
    this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
 | 
			
		||||
      var data = bufferUtil.concat(
 | 
			
		||||
        this._deflate[kBuffers],
 | 
			
		||||
        this._deflate[kTotalLength]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (fin) data = data.slice(0, data.length - 4);
 | 
			
		||||
 | 
			
		||||
      if (
 | 
			
		||||
        (fin && this.params[`${endpoint}_no_context_takeover`]) ||
 | 
			
		||||
        this._deflate[kPendingClose]
 | 
			
		||||
      ) {
 | 
			
		||||
        this._deflate.close();
 | 
			
		||||
        this._deflate = null;
 | 
			
		||||
      } else {
 | 
			
		||||
        this._deflate[kWriteInProgress] = false;
 | 
			
		||||
        this._deflate[kTotalLength] = 0;
 | 
			
		||||
        this._deflate[kBuffers] = [];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      callback(null, data);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = PerMessageDeflate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The listener of the `zlib.DeflateRaw` stream `'data'` event.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Buffer} chunk A chunk of data
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function deflateOnData (chunk) {
 | 
			
		||||
  this[kBuffers].push(chunk);
 | 
			
		||||
  this[kTotalLength] += chunk.length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The listener of the `zlib.InflateRaw` stream `'data'` event.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Buffer} chunk A chunk of data
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function inflateOnData (chunk) {
 | 
			
		||||
  this[kTotalLength] += chunk.length;
 | 
			
		||||
 | 
			
		||||
  if (
 | 
			
		||||
    this[kOwner]._maxPayload < 1 ||
 | 
			
		||||
    this[kTotalLength] <= this[kOwner]._maxPayload
 | 
			
		||||
  ) {
 | 
			
		||||
    this[kBuffers].push(chunk);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this[kError] = new RangeError('Max payload size exceeded');
 | 
			
		||||
  this[kError].closeCode = 1009;
 | 
			
		||||
  this.removeListener('data', inflateOnData);
 | 
			
		||||
  this.reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The listener of the `zlib.InflateRaw` stream `'error'` event.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Error} err The emitted error
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function inflateOnError (err) {
 | 
			
		||||
  //
 | 
			
		||||
  // There is no need to call `Zlib#close()` as the handle is automatically
 | 
			
		||||
  // closed when an error is emitted.
 | 
			
		||||
  //
 | 
			
		||||
  this[kOwner]._inflate = null;
 | 
			
		||||
  this[kCallback](err);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										589
									
								
								node_modules/ws/lib/receiver.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										589
									
								
								node_modules/ws/lib/receiver.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,589 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const safeBuffer = require('safe-buffer');
 | 
			
		||||
 | 
			
		||||
const PerMessageDeflate = require('./permessage-deflate');
 | 
			
		||||
const bufferUtil = require('./buffer-util');
 | 
			
		||||
const validation = require('./validation');
 | 
			
		||||
const constants = require('./constants');
 | 
			
		||||
 | 
			
		||||
const Buffer = safeBuffer.Buffer;
 | 
			
		||||
 | 
			
		||||
const GET_INFO = 0;
 | 
			
		||||
const GET_PAYLOAD_LENGTH_16 = 1;
 | 
			
		||||
const GET_PAYLOAD_LENGTH_64 = 2;
 | 
			
		||||
const GET_MASK = 3;
 | 
			
		||||
const GET_DATA = 4;
 | 
			
		||||
const INFLATING = 5;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * HyBi Receiver implementation.
 | 
			
		||||
 */
 | 
			
		||||
class Receiver {
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates a Receiver instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Object} extensions An object containing the negotiated extensions
 | 
			
		||||
   * @param {Number} maxPayload The maximum allowed message length
 | 
			
		||||
   * @param {String} binaryType The type for binary data
 | 
			
		||||
   */
 | 
			
		||||
  constructor (extensions, maxPayload, binaryType) {
 | 
			
		||||
    this._binaryType = binaryType || constants.BINARY_TYPES[0];
 | 
			
		||||
    this._extensions = extensions || {};
 | 
			
		||||
    this._maxPayload = maxPayload | 0;
 | 
			
		||||
 | 
			
		||||
    this._bufferedBytes = 0;
 | 
			
		||||
    this._buffers = [];
 | 
			
		||||
 | 
			
		||||
    this._compressed = false;
 | 
			
		||||
    this._payloadLength = 0;
 | 
			
		||||
    this._fragmented = 0;
 | 
			
		||||
    this._masked = false;
 | 
			
		||||
    this._fin = false;
 | 
			
		||||
    this._mask = null;
 | 
			
		||||
    this._opcode = 0;
 | 
			
		||||
 | 
			
		||||
    this._totalPayloadLength = 0;
 | 
			
		||||
    this._messageLength = 0;
 | 
			
		||||
    this._fragments = [];
 | 
			
		||||
 | 
			
		||||
    this._cleanupCallback = null;
 | 
			
		||||
    this._isCleaningUp = false;
 | 
			
		||||
    this._hadError = false;
 | 
			
		||||
    this._loop = false;
 | 
			
		||||
 | 
			
		||||
    this.add = this.add.bind(this);
 | 
			
		||||
    this.onmessage = null;
 | 
			
		||||
    this.onclose = null;
 | 
			
		||||
    this.onerror = null;
 | 
			
		||||
    this.onping = null;
 | 
			
		||||
    this.onpong = null;
 | 
			
		||||
 | 
			
		||||
    this._state = GET_INFO;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Consumes `n` bytes from the buffered data, calls `cleanup` if necessary.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Number} n The number of bytes to consume
 | 
			
		||||
   * @return {(Buffer|null)} The consumed bytes or `null` if `n` bytes are not
 | 
			
		||||
   *     available
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  consume (n) {
 | 
			
		||||
    if (this._bufferedBytes < n) {
 | 
			
		||||
      this._loop = false;
 | 
			
		||||
      if (this._isCleaningUp) this.cleanup(this._cleanupCallback);
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._bufferedBytes -= n;
 | 
			
		||||
 | 
			
		||||
    if (n === this._buffers[0].length) return this._buffers.shift();
 | 
			
		||||
 | 
			
		||||
    if (n < this._buffers[0].length) {
 | 
			
		||||
      const buf = this._buffers[0];
 | 
			
		||||
      this._buffers[0] = buf.slice(n);
 | 
			
		||||
      return buf.slice(0, n);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const dst = Buffer.allocUnsafe(n);
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
      const buf = this._buffers[0];
 | 
			
		||||
 | 
			
		||||
      if (n >= buf.length) {
 | 
			
		||||
        this._buffers.shift().copy(dst, dst.length - n);
 | 
			
		||||
      } else {
 | 
			
		||||
        buf.copy(dst, dst.length - n, 0, n);
 | 
			
		||||
        this._buffers[0] = buf.slice(n);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      n -= buf.length;
 | 
			
		||||
    } while (n > 0);
 | 
			
		||||
 | 
			
		||||
    return dst;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Adds new data to the parser.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} chunk A chunk of data
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  add (chunk) {
 | 
			
		||||
    this._bufferedBytes += chunk.length;
 | 
			
		||||
    this._buffers.push(chunk);
 | 
			
		||||
    this.startLoop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Starts the parsing loop.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  startLoop () {
 | 
			
		||||
    this._loop = true;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
      switch (this._state) {
 | 
			
		||||
        case GET_INFO:
 | 
			
		||||
          this.getInfo();
 | 
			
		||||
          break;
 | 
			
		||||
        case GET_PAYLOAD_LENGTH_16:
 | 
			
		||||
          this.getPayloadLength16();
 | 
			
		||||
          break;
 | 
			
		||||
        case GET_PAYLOAD_LENGTH_64:
 | 
			
		||||
          this.getPayloadLength64();
 | 
			
		||||
          break;
 | 
			
		||||
        case GET_MASK:
 | 
			
		||||
          this.getMask();
 | 
			
		||||
          break;
 | 
			
		||||
        case GET_DATA:
 | 
			
		||||
          this.getData();
 | 
			
		||||
          break;
 | 
			
		||||
        default: // `INFLATING`
 | 
			
		||||
          this._loop = false;
 | 
			
		||||
      }
 | 
			
		||||
    } while (this._loop);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Reads the first two bytes of a frame.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  getInfo () {
 | 
			
		||||
    const buf = this.consume(2);
 | 
			
		||||
    if (buf === null) return;
 | 
			
		||||
 | 
			
		||||
    if ((buf[0] & 0x30) !== 0x00) {
 | 
			
		||||
      this.error(
 | 
			
		||||
        new RangeError('Invalid WebSocket frame: RSV2 and RSV3 must be clear'),
 | 
			
		||||
        1002
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const compressed = (buf[0] & 0x40) === 0x40;
 | 
			
		||||
 | 
			
		||||
    if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
 | 
			
		||||
      this.error(
 | 
			
		||||
        new RangeError('Invalid WebSocket frame: RSV1 must be clear'),
 | 
			
		||||
        1002
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._fin = (buf[0] & 0x80) === 0x80;
 | 
			
		||||
    this._opcode = buf[0] & 0x0f;
 | 
			
		||||
    this._payloadLength = buf[1] & 0x7f;
 | 
			
		||||
 | 
			
		||||
    if (this._opcode === 0x00) {
 | 
			
		||||
      if (compressed) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError('Invalid WebSocket frame: RSV1 must be clear'),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!this._fragmented) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError('Invalid WebSocket frame: invalid opcode 0'),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      } else {
 | 
			
		||||
        this._opcode = this._fragmented;
 | 
			
		||||
      }
 | 
			
		||||
    } else if (this._opcode === 0x01 || this._opcode === 0x02) {
 | 
			
		||||
      if (this._fragmented) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError(
 | 
			
		||||
            `Invalid WebSocket frame: invalid opcode ${this._opcode}`
 | 
			
		||||
          ),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this._compressed = compressed;
 | 
			
		||||
    } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
 | 
			
		||||
      if (!this._fin) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError('Invalid WebSocket frame: FIN must be set'),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (compressed) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError('Invalid WebSocket frame: RSV1 must be clear'),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this._payloadLength > 0x7d) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError(
 | 
			
		||||
            `Invalid WebSocket frame: invalid payload length ` +
 | 
			
		||||
              `${this._payloadLength}`
 | 
			
		||||
          ),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      this.error(
 | 
			
		||||
        new RangeError(
 | 
			
		||||
          `Invalid WebSocket frame: invalid opcode ${this._opcode}`
 | 
			
		||||
        ),
 | 
			
		||||
        1002
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
 | 
			
		||||
 | 
			
		||||
    this._masked = (buf[1] & 0x80) === 0x80;
 | 
			
		||||
 | 
			
		||||
    if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
 | 
			
		||||
    else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
 | 
			
		||||
    else this.haveLength();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Gets extended payload length (7+16).
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  getPayloadLength16 () {
 | 
			
		||||
    const buf = this.consume(2);
 | 
			
		||||
    if (buf === null) return;
 | 
			
		||||
 | 
			
		||||
    this._payloadLength = buf.readUInt16BE(0, true);
 | 
			
		||||
    this.haveLength();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Gets extended payload length (7+64).
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  getPayloadLength64 () {
 | 
			
		||||
    const buf = this.consume(8);
 | 
			
		||||
    if (buf === null) return;
 | 
			
		||||
 | 
			
		||||
    const num = buf.readUInt32BE(0, true);
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
 | 
			
		||||
    // if payload length is greater than this number.
 | 
			
		||||
    //
 | 
			
		||||
    if (num > Math.pow(2, 53 - 32) - 1) {
 | 
			
		||||
      this.error(
 | 
			
		||||
        new RangeError(
 | 
			
		||||
          'Unsupported WebSocket frame: payload length > 2^53 - 1'
 | 
			
		||||
        ),
 | 
			
		||||
        1009
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4, true);
 | 
			
		||||
    this.haveLength();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Payload length has been read.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  haveLength () {
 | 
			
		||||
    if (this._opcode < 0x08 && this.maxPayloadExceeded(this._payloadLength)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._masked) this._state = GET_MASK;
 | 
			
		||||
    else this._state = GET_DATA;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Reads mask bytes.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  getMask () {
 | 
			
		||||
    this._mask = this.consume(4);
 | 
			
		||||
    if (this._mask === null) return;
 | 
			
		||||
 | 
			
		||||
    this._state = GET_DATA;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Reads data bytes.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  getData () {
 | 
			
		||||
    var data = constants.EMPTY_BUFFER;
 | 
			
		||||
 | 
			
		||||
    if (this._payloadLength) {
 | 
			
		||||
      data = this.consume(this._payloadLength);
 | 
			
		||||
      if (data === null) return;
 | 
			
		||||
 | 
			
		||||
      if (this._masked) bufferUtil.unmask(data, this._mask);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._opcode > 0x07) {
 | 
			
		||||
      this.controlMessage(data);
 | 
			
		||||
    } else if (this._compressed) {
 | 
			
		||||
      this._state = INFLATING;
 | 
			
		||||
      this.decompress(data);
 | 
			
		||||
    } else if (this.pushFragment(data)) {
 | 
			
		||||
      this.dataMessage();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Decompresses data.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data Compressed data
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  decompress (data) {
 | 
			
		||||
    const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
 | 
			
		||||
 | 
			
		||||
    perMessageDeflate.decompress(data, this._fin, (err, buf) => {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        this.error(err, err.closeCode === 1009 ? 1009 : 1007);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.pushFragment(buf)) this.dataMessage();
 | 
			
		||||
      this.startLoop();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Handles a data message.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  dataMessage () {
 | 
			
		||||
    if (this._fin) {
 | 
			
		||||
      const messageLength = this._messageLength;
 | 
			
		||||
      const fragments = this._fragments;
 | 
			
		||||
 | 
			
		||||
      this._totalPayloadLength = 0;
 | 
			
		||||
      this._messageLength = 0;
 | 
			
		||||
      this._fragmented = 0;
 | 
			
		||||
      this._fragments = [];
 | 
			
		||||
 | 
			
		||||
      if (this._opcode === 2) {
 | 
			
		||||
        var data;
 | 
			
		||||
 | 
			
		||||
        if (this._binaryType === 'nodebuffer') {
 | 
			
		||||
          data = toBuffer(fragments, messageLength);
 | 
			
		||||
        } else if (this._binaryType === 'arraybuffer') {
 | 
			
		||||
          data = toArrayBuffer(toBuffer(fragments, messageLength));
 | 
			
		||||
        } else {
 | 
			
		||||
          data = fragments;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.onmessage(data);
 | 
			
		||||
      } else {
 | 
			
		||||
        const buf = toBuffer(fragments, messageLength);
 | 
			
		||||
 | 
			
		||||
        if (!validation.isValidUTF8(buf)) {
 | 
			
		||||
          this.error(
 | 
			
		||||
            new Error('Invalid WebSocket frame: invalid UTF-8 sequence'),
 | 
			
		||||
            1007
 | 
			
		||||
          );
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.onmessage(buf.toString());
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._state = GET_INFO;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Handles a control message.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data Data to handle
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  controlMessage (data) {
 | 
			
		||||
    if (this._opcode === 0x08) {
 | 
			
		||||
      if (data.length === 0) {
 | 
			
		||||
        this._loop = false;
 | 
			
		||||
        this.onclose(1005, '');
 | 
			
		||||
        this.cleanup(this._cleanupCallback);
 | 
			
		||||
      } else if (data.length === 1) {
 | 
			
		||||
        this.error(
 | 
			
		||||
          new RangeError('Invalid WebSocket frame: invalid payload length 1'),
 | 
			
		||||
          1002
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        const code = data.readUInt16BE(0, true);
 | 
			
		||||
 | 
			
		||||
        if (!validation.isValidStatusCode(code)) {
 | 
			
		||||
          this.error(
 | 
			
		||||
            new RangeError(
 | 
			
		||||
              `Invalid WebSocket frame: invalid status code ${code}`
 | 
			
		||||
            ),
 | 
			
		||||
            1002
 | 
			
		||||
          );
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const buf = data.slice(2);
 | 
			
		||||
 | 
			
		||||
        if (!validation.isValidUTF8(buf)) {
 | 
			
		||||
          this.error(
 | 
			
		||||
            new Error('Invalid WebSocket frame: invalid UTF-8 sequence'),
 | 
			
		||||
            1007
 | 
			
		||||
          );
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._loop = false;
 | 
			
		||||
        this.onclose(code, buf.toString());
 | 
			
		||||
        this.cleanup(this._cleanupCallback);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._opcode === 0x09) this.onping(data);
 | 
			
		||||
    else this.onpong(data);
 | 
			
		||||
 | 
			
		||||
    this._state = GET_INFO;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Handles an error.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Error} err The error
 | 
			
		||||
   * @param {Number} code Close code
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  error (err, code) {
 | 
			
		||||
    this._hadError = true;
 | 
			
		||||
    this._loop = false;
 | 
			
		||||
    this.onerror(err, code);
 | 
			
		||||
    this.cleanup(this._cleanupCallback);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Checks payload size, disconnects socket when it exceeds `maxPayload`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Number} length Payload length
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  maxPayloadExceeded (length) {
 | 
			
		||||
    if (length === 0 || this._maxPayload < 1) return false;
 | 
			
		||||
 | 
			
		||||
    const fullLength = this._totalPayloadLength + length;
 | 
			
		||||
 | 
			
		||||
    if (fullLength <= this._maxPayload) {
 | 
			
		||||
      this._totalPayloadLength = fullLength;
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.error(new RangeError('Max payload size exceeded'), 1009);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Appends a fragment in the fragments array after checking that the sum of
 | 
			
		||||
   * fragment lengths does not exceed `maxPayload`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} fragment The fragment to add
 | 
			
		||||
   * @return {Boolean} `true` if `maxPayload` is not exceeded, else `false`
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  pushFragment (fragment) {
 | 
			
		||||
    if (fragment.length === 0) return true;
 | 
			
		||||
 | 
			
		||||
    const totalLength = this._messageLength + fragment.length;
 | 
			
		||||
 | 
			
		||||
    if (this._maxPayload < 1 || totalLength <= this._maxPayload) {
 | 
			
		||||
      this._messageLength = totalLength;
 | 
			
		||||
      this._fragments.push(fragment);
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.error(new RangeError('Max payload size exceeded'), 1009);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Releases resources used by the receiver.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  cleanup (cb) {
 | 
			
		||||
    if (this._extensions === null) {
 | 
			
		||||
      if (cb) cb();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!this._hadError && (this._loop || this._state === INFLATING)) {
 | 
			
		||||
      this._cleanupCallback = cb;
 | 
			
		||||
      this._isCleaningUp = true;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._extensions = null;
 | 
			
		||||
    this._fragments = null;
 | 
			
		||||
    this._buffers = null;
 | 
			
		||||
    this._mask = null;
 | 
			
		||||
 | 
			
		||||
    this._cleanupCallback = null;
 | 
			
		||||
    this.onmessage = null;
 | 
			
		||||
    this.onclose = null;
 | 
			
		||||
    this.onerror = null;
 | 
			
		||||
    this.onping = null;
 | 
			
		||||
    this.onpong = null;
 | 
			
		||||
 | 
			
		||||
    if (cb) cb();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = Receiver;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Makes a buffer from a list of fragments.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Buffer[]} fragments The list of fragments composing the message
 | 
			
		||||
 * @param {Number} messageLength The length of the message
 | 
			
		||||
 * @return {Buffer}
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function toBuffer (fragments, messageLength) {
 | 
			
		||||
  if (fragments.length === 1) return fragments[0];
 | 
			
		||||
  if (fragments.length > 1) return bufferUtil.concat(fragments, messageLength);
 | 
			
		||||
  return constants.EMPTY_BUFFER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Converts a buffer to an `ArrayBuffer`.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Buffer} The buffer to convert
 | 
			
		||||
 * @return {ArrayBuffer} Converted buffer
 | 
			
		||||
 */
 | 
			
		||||
function toArrayBuffer (buf) {
 | 
			
		||||
  if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
 | 
			
		||||
    return buf.buffer;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										404
									
								
								node_modules/ws/lib/sender.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										404
									
								
								node_modules/ws/lib/sender.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,404 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const safeBuffer = require('safe-buffer');
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
 | 
			
		||||
const PerMessageDeflate = require('./permessage-deflate');
 | 
			
		||||
const bufferUtil = require('./buffer-util');
 | 
			
		||||
const validation = require('./validation');
 | 
			
		||||
const constants = require('./constants');
 | 
			
		||||
 | 
			
		||||
const Buffer = safeBuffer.Buffer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * HyBi Sender implementation.
 | 
			
		||||
 */
 | 
			
		||||
class Sender {
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates a Sender instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {net.Socket} socket The connection socket
 | 
			
		||||
   * @param {Object} extensions An object containing the negotiated extensions
 | 
			
		||||
   */
 | 
			
		||||
  constructor (socket, extensions) {
 | 
			
		||||
    this._extensions = extensions || {};
 | 
			
		||||
    this._socket = socket;
 | 
			
		||||
 | 
			
		||||
    this._firstFragment = true;
 | 
			
		||||
    this._compress = false;
 | 
			
		||||
 | 
			
		||||
    this._bufferedBytes = 0;
 | 
			
		||||
    this._deflating = false;
 | 
			
		||||
    this._queue = [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Frames a piece of data according to the HyBi WebSocket protocol.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data The data to frame
 | 
			
		||||
   * @param {Object} options Options object
 | 
			
		||||
   * @param {Number} options.opcode The opcode
 | 
			
		||||
   * @param {Boolean} options.readOnly Specifies whether `data` can be modified
 | 
			
		||||
   * @param {Boolean} options.fin Specifies whether or not to set the FIN bit
 | 
			
		||||
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
 | 
			
		||||
   * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit
 | 
			
		||||
   * @return {Buffer[]} The framed data as a list of `Buffer` instances
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  static frame (data, options) {
 | 
			
		||||
    const merge = data.length < 1024 || (options.mask && options.readOnly);
 | 
			
		||||
    var offset = options.mask ? 6 : 2;
 | 
			
		||||
    var payloadLength = data.length;
 | 
			
		||||
 | 
			
		||||
    if (data.length >= 65536) {
 | 
			
		||||
      offset += 8;
 | 
			
		||||
      payloadLength = 127;
 | 
			
		||||
    } else if (data.length > 125) {
 | 
			
		||||
      offset += 2;
 | 
			
		||||
      payloadLength = 126;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const target = Buffer.allocUnsafe(merge ? data.length + offset : offset);
 | 
			
		||||
 | 
			
		||||
    target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
 | 
			
		||||
    if (options.rsv1) target[0] |= 0x40;
 | 
			
		||||
 | 
			
		||||
    if (payloadLength === 126) {
 | 
			
		||||
      target.writeUInt16BE(data.length, 2, true);
 | 
			
		||||
    } else if (payloadLength === 127) {
 | 
			
		||||
      target.writeUInt32BE(0, 2, true);
 | 
			
		||||
      target.writeUInt32BE(data.length, 6, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!options.mask) {
 | 
			
		||||
      target[1] = payloadLength;
 | 
			
		||||
      if (merge) {
 | 
			
		||||
        data.copy(target, offset);
 | 
			
		||||
        return [target];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return [target, data];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const mask = crypto.randomBytes(4);
 | 
			
		||||
 | 
			
		||||
    target[1] = payloadLength | 0x80;
 | 
			
		||||
    target[offset - 4] = mask[0];
 | 
			
		||||
    target[offset - 3] = mask[1];
 | 
			
		||||
    target[offset - 2] = mask[2];
 | 
			
		||||
    target[offset - 1] = mask[3];
 | 
			
		||||
 | 
			
		||||
    if (merge) {
 | 
			
		||||
      bufferUtil.mask(data, mask, target, offset, data.length);
 | 
			
		||||
      return [target];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bufferUtil.mask(data, mask, data, 0, data.length);
 | 
			
		||||
    return [target, data];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sends a close message to the other peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {(Number|undefined)} code The status code component of the body
 | 
			
		||||
   * @param {String} data The message component of the body
 | 
			
		||||
   * @param {Boolean} mask Specifies whether or not to mask the message
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  close (code, data, mask, cb) {
 | 
			
		||||
    var buf;
 | 
			
		||||
 | 
			
		||||
    if (code === undefined) {
 | 
			
		||||
      buf = constants.EMPTY_BUFFER;
 | 
			
		||||
    } else if (typeof code !== 'number' || !validation.isValidStatusCode(code)) {
 | 
			
		||||
      throw new TypeError('First argument must be a valid error code number');
 | 
			
		||||
    } else if (data === undefined || data === '') {
 | 
			
		||||
      buf = Buffer.allocUnsafe(2);
 | 
			
		||||
      buf.writeUInt16BE(code, 0, true);
 | 
			
		||||
    } else {
 | 
			
		||||
      buf = Buffer.allocUnsafe(2 + Buffer.byteLength(data));
 | 
			
		||||
      buf.writeUInt16BE(code, 0, true);
 | 
			
		||||
      buf.write(data, 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._deflating) {
 | 
			
		||||
      this.enqueue([this.doClose, buf, mask, cb]);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.doClose(buf, mask, cb);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Frames and sends a close message.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data The message to send
 | 
			
		||||
   * @param {Boolean} mask Specifies whether or not to mask `data`
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  doClose (data, mask, cb) {
 | 
			
		||||
    this.sendFrame(Sender.frame(data, {
 | 
			
		||||
      fin: true,
 | 
			
		||||
      rsv1: false,
 | 
			
		||||
      opcode: 0x08,
 | 
			
		||||
      mask,
 | 
			
		||||
      readOnly: false
 | 
			
		||||
    }), cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sends a ping message to the other peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {*} data The message to send
 | 
			
		||||
   * @param {Boolean} mask Specifies whether or not to mask `data`
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  ping (data, mask, cb) {
 | 
			
		||||
    var readOnly = true;
 | 
			
		||||
 | 
			
		||||
    if (!Buffer.isBuffer(data)) {
 | 
			
		||||
      if (data instanceof ArrayBuffer) {
 | 
			
		||||
        data = Buffer.from(data);
 | 
			
		||||
      } else if (ArrayBuffer.isView(data)) {
 | 
			
		||||
        data = viewToBuffer(data);
 | 
			
		||||
      } else {
 | 
			
		||||
        data = Buffer.from(data);
 | 
			
		||||
        readOnly = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._deflating) {
 | 
			
		||||
      this.enqueue([this.doPing, data, mask, readOnly, cb]);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.doPing(data, mask, readOnly, cb);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Frames and sends a ping message.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {*} 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
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  doPing (data, mask, readOnly, cb) {
 | 
			
		||||
    this.sendFrame(Sender.frame(data, {
 | 
			
		||||
      fin: true,
 | 
			
		||||
      rsv1: false,
 | 
			
		||||
      opcode: 0x09,
 | 
			
		||||
      mask,
 | 
			
		||||
      readOnly
 | 
			
		||||
    }), cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sends a pong message to the other peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {*} data The message to send
 | 
			
		||||
   * @param {Boolean} mask Specifies whether or not to mask `data`
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  pong (data, mask, cb) {
 | 
			
		||||
    var readOnly = true;
 | 
			
		||||
 | 
			
		||||
    if (!Buffer.isBuffer(data)) {
 | 
			
		||||
      if (data instanceof ArrayBuffer) {
 | 
			
		||||
        data = Buffer.from(data);
 | 
			
		||||
      } else if (ArrayBuffer.isView(data)) {
 | 
			
		||||
        data = viewToBuffer(data);
 | 
			
		||||
      } else {
 | 
			
		||||
        data = Buffer.from(data);
 | 
			
		||||
        readOnly = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._deflating) {
 | 
			
		||||
      this.enqueue([this.doPong, data, mask, readOnly, cb]);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.doPong(data, mask, readOnly, cb);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Frames and sends a pong message.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {*} 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
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  doPong (data, mask, readOnly, cb) {
 | 
			
		||||
    this.sendFrame(Sender.frame(data, {
 | 
			
		||||
      fin: true,
 | 
			
		||||
      rsv1: false,
 | 
			
		||||
      opcode: 0x0a,
 | 
			
		||||
      mask,
 | 
			
		||||
      readOnly
 | 
			
		||||
    }), cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sends a data message to the other peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @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.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`
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  send (data, options, cb) {
 | 
			
		||||
    var opcode = options.binary ? 2 : 1;
 | 
			
		||||
    var rsv1 = options.compress;
 | 
			
		||||
    var readOnly = true;
 | 
			
		||||
 | 
			
		||||
    if (!Buffer.isBuffer(data)) {
 | 
			
		||||
      if (data instanceof ArrayBuffer) {
 | 
			
		||||
        data = Buffer.from(data);
 | 
			
		||||
      } else if (ArrayBuffer.isView(data)) {
 | 
			
		||||
        data = viewToBuffer(data);
 | 
			
		||||
      } else {
 | 
			
		||||
        data = Buffer.from(data);
 | 
			
		||||
        readOnly = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
 | 
			
		||||
 | 
			
		||||
    if (this._firstFragment) {
 | 
			
		||||
      this._firstFragment = false;
 | 
			
		||||
      if (rsv1 && perMessageDeflate) {
 | 
			
		||||
        rsv1 = data.length >= perMessageDeflate._threshold;
 | 
			
		||||
      }
 | 
			
		||||
      this._compress = rsv1;
 | 
			
		||||
    } else {
 | 
			
		||||
      rsv1 = false;
 | 
			
		||||
      opcode = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (options.fin) this._firstFragment = true;
 | 
			
		||||
 | 
			
		||||
    if (perMessageDeflate) {
 | 
			
		||||
      const opts = {
 | 
			
		||||
        fin: options.fin,
 | 
			
		||||
        rsv1,
 | 
			
		||||
        opcode,
 | 
			
		||||
        mask: options.mask,
 | 
			
		||||
        readOnly
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      if (this._deflating) {
 | 
			
		||||
        this.enqueue([this.dispatch, data, this._compress, opts, cb]);
 | 
			
		||||
      } else {
 | 
			
		||||
        this.dispatch(data, this._compress, opts, cb);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      this.sendFrame(Sender.frame(data, {
 | 
			
		||||
        fin: options.fin,
 | 
			
		||||
        rsv1: false,
 | 
			
		||||
        opcode,
 | 
			
		||||
        mask: options.mask,
 | 
			
		||||
        readOnly
 | 
			
		||||
      }), cb);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Dispatches a data message.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer} data The message to send
 | 
			
		||||
   * @param {Boolean} compress Specifies whether or not to compress `data`
 | 
			
		||||
   * @param {Object} options Options object
 | 
			
		||||
   * @param {Number} options.opcode The opcode
 | 
			
		||||
   * @param {Boolean} options.readOnly Specifies whether `data` can be modified
 | 
			
		||||
   * @param {Boolean} options.fin Specifies whether or not to set the FIN bit
 | 
			
		||||
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
 | 
			
		||||
   * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  dispatch (data, compress, options, cb) {
 | 
			
		||||
    if (!compress) {
 | 
			
		||||
      this.sendFrame(Sender.frame(data, options), cb);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
 | 
			
		||||
 | 
			
		||||
    this._deflating = true;
 | 
			
		||||
    perMessageDeflate.compress(data, options.fin, (_, buf) => {
 | 
			
		||||
      options.readOnly = false;
 | 
			
		||||
      this.sendFrame(Sender.frame(buf, options), cb);
 | 
			
		||||
      this._deflating = false;
 | 
			
		||||
      this.dequeue();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Executes queued send operations.
 | 
			
		||||
   *
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  dequeue () {
 | 
			
		||||
    while (!this._deflating && this._queue.length) {
 | 
			
		||||
      const params = this._queue.shift();
 | 
			
		||||
 | 
			
		||||
      this._bufferedBytes -= params[1].length;
 | 
			
		||||
      params[0].apply(this, params.slice(1));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Enqueues a send operation.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Array} params Send operation parameters.
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  enqueue (params) {
 | 
			
		||||
    this._bufferedBytes += params[1].length;
 | 
			
		||||
    this._queue.push(params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sends a frame.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Buffer[]} list The frame to send
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  sendFrame (list, cb) {
 | 
			
		||||
    if (list.length === 2) {
 | 
			
		||||
      this._socket.write(list[0]);
 | 
			
		||||
      this._socket.write(list[1], cb);
 | 
			
		||||
    } else {
 | 
			
		||||
      this._socket.write(list[0], cb);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = Sender;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								node_modules/ws/lib/validation.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								node_modules/ws/lib/validation.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,29 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
  const isValidUTF8 = require('utf-8-validate');
 | 
			
		||||
 | 
			
		||||
  exports.isValidUTF8 = typeof isValidUTF8 === 'object'
 | 
			
		||||
    ? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0
 | 
			
		||||
    : isValidUTF8;
 | 
			
		||||
} catch (e) /* istanbul ignore next */ {
 | 
			
		||||
  exports.isValidUTF8 = () => true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks if a status code is allowed in a close frame.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Number} code The status code
 | 
			
		||||
 * @return {Boolean} `true` if the status code is valid, else `false`
 | 
			
		||||
 * @public
 | 
			
		||||
 */
 | 
			
		||||
exports.isValidStatusCode = (code) => {
 | 
			
		||||
  return (
 | 
			
		||||
    (code >= 1000 &&
 | 
			
		||||
      code <= 1013 &&
 | 
			
		||||
      code !== 1004 &&
 | 
			
		||||
      code !== 1005 &&
 | 
			
		||||
      code !== 1006) ||
 | 
			
		||||
    (code >= 3000 && code <= 4999)
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										351
									
								
								node_modules/ws/lib/websocket-server.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										351
									
								
								node_modules/ws/lib/websocket-server.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,351 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const safeBuffer = require('safe-buffer');
 | 
			
		||||
const EventEmitter = require('events');
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
const http = require('http');
 | 
			
		||||
const url = require('url');
 | 
			
		||||
 | 
			
		||||
const PerMessageDeflate = require('./permessage-deflate');
 | 
			
		||||
const extension = require('./extension');
 | 
			
		||||
const constants = require('./constants');
 | 
			
		||||
const WebSocket = require('./websocket');
 | 
			
		||||
 | 
			
		||||
const Buffer = safeBuffer.Buffer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing a WebSocket server.
 | 
			
		||||
 *
 | 
			
		||||
 * @extends EventEmitter
 | 
			
		||||
 */
 | 
			
		||||
class WebSocketServer extends EventEmitter {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a `WebSocketServer` instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Object} options Configuration options
 | 
			
		||||
   * @param {String} options.host The hostname where to bind the server
 | 
			
		||||
   * @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.handleProtocols An hook to handle protocols
 | 
			
		||||
   * @param {String} options.path Accept only connections matching this path
 | 
			
		||||
   * @param {Boolean} options.noServer Enable no server mode
 | 
			
		||||
   * @param {Boolean} options.clientTracking Specifies whether or not to track clients
 | 
			
		||||
   * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
 | 
			
		||||
   * @param {Number} options.maxPayload The maximum allowed message size
 | 
			
		||||
   * @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);
 | 
			
		||||
 | 
			
		||||
    if (options.port == null && !options.server && !options.noServer) {
 | 
			
		||||
      throw new TypeError(
 | 
			
		||||
        'One of the "port", "server", or "noServer" options must be specified'
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (options.port != null) {
 | 
			
		||||
      this._server = http.createServer((req, res) => {
 | 
			
		||||
        const body = http.STATUS_CODES[426];
 | 
			
		||||
 | 
			
		||||
        res.writeHead(426, {
 | 
			
		||||
          'Content-Length': body.length,
 | 
			
		||||
          'Content-Type': 'text/plain'
 | 
			
		||||
        });
 | 
			
		||||
        res.end(body);
 | 
			
		||||
      });
 | 
			
		||||
      this._server.listen(options.port, options.host, options.backlog, callback);
 | 
			
		||||
    } else if (options.server) {
 | 
			
		||||
      this._server = options.server;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this._server) {
 | 
			
		||||
      this._removeListeners = addListeners(this._server, {
 | 
			
		||||
        listening: this.emit.bind(this, 'listening'),
 | 
			
		||||
        error: this.emit.bind(this, 'error'),
 | 
			
		||||
        upgrade: (req, socket, head) => {
 | 
			
		||||
          this.handleUpgrade(req, socket, head, (ws) => {
 | 
			
		||||
            this.emit('connection', ws, req);
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (options.perMessageDeflate === true) options.perMessageDeflate = {};
 | 
			
		||||
    if (options.clientTracking) this.clients = new Set();
 | 
			
		||||
    this.options = options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the bound address, the address family name, and port of the server
 | 
			
		||||
   * as reported by the operating system if listening on an IP socket.
 | 
			
		||||
   * If the server is listening on a pipe or UNIX domain socket, the name is
 | 
			
		||||
   * returned as a string.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {(Object|String|null)} The address of the server
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  address () {
 | 
			
		||||
    if (this.options.noServer) {
 | 
			
		||||
      throw new Error('The server is operating in "noServer" mode');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!this._server) return null;
 | 
			
		||||
    return this._server.address();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Close the server.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Function} cb Callback
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  close (cb) {
 | 
			
		||||
    //
 | 
			
		||||
    // Terminate all associated clients.
 | 
			
		||||
    //
 | 
			
		||||
    if (this.clients) {
 | 
			
		||||
      for (const client of this.clients) client.terminate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const server = this._server;
 | 
			
		||||
 | 
			
		||||
    if (server) {
 | 
			
		||||
      this._removeListeners();
 | 
			
		||||
      this._removeListeners = this._server = null;
 | 
			
		||||
 | 
			
		||||
      //
 | 
			
		||||
      // Close the http server if it was internally created.
 | 
			
		||||
      //
 | 
			
		||||
      if (this.options.port != null) return server.close(cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cb) cb();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * See if a given request should be handled by this server instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {http.IncomingMessage} req Request object to inspect
 | 
			
		||||
   * @return {Boolean} `true` if the request is valid, else `false`
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  shouldHandle (req) {
 | 
			
		||||
    if (this.options.path && url.parse(req.url).pathname !== this.options.path) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Handle a HTTP Upgrade request.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {http.IncomingMessage} req The request object
 | 
			
		||||
   * @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
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  handleUpgrade (req, socket, head, cb) {
 | 
			
		||||
    socket.on('error', socketOnError);
 | 
			
		||||
 | 
			
		||||
    const version = +req.headers['sec-websocket-version'];
 | 
			
		||||
    const extensions = {};
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket' ||
 | 
			
		||||
      !req.headers['sec-websocket-key'] || (version !== 8 && version !== 13) ||
 | 
			
		||||
      !this.shouldHandle(req)
 | 
			
		||||
    ) {
 | 
			
		||||
      return abortConnection(socket, 400);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.options.perMessageDeflate) {
 | 
			
		||||
      const perMessageDeflate = new PerMessageDeflate(
 | 
			
		||||
        this.options.perMessageDeflate,
 | 
			
		||||
        true,
 | 
			
		||||
        this.options.maxPayload
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const offers = extension.parse(
 | 
			
		||||
          req.headers['sec-websocket-extensions']
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (offers[PerMessageDeflate.extensionName]) {
 | 
			
		||||
          perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
 | 
			
		||||
          extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
 | 
			
		||||
        }
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        return abortConnection(socket, 400);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var protocol = (req.headers['sec-websocket-protocol'] || '').split(/, */);
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Optionally call external protocol selection handler.
 | 
			
		||||
    //
 | 
			
		||||
    if (this.options.handleProtocols) {
 | 
			
		||||
      protocol = this.options.handleProtocols(protocol, req);
 | 
			
		||||
      if (protocol === false) return abortConnection(socket, 401);
 | 
			
		||||
    } else {
 | 
			
		||||
      protocol = protocol[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Optionally call external client verification handler.
 | 
			
		||||
    //
 | 
			
		||||
    if (this.options.verifyClient) {
 | 
			
		||||
      const info = {
 | 
			
		||||
        origin: req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
 | 
			
		||||
        secure: !!(req.connection.authorized || req.connection.encrypted),
 | 
			
		||||
        req
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      if (this.options.verifyClient.length === 2) {
 | 
			
		||||
        this.options.verifyClient(info, (verified, code, message) => {
 | 
			
		||||
          if (!verified) return abortConnection(socket, code || 401, message);
 | 
			
		||||
 | 
			
		||||
          this.completeUpgrade(protocol, extensions, req, socket, head, cb);
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!this.options.verifyClient(info)) return abortConnection(socket, 401);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.completeUpgrade(protocol, extensions, req, socket, head, cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Upgrade the connection to WebSocket.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {String} protocol The chosen subprotocol
 | 
			
		||||
   * @param {Object} extensions The accepted extensions
 | 
			
		||||
   * @param {http.IncomingMessage} req The request object
 | 
			
		||||
   * @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
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  completeUpgrade (protocol, extensions, req, socket, head, cb) {
 | 
			
		||||
    //
 | 
			
		||||
    // Destroy the socket if the client has already sent a FIN packet.
 | 
			
		||||
    //
 | 
			
		||||
    if (!socket.readable || !socket.writable) return socket.destroy();
 | 
			
		||||
 | 
			
		||||
    const key = crypto.createHash('sha1')
 | 
			
		||||
      .update(req.headers['sec-websocket-key'] + constants.GUID, 'binary')
 | 
			
		||||
      .digest('base64');
 | 
			
		||||
 | 
			
		||||
    const headers = [
 | 
			
		||||
      'HTTP/1.1 101 Switching Protocols',
 | 
			
		||||
      'Upgrade: websocket',
 | 
			
		||||
      'Connection: Upgrade',
 | 
			
		||||
      `Sec-WebSocket-Accept: ${key}`
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const ws = new WebSocket(null);
 | 
			
		||||
 | 
			
		||||
    if (protocol) {
 | 
			
		||||
      headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
 | 
			
		||||
      ws.protocol = protocol;
 | 
			
		||||
    }
 | 
			
		||||
    if (extensions[PerMessageDeflate.extensionName]) {
 | 
			
		||||
      const params = extensions[PerMessageDeflate.extensionName].params;
 | 
			
		||||
      const value = extension.format({
 | 
			
		||||
        [PerMessageDeflate.extensionName]: [params]
 | 
			
		||||
      });
 | 
			
		||||
      headers.push(`Sec-WebSocket-Extensions: ${value}`);
 | 
			
		||||
      ws._extensions = extensions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Allow external modification/inspection of handshake headers.
 | 
			
		||||
    //
 | 
			
		||||
    this.emit('headers', headers, req);
 | 
			
		||||
 | 
			
		||||
    socket.write(headers.concat('\r\n').join('\r\n'));
 | 
			
		||||
    socket.removeListener('error', socketOnError);
 | 
			
		||||
 | 
			
		||||
    ws.setSocket(socket, head, this.options.maxPayload);
 | 
			
		||||
 | 
			
		||||
    if (this.clients) {
 | 
			
		||||
      this.clients.add(ws);
 | 
			
		||||
      ws.on('close', () => this.clients.delete(ws));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cb(ws);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = WebSocketServer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add event listeners on an `EventEmitter` using a map of <event, listener>
 | 
			
		||||
 * pairs.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {EventEmitter} server The event emitter
 | 
			
		||||
 * @param {Object.<String, Function>} map The listeners to add
 | 
			
		||||
 * @return {Function} A function that will remove the added listeners when called
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function addListeners (server, map) {
 | 
			
		||||
  for (const event of Object.keys(map)) server.on(event, map[event]);
 | 
			
		||||
 | 
			
		||||
  return function removeListeners () {
 | 
			
		||||
    for (const event of Object.keys(map)) {
 | 
			
		||||
      server.removeListener(event, map[event]);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle premature socket errors.
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function socketOnError () {
 | 
			
		||||
  this.destroy();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Close the connection when preconditions are not fulfilled.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {net.Socket} socket The socket of the upgrade request
 | 
			
		||||
 * @param {Number} code The HTTP response status code
 | 
			
		||||
 * @param {String} [message] The HTTP response body
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function abortConnection (socket, code, message) {
 | 
			
		||||
  if (socket.writable) {
 | 
			
		||||
    message = message || http.STATUS_CODES[code];
 | 
			
		||||
    socket.write(
 | 
			
		||||
      `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
 | 
			
		||||
      'Connection: close\r\n' +
 | 
			
		||||
      'Content-type: text/html\r\n' +
 | 
			
		||||
      `Content-Length: ${Buffer.byteLength(message)}\r\n` +
 | 
			
		||||
      '\r\n' +
 | 
			
		||||
      message
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  socket.removeListener('error', socketOnError);
 | 
			
		||||
  socket.destroy();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										705
									
								
								node_modules/ws/lib/websocket.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										705
									
								
								node_modules/ws/lib/websocket.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,705 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const EventEmitter = require('events');
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
const https = require('https');
 | 
			
		||||
const http = require('http');
 | 
			
		||||
const url = require('url');
 | 
			
		||||
 | 
			
		||||
const PerMessageDeflate = require('./permessage-deflate');
 | 
			
		||||
const EventTarget = require('./event-target');
 | 
			
		||||
const extension = require('./extension');
 | 
			
		||||
const constants = require('./constants');
 | 
			
		||||
const Receiver = require('./receiver');
 | 
			
		||||
const Sender = require('./sender');
 | 
			
		||||
 | 
			
		||||
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
 | 
			
		||||
const protocolVersions = [8, 13];
 | 
			
		||||
const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly.
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing a WebSocket.
 | 
			
		||||
 *
 | 
			
		||||
 * @extends EventEmitter
 | 
			
		||||
 */
 | 
			
		||||
class WebSocket extends EventEmitter {
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new `WebSocket`.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {String} address The URL to which to connect
 | 
			
		||||
   * @param {(String|String[])} protocols The subprotocols
 | 
			
		||||
   * @param {Object} options Connection options
 | 
			
		||||
   */
 | 
			
		||||
  constructor (address, protocols, options) {
 | 
			
		||||
    super();
 | 
			
		||||
 | 
			
		||||
    this.readyState = WebSocket.CONNECTING;
 | 
			
		||||
    this.protocol = '';
 | 
			
		||||
 | 
			
		||||
    this._binaryType = constants.BINARY_TYPES[0];
 | 
			
		||||
    this._finalize = this.finalize.bind(this);
 | 
			
		||||
    this._closeFrameReceived = false;
 | 
			
		||||
    this._closeFrameSent = false;
 | 
			
		||||
    this._closeMessage = '';
 | 
			
		||||
    this._closeTimer = null;
 | 
			
		||||
    this._finalized = false;
 | 
			
		||||
    this._closeCode = 1006;
 | 
			
		||||
    this._extensions = {};
 | 
			
		||||
    this._isServer = true;
 | 
			
		||||
    this._receiver = null;
 | 
			
		||||
    this._sender = null;
 | 
			
		||||
    this._socket = null;
 | 
			
		||||
    this._error = null;
 | 
			
		||||
 | 
			
		||||
    if (address !== null) {
 | 
			
		||||
      if (!protocols) {
 | 
			
		||||
        protocols = [];
 | 
			
		||||
      } else if (typeof protocols === 'string') {
 | 
			
		||||
        protocols = [protocols];
 | 
			
		||||
      } else if (!Array.isArray(protocols)) {
 | 
			
		||||
        options = protocols;
 | 
			
		||||
        protocols = [];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      initAsClient.call(this, address, protocols, options);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get CONNECTING () { return WebSocket.CONNECTING; }
 | 
			
		||||
  get CLOSING () { return WebSocket.CLOSING; }
 | 
			
		||||
  get CLOSED () { return WebSocket.CLOSED; }
 | 
			
		||||
  get OPEN () { return WebSocket.OPEN; }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * This deviates from the WHATWG interface since ws doesn't support the required
 | 
			
		||||
   * default "blob" type (instead we define a custom "nodebuffer" type).
 | 
			
		||||
   *
 | 
			
		||||
   * @type {String}
 | 
			
		||||
   */
 | 
			
		||||
  get binaryType () {
 | 
			
		||||
    return this._binaryType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set binaryType (type) {
 | 
			
		||||
    if (constants.BINARY_TYPES.indexOf(type) < 0) return;
 | 
			
		||||
 | 
			
		||||
    this._binaryType = type;
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Allow to change `binaryType` on the fly.
 | 
			
		||||
    //
 | 
			
		||||
    if (this._receiver) this._receiver._binaryType = type;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @type {Number}
 | 
			
		||||
   */
 | 
			
		||||
  get bufferedAmount () {
 | 
			
		||||
    if (!this._socket) return 0;
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // `socket.bufferSize` is `undefined` if the socket is closed.
 | 
			
		||||
    //
 | 
			
		||||
    return (this._socket.bufferSize || 0) + this._sender._bufferedBytes;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @type {String}
 | 
			
		||||
   */
 | 
			
		||||
  get extensions () {
 | 
			
		||||
    return Object.keys(this._extensions).join();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Set up the socket and the internal resources.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {net.Socket} socket The network socket between the server and client
 | 
			
		||||
   * @param {Buffer} head The first packet of the upgraded stream
 | 
			
		||||
   * @param {Number} maxPayload The maximum allowed message size
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  setSocket (socket, head, maxPayload) {
 | 
			
		||||
    socket.setTimeout(0);
 | 
			
		||||
    socket.setNoDelay();
 | 
			
		||||
 | 
			
		||||
    socket.on('close', this._finalize);
 | 
			
		||||
    socket.on('error', this._finalize);
 | 
			
		||||
    socket.on('end', this._finalize);
 | 
			
		||||
 | 
			
		||||
    this._receiver = new Receiver(this._extensions, maxPayload, this.binaryType);
 | 
			
		||||
    this._sender = new Sender(socket, this._extensions);
 | 
			
		||||
    this._socket = socket;
 | 
			
		||||
 | 
			
		||||
    if (head.length > 0) socket.unshift(head);
 | 
			
		||||
 | 
			
		||||
    socket.on('data', this._receiver.add);
 | 
			
		||||
 | 
			
		||||
    this._receiver.onmessage = (data) => this.emit('message', data);
 | 
			
		||||
    this._receiver.onping = (data) => {
 | 
			
		||||
      this.pong(data, !this._isServer, constants.NOOP);
 | 
			
		||||
      this.emit('ping', data);
 | 
			
		||||
    };
 | 
			
		||||
    this._receiver.onpong = (data) => this.emit('pong', data);
 | 
			
		||||
    this._receiver.onclose = (code, reason) => {
 | 
			
		||||
      //
 | 
			
		||||
      // Discard any additional data that is received on the socket.
 | 
			
		||||
      //
 | 
			
		||||
      this._socket.removeListener('data', this._receiver.add);
 | 
			
		||||
 | 
			
		||||
      this._closeFrameReceived = true;
 | 
			
		||||
      this._closeMessage = reason;
 | 
			
		||||
      this._closeCode = code;
 | 
			
		||||
 | 
			
		||||
      if (code === 1005) this.close();
 | 
			
		||||
      else this.close(code, reason);
 | 
			
		||||
    };
 | 
			
		||||
    this._receiver.onerror = (error, code) => {
 | 
			
		||||
      if (this._error) return;
 | 
			
		||||
 | 
			
		||||
      this._closeCode = code;
 | 
			
		||||
 | 
			
		||||
      if (!this._finalized) this.finalize(error);
 | 
			
		||||
      else this.emit('error', error);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.readyState = WebSocket.OPEN;
 | 
			
		||||
    this.emit('open');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Clean up internal resources and emit the `'close'` event.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {(Boolean|Error)} error Indicates whether or not an error occurred
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  finalize (error) {
 | 
			
		||||
    if (this._finalized) return;
 | 
			
		||||
 | 
			
		||||
    this.readyState = WebSocket.CLOSING;
 | 
			
		||||
    this._finalized = true;
 | 
			
		||||
 | 
			
		||||
    if (!this._socket) {
 | 
			
		||||
      //
 | 
			
		||||
      // `error` is always an `Error` instance in this case.
 | 
			
		||||
      //
 | 
			
		||||
      this.emit('error', error);
 | 
			
		||||
      this.readyState = WebSocket.CLOSED;
 | 
			
		||||
      this.emit('close', this._closeCode, this._closeMessage);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    clearTimeout(this._closeTimer);
 | 
			
		||||
 | 
			
		||||
    this._socket.removeListener('data', this._receiver.add);
 | 
			
		||||
    this._socket.removeListener('close', this._finalize);
 | 
			
		||||
    this._socket.removeListener('error', this._finalize);
 | 
			
		||||
    this._socket.removeListener('end', this._finalize);
 | 
			
		||||
    this._socket.on('error', constants.NOOP);
 | 
			
		||||
 | 
			
		||||
    if (error) {
 | 
			
		||||
      if (error !== true) this._error = error;
 | 
			
		||||
      this._socket.destroy();
 | 
			
		||||
    } else {
 | 
			
		||||
      this._socket.end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._receiver.cleanup(() => {
 | 
			
		||||
      const err = this._error;
 | 
			
		||||
 | 
			
		||||
      if (err) {
 | 
			
		||||
        this._error = null;
 | 
			
		||||
        this.emit('error', err);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.readyState = WebSocket.CLOSED;
 | 
			
		||||
 | 
			
		||||
      if (this._extensions[PerMessageDeflate.extensionName]) {
 | 
			
		||||
        this._extensions[PerMessageDeflate.extensionName].cleanup();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.emit('close', this._closeCode, this._closeMessage);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Start a closing handshake.
 | 
			
		||||
   *
 | 
			
		||||
   *            +----------+     +-----------+   +----------+
 | 
			
		||||
   *     + - - -|ws.close()|---->|close frame|-->|ws.close()|- - - -
 | 
			
		||||
   *            +----------+     +-----------+   +----------+       |
 | 
			
		||||
   *     |      +----------+     +-----------+         |
 | 
			
		||||
   *            |ws.close()|<----|close frame|<--------+            |
 | 
			
		||||
   *            +----------+     +-----------+         |
 | 
			
		||||
   *  CLOSING         |              +---+             |         CLOSING
 | 
			
		||||
   *                  |          +---|fin|<------------+
 | 
			
		||||
   *     |            |          |   +---+                          |
 | 
			
		||||
   *                  |          |   +---+      +-------------+
 | 
			
		||||
   *     |            +----------+-->|fin|----->|ws.finalize()| - - +
 | 
			
		||||
   *                             |   +---+      +-------------+
 | 
			
		||||
   *     |     +-------------+   |
 | 
			
		||||
   *      - - -|ws.finalize()|<--+
 | 
			
		||||
   *           +-------------+
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Number} code Status code explaining why the connection is closing
 | 
			
		||||
   * @param {String} data A string explaining why the connection is closing
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  close (code, data) {
 | 
			
		||||
    if (this.readyState === WebSocket.CLOSED) return;
 | 
			
		||||
    if (this.readyState === WebSocket.CONNECTING) {
 | 
			
		||||
      this._req.abort();
 | 
			
		||||
      this.finalize(
 | 
			
		||||
        new Error('WebSocket was closed before the connection was established')
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.readyState === WebSocket.CLOSING) {
 | 
			
		||||
      if (this._closeFrameSent && this._closeFrameReceived) this._socket.end();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.readyState = WebSocket.CLOSING;
 | 
			
		||||
    this._sender.close(code, data, !this._isServer, (err) => {
 | 
			
		||||
      //
 | 
			
		||||
      // This error is handled by the `'error'` listener on the socket. We only
 | 
			
		||||
      // want to know if the close frame has been sent here.
 | 
			
		||||
      //
 | 
			
		||||
      if (err) return;
 | 
			
		||||
 | 
			
		||||
      this._closeFrameSent = true;
 | 
			
		||||
 | 
			
		||||
      if (!this._finalized) {
 | 
			
		||||
        if (this._closeFrameReceived) this._socket.end();
 | 
			
		||||
 | 
			
		||||
        //
 | 
			
		||||
        // Ensure that the connection is cleaned up even when the closing
 | 
			
		||||
        // handshake fails.
 | 
			
		||||
        //
 | 
			
		||||
        this._closeTimer = setTimeout(this._finalize, closeTimeout, true);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Send a ping.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {*} data The data to send
 | 
			
		||||
   * @param {Boolean} mask Indicates whether or not to mask `data`
 | 
			
		||||
   * @param {Function} cb Callback which is executed when the ping is sent
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  ping (data, mask, cb) {
 | 
			
		||||
    if (typeof data === 'function') {
 | 
			
		||||
      cb = data;
 | 
			
		||||
      data = mask = undefined;
 | 
			
		||||
    } else if (typeof mask === 'function') {
 | 
			
		||||
      cb = mask;
 | 
			
		||||
      mask = undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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();
 | 
			
		||||
    if (mask === undefined) mask = !this._isServer;
 | 
			
		||||
    this._sender.ping(data || constants.EMPTY_BUFFER, mask, cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Send a pong.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {*} data The data to send
 | 
			
		||||
   * @param {Boolean} mask Indicates whether or not to mask `data`
 | 
			
		||||
   * @param {Function} cb Callback which is executed when the pong is sent
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  pong (data, mask, cb) {
 | 
			
		||||
    if (typeof data === 'function') {
 | 
			
		||||
      cb = data;
 | 
			
		||||
      data = mask = undefined;
 | 
			
		||||
    } else if (typeof mask === 'function') {
 | 
			
		||||
      cb = mask;
 | 
			
		||||
      mask = undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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();
 | 
			
		||||
    if (mask === undefined) mask = !this._isServer;
 | 
			
		||||
    this._sender.pong(data || constants.EMPTY_BUFFER, mask, cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Send a data message.
 | 
			
		||||
   *
 | 
			
		||||
   * @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.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`
 | 
			
		||||
   * @param {Function} cb Callback which is executed when data is written out
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  send (data, options, cb) {
 | 
			
		||||
    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._extensions[PerMessageDeflate.extensionName]) {
 | 
			
		||||
      opts.compress = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._sender.send(data || constants.EMPTY_BUFFER, opts, cb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Forcibly close the connection.
 | 
			
		||||
   *
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
  terminate () {
 | 
			
		||||
    if (this.readyState === WebSocket.CLOSED) return;
 | 
			
		||||
    if (this.readyState === WebSocket.CONNECTING) {
 | 
			
		||||
      this._req.abort();
 | 
			
		||||
      this.finalize(
 | 
			
		||||
        new Error('WebSocket was closed before the connection was established')
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.finalize(true);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
readyStates.forEach((readyState, i) => {
 | 
			
		||||
  WebSocket[readyStates[i]] = i;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
 | 
			
		||||
// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
 | 
			
		||||
//
 | 
			
		||||
['open', 'error', 'close', 'message'].forEach((method) => {
 | 
			
		||||
  Object.defineProperty(WebSocket.prototype, `on${method}`, {
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the listener of the event.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {(Function|undefined)} The event listener or `undefined`
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    get () {
 | 
			
		||||
      const listeners = this.listeners(method);
 | 
			
		||||
      for (var i = 0; i < listeners.length; i++) {
 | 
			
		||||
        if (listeners[i]._listener) return listeners[i]._listener;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    /**
 | 
			
		||||
     * Add a listener for the event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Function} listener The listener to add
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    set (listener) {
 | 
			
		||||
      const listeners = this.listeners(method);
 | 
			
		||||
      for (var i = 0; i < listeners.length; i++) {
 | 
			
		||||
        //
 | 
			
		||||
        // Remove only the listeners added via `addEventListener`.
 | 
			
		||||
        //
 | 
			
		||||
        if (listeners[i]._listener) this.removeListener(method, listeners[i]);
 | 
			
		||||
      }
 | 
			
		||||
      this.addEventListener(method, listener);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
WebSocket.prototype.addEventListener = EventTarget.addEventListener;
 | 
			
		||||
WebSocket.prototype.removeEventListener = EventTarget.removeEventListener;
 | 
			
		||||
 | 
			
		||||
module.exports = WebSocket;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialize a WebSocket client.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} address The URL to which to connect
 | 
			
		||||
 * @param {String[]} protocols The list of subprotocols
 | 
			
		||||
 * @param {Object} options Connection options
 | 
			
		||||
 * @param {String} options.protocol Value of the `Sec-WebSocket-Protocol` header
 | 
			
		||||
 * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
 | 
			
		||||
 * @param {Number} options.handshakeTimeout Timeout in milliseconds for the handshake request
 | 
			
		||||
 * @param {String} options.localAddress Local interface to bind for network connections
 | 
			
		||||
 * @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` header
 | 
			
		||||
 * @param {Object} options.headers An object containing request headers
 | 
			
		||||
 * @param {String} options.origin Value of the `Origin` or `Sec-WebSocket-Origin` header
 | 
			
		||||
 * @param {http.Agent} options.agent Use the specified Agent
 | 
			
		||||
 * @param {String} options.host Value of the `Host` header
 | 
			
		||||
 * @param {Number} options.family IP address family to use during hostname lookup (4 or 6).
 | 
			
		||||
 * @param {Function} options.checkServerIdentity A function to validate the server hostname
 | 
			
		||||
 * @param {Boolean} options.rejectUnauthorized Verify or not the server certificate
 | 
			
		||||
 * @param {String} options.passphrase The passphrase for the private key or pfx
 | 
			
		||||
 * @param {String} options.ciphers The ciphers to use or exclude
 | 
			
		||||
 * @param {String} options.ecdhCurve The curves for ECDH key agreement to use or exclude
 | 
			
		||||
 * @param {(String|String[]|Buffer|Buffer[])} options.cert The certificate key
 | 
			
		||||
 * @param {(String|String[]|Buffer|Buffer[])} options.key The private key
 | 
			
		||||
 * @param {(String|Buffer)} options.pfx The private key, certificate, and CA certs
 | 
			
		||||
 * @param {(String|String[]|Buffer|Buffer[])} options.ca Trusted certificates
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
function initAsClient (address, protocols, options) {
 | 
			
		||||
  options = Object.assign({
 | 
			
		||||
    protocolVersion: protocolVersions[1],
 | 
			
		||||
    protocol: protocols.join(','),
 | 
			
		||||
    perMessageDeflate: true,
 | 
			
		||||
    handshakeTimeout: null,
 | 
			
		||||
    localAddress: null,
 | 
			
		||||
    headers: null,
 | 
			
		||||
    family: null,
 | 
			
		||||
    origin: null,
 | 
			
		||||
    agent: null,
 | 
			
		||||
    host: null,
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // SSL options.
 | 
			
		||||
    //
 | 
			
		||||
    checkServerIdentity: null,
 | 
			
		||||
    rejectUnauthorized: null,
 | 
			
		||||
    passphrase: null,
 | 
			
		||||
    ciphers: null,
 | 
			
		||||
    ecdhCurve: null,
 | 
			
		||||
    cert: null,
 | 
			
		||||
    key: null,
 | 
			
		||||
    pfx: null,
 | 
			
		||||
    ca: null
 | 
			
		||||
  }, options);
 | 
			
		||||
 | 
			
		||||
  if (protocolVersions.indexOf(options.protocolVersion) === -1) {
 | 
			
		||||
    throw new RangeError(
 | 
			
		||||
      `Unsupported protocol version: ${options.protocolVersion} ` +
 | 
			
		||||
        `(supported versions: ${protocolVersions.join(', ')})`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this._isServer = false;
 | 
			
		||||
  this.url = address;
 | 
			
		||||
 | 
			
		||||
  const serverUrl = url.parse(address);
 | 
			
		||||
  const isUnixSocket = serverUrl.protocol === 'ws+unix:';
 | 
			
		||||
 | 
			
		||||
  if (!serverUrl.host && (!isUnixSocket || !serverUrl.path)) {
 | 
			
		||||
    throw new Error(`Invalid URL: ${address}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:';
 | 
			
		||||
  const key = crypto.randomBytes(16).toString('base64');
 | 
			
		||||
  const httpObj = isSecure ? https : http;
 | 
			
		||||
  var perMessageDeflate;
 | 
			
		||||
 | 
			
		||||
  const requestOptions = {
 | 
			
		||||
    port: serverUrl.port || (isSecure ? 443 : 80),
 | 
			
		||||
    host: serverUrl.hostname,
 | 
			
		||||
    path: '/',
 | 
			
		||||
    headers: {
 | 
			
		||||
      'Sec-WebSocket-Version': options.protocolVersion,
 | 
			
		||||
      'Sec-WebSocket-Key': key,
 | 
			
		||||
      'Connection': 'Upgrade',
 | 
			
		||||
      'Upgrade': 'websocket'
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (options.headers) Object.assign(requestOptions.headers, options.headers);
 | 
			
		||||
  if (options.perMessageDeflate) {
 | 
			
		||||
    perMessageDeflate = new PerMessageDeflate(
 | 
			
		||||
      options.perMessageDeflate !== true ? options.perMessageDeflate : {},
 | 
			
		||||
      false
 | 
			
		||||
    );
 | 
			
		||||
    requestOptions.headers['Sec-WebSocket-Extensions'] = extension.format({
 | 
			
		||||
      [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  if (options.protocol) {
 | 
			
		||||
    requestOptions.headers['Sec-WebSocket-Protocol'] = options.protocol;
 | 
			
		||||
  }
 | 
			
		||||
  if (options.origin) {
 | 
			
		||||
    if (options.protocolVersion < 13) {
 | 
			
		||||
      requestOptions.headers['Sec-WebSocket-Origin'] = options.origin;
 | 
			
		||||
    } else {
 | 
			
		||||
      requestOptions.headers.Origin = options.origin;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (options.host) requestOptions.headers.Host = options.host;
 | 
			
		||||
  if (serverUrl.auth) requestOptions.auth = serverUrl.auth;
 | 
			
		||||
 | 
			
		||||
  if (options.localAddress) requestOptions.localAddress = options.localAddress;
 | 
			
		||||
  if (options.family) requestOptions.family = options.family;
 | 
			
		||||
 | 
			
		||||
  if (isUnixSocket) {
 | 
			
		||||
    const parts = serverUrl.path.split(':');
 | 
			
		||||
 | 
			
		||||
    requestOptions.socketPath = parts[0];
 | 
			
		||||
    requestOptions.path = parts[1];
 | 
			
		||||
  } else if (serverUrl.path) {
 | 
			
		||||
    //
 | 
			
		||||
    // Make sure that path starts with `/`.
 | 
			
		||||
    //
 | 
			
		||||
    if (serverUrl.path.charAt(0) !== '/') {
 | 
			
		||||
      requestOptions.path = `/${serverUrl.path}`;
 | 
			
		||||
    } else {
 | 
			
		||||
      requestOptions.path = serverUrl.path;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var agent = options.agent;
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // A custom agent is required for these options.
 | 
			
		||||
  //
 | 
			
		||||
  if (
 | 
			
		||||
    options.rejectUnauthorized != null ||
 | 
			
		||||
    options.checkServerIdentity ||
 | 
			
		||||
    options.passphrase ||
 | 
			
		||||
    options.ciphers ||
 | 
			
		||||
    options.ecdhCurve ||
 | 
			
		||||
    options.cert ||
 | 
			
		||||
    options.key ||
 | 
			
		||||
    options.pfx ||
 | 
			
		||||
    options.ca
 | 
			
		||||
  ) {
 | 
			
		||||
    if (options.passphrase) requestOptions.passphrase = options.passphrase;
 | 
			
		||||
    if (options.ciphers) requestOptions.ciphers = options.ciphers;
 | 
			
		||||
    if (options.ecdhCurve) requestOptions.ecdhCurve = options.ecdhCurve;
 | 
			
		||||
    if (options.cert) requestOptions.cert = options.cert;
 | 
			
		||||
    if (options.key) requestOptions.key = options.key;
 | 
			
		||||
    if (options.pfx) requestOptions.pfx = options.pfx;
 | 
			
		||||
    if (options.ca) requestOptions.ca = options.ca;
 | 
			
		||||
    if (options.checkServerIdentity) {
 | 
			
		||||
      requestOptions.checkServerIdentity = options.checkServerIdentity;
 | 
			
		||||
    }
 | 
			
		||||
    if (options.rejectUnauthorized != null) {
 | 
			
		||||
      requestOptions.rejectUnauthorized = options.rejectUnauthorized;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!agent) agent = new httpObj.Agent(requestOptions);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (agent) requestOptions.agent = agent;
 | 
			
		||||
 | 
			
		||||
  this._req = httpObj.get(requestOptions);
 | 
			
		||||
 | 
			
		||||
  if (options.handshakeTimeout) {
 | 
			
		||||
    this._req.setTimeout(options.handshakeTimeout, () => {
 | 
			
		||||
      this._req.abort();
 | 
			
		||||
      this.finalize(new Error('Opening handshake has timed out'));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this._req.on('error', (error) => {
 | 
			
		||||
    if (this._req.aborted) return;
 | 
			
		||||
 | 
			
		||||
    this._req = null;
 | 
			
		||||
    this.finalize(error);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  this._req.on('response', (res) => {
 | 
			
		||||
    if (!this.emit('unexpected-response', this._req, res)) {
 | 
			
		||||
      this._req.abort();
 | 
			
		||||
      this.finalize(new Error(`Unexpected server response: ${res.statusCode}`));
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  this._req.on('upgrade', (res, socket, head) => {
 | 
			
		||||
    this.emit('upgrade', res);
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // The user may have closed the connection from a listener of the `upgrade`
 | 
			
		||||
    // event.
 | 
			
		||||
    //
 | 
			
		||||
    if (this.readyState !== WebSocket.CONNECTING) return;
 | 
			
		||||
 | 
			
		||||
    this._req = null;
 | 
			
		||||
 | 
			
		||||
    const digest = crypto.createHash('sha1')
 | 
			
		||||
      .update(key + constants.GUID, 'binary')
 | 
			
		||||
      .digest('base64');
 | 
			
		||||
 | 
			
		||||
    if (res.headers['sec-websocket-accept'] !== digest) {
 | 
			
		||||
      socket.destroy();
 | 
			
		||||
      return this.finalize(new Error('Invalid Sec-WebSocket-Accept header'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const serverProt = res.headers['sec-websocket-protocol'];
 | 
			
		||||
    const protList = (options.protocol || '').split(/, */);
 | 
			
		||||
    var protError;
 | 
			
		||||
 | 
			
		||||
    if (!options.protocol && serverProt) {
 | 
			
		||||
      protError = 'Server sent a subprotocol but none was requested';
 | 
			
		||||
    } else if (options.protocol && !serverProt) {
 | 
			
		||||
      protError = 'Server sent no subprotocol';
 | 
			
		||||
    } else if (serverProt && protList.indexOf(serverProt) === -1) {
 | 
			
		||||
      protError = 'Server sent an invalid subprotocol';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (protError) {
 | 
			
		||||
      socket.destroy();
 | 
			
		||||
      return this.finalize(new Error(protError));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (serverProt) this.protocol = serverProt;
 | 
			
		||||
 | 
			
		||||
    if (perMessageDeflate) {
 | 
			
		||||
      try {
 | 
			
		||||
        const extensions = extension.parse(
 | 
			
		||||
          res.headers['sec-websocket-extensions']
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (extensions[PerMessageDeflate.extensionName]) {
 | 
			
		||||
          perMessageDeflate.accept(
 | 
			
		||||
            extensions[PerMessageDeflate.extensionName]
 | 
			
		||||
          );
 | 
			
		||||
          this._extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
 | 
			
		||||
        }
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        socket.destroy();
 | 
			
		||||
        this.finalize(new Error('Invalid Sec-WebSocket-Extensions header'));
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.setSocket(socket, head, 0);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user