|
import require$$0 from "stream"; |
|
import require$$0$2 from "zlib"; |
|
import require$$0$1 from "fs"; |
|
import require$$1$1 from "path"; |
|
import require$$2 from "os"; |
|
import require$$0$3 from "buffer"; |
|
import require$$3 from "net"; |
|
import require$$4 from "tls"; |
|
import require$$5 from "crypto"; |
|
import require$$0$4 from "events"; |
|
import require$$1$2 from "https"; |
|
import require$$2$1 from "http"; |
|
import require$$7 from "url"; |
|
function getDefaultExportFromCjs(x) { |
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; |
|
} |
|
function getAugmentedNamespace(n) { |
|
if (n.__esModule) |
|
return n; |
|
var f = n.default; |
|
if (typeof f == "function") { |
|
var a = function a2() { |
|
if (this instanceof a2) { |
|
return Reflect.construct(f, arguments, this.constructor); |
|
} |
|
return f.apply(this, arguments); |
|
}; |
|
a.prototype = f.prototype; |
|
} else |
|
a = {}; |
|
Object.defineProperty(a, "__esModule", { value: true }); |
|
Object.keys(n).forEach(function(k) { |
|
var d = Object.getOwnPropertyDescriptor(n, k); |
|
Object.defineProperty(a, k, d.get ? d : { |
|
enumerable: true, |
|
get: function() { |
|
return n[k]; |
|
} |
|
}); |
|
}); |
|
return a; |
|
} |
|
const { Duplex } = require$$0; |
|
function emitClose$1(stream2) { |
|
stream2.emit("close"); |
|
} |
|
function duplexOnEnd() { |
|
if (!this.destroyed && this._writableState.finished) { |
|
this.destroy(); |
|
} |
|
} |
|
function duplexOnError(err) { |
|
this.removeListener("error", duplexOnError); |
|
this.destroy(); |
|
if (this.listenerCount("error") === 0) { |
|
this.emit("error", err); |
|
} |
|
} |
|
function createWebSocketStream(ws, options) { |
|
let terminateOnDestroy = true; |
|
const duplex = new Duplex({ |
|
...options, |
|
autoDestroy: false, |
|
emitClose: false, |
|
objectMode: false, |
|
writableObjectMode: false |
|
}); |
|
ws.on("message", function message(msg, isBinary) { |
|
const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; |
|
if (!duplex.push(data)) |
|
ws.pause(); |
|
}); |
|
ws.once("error", function error2(err) { |
|
if (duplex.destroyed) |
|
return; |
|
terminateOnDestroy = false; |
|
duplex.destroy(err); |
|
}); |
|
ws.once("close", function close() { |
|
if (duplex.destroyed) |
|
return; |
|
duplex.push(null); |
|
}); |
|
duplex._destroy = function(err, callback) { |
|
if (ws.readyState === ws.CLOSED) { |
|
callback(err); |
|
process.nextTick(emitClose$1, duplex); |
|
return; |
|
} |
|
let called = false; |
|
ws.once("error", function error2(err2) { |
|
called = true; |
|
callback(err2); |
|
}); |
|
ws.once("close", function close() { |
|
if (!called) |
|
callback(err); |
|
process.nextTick(emitClose$1, duplex); |
|
}); |
|
if (terminateOnDestroy) |
|
ws.terminate(); |
|
}; |
|
duplex._final = function(callback) { |
|
if (ws.readyState === ws.CONNECTING) { |
|
ws.once("open", function open() { |
|
duplex._final(callback); |
|
}); |
|
return; |
|
} |
|
if (ws._socket === null) |
|
return; |
|
if (ws._socket._writableState.finished) { |
|
callback(); |
|
if (duplex._readableState.endEmitted) |
|
duplex.destroy(); |
|
} else { |
|
ws._socket.once("finish", function finish() { |
|
callback(); |
|
}); |
|
ws.close(); |
|
} |
|
}; |
|
duplex._read = function() { |
|
if (ws.isPaused) |
|
ws.resume(); |
|
}; |
|
duplex._write = function(chunk, encoding, callback) { |
|
if (ws.readyState === ws.CONNECTING) { |
|
ws.once("open", function open() { |
|
duplex._write(chunk, encoding, callback); |
|
}); |
|
return; |
|
} |
|
ws.send(chunk, callback); |
|
}; |
|
duplex.on("end", duplexOnEnd); |
|
duplex.on("error", duplexOnError); |
|
return duplex; |
|
} |
|
var stream = createWebSocketStream; |
|
const stream$1 = getDefaultExportFromCjs(stream); |
|
var bufferUtil$1 = { exports: {} }; |
|
var constants = { |
|
BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], |
|
EMPTY_BUFFER: Buffer.alloc(0), |
|
GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", |
|
kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), |
|
kListener: Symbol("kListener"), |
|
kStatusCode: Symbol("status-code"), |
|
kWebSocket: Symbol("websocket"), |
|
NOOP: () => { |
|
} |
|
}; |
|
var bufferutil = { exports: {} }; |
|
var nodeGypBuild$1 = { exports: {} }; |
|
function commonjsRequire(path) { |
|
throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); |
|
} |
|
var nodeGypBuild; |
|
var hasRequiredNodeGypBuild$1; |
|
function requireNodeGypBuild$1() { |
|
if (hasRequiredNodeGypBuild$1) |
|
return nodeGypBuild; |
|
hasRequiredNodeGypBuild$1 = 1; |
|
var fs = require$$0$1; |
|
var path = require$$1$1; |
|
var os = require$$2; |
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : commonjsRequire; |
|
var vars = process.config && process.config.variables || {}; |
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY; |
|
var abi = process.versions.modules; |
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node"; |
|
var arch = process.env.npm_config_arch || os.arch(); |
|
var platform = process.env.npm_config_platform || os.platform(); |
|
var libc = process.env.LIBC || (isAlpine(platform) ? "musl" : "glibc"); |
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || ""; |
|
var uv = (process.versions.uv || "").split(".")[0]; |
|
nodeGypBuild = load; |
|
function load(dir) { |
|
return runtimeRequire(load.resolve(dir)); |
|
} |
|
load.resolve = load.path = function(dir) { |
|
dir = path.resolve(dir || "."); |
|
try { |
|
var name = runtimeRequire(path.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_"); |
|
if (process.env[name + "_PREBUILD"]) |
|
dir = process.env[name + "_PREBUILD"]; |
|
} catch (err) { |
|
} |
|
if (!prebuildsOnly) { |
|
var release = getFirst(path.join(dir, "build/Release"), matchBuild); |
|
if (release) |
|
return release; |
|
var debug = getFirst(path.join(dir, "build/Debug"), matchBuild); |
|
if (debug) |
|
return debug; |
|
} |
|
var prebuild = resolve(dir); |
|
if (prebuild) |
|
return prebuild; |
|
var nearby = resolve(path.dirname(process.execPath)); |
|
if (nearby) |
|
return nearby; |
|
var target = [ |
|
"platform=" + platform, |
|
"arch=" + arch, |
|
"runtime=" + runtime, |
|
"abi=" + abi, |
|
"uv=" + uv, |
|
armv ? "armv=" + armv : "", |
|
"libc=" + libc, |
|
"node=" + process.versions.node, |
|
process.versions.electron ? "electron=" + process.versions.electron : "", |
|
typeof __webpack_require__ === "function" ? "webpack=true" : "" |
|
|
|
].filter(Boolean).join(" "); |
|
throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n"); |
|
function resolve(dir2) { |
|
var tuples = readdirSync(path.join(dir2, "prebuilds")).map(parseTuple); |
|
var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0]; |
|
if (!tuple) |
|
return; |
|
var prebuilds = path.join(dir2, "prebuilds", tuple.name); |
|
var parsed = readdirSync(prebuilds).map(parseTags); |
|
var candidates = parsed.filter(matchTags(runtime, abi)); |
|
var winner = candidates.sort(compareTags(runtime))[0]; |
|
if (winner) |
|
return path.join(prebuilds, winner.file); |
|
} |
|
}; |
|
function readdirSync(dir) { |
|
try { |
|
return fs.readdirSync(dir); |
|
} catch (err) { |
|
return []; |
|
} |
|
} |
|
function getFirst(dir, filter) { |
|
var files = readdirSync(dir).filter(filter); |
|
return files[0] && path.join(dir, files[0]); |
|
} |
|
function matchBuild(name) { |
|
return /\.node$/.test(name); |
|
} |
|
function parseTuple(name) { |
|
var arr = name.split("-"); |
|
if (arr.length !== 2) |
|
return; |
|
var platform2 = arr[0]; |
|
var architectures = arr[1].split("+"); |
|
if (!platform2) |
|
return; |
|
if (!architectures.length) |
|
return; |
|
if (!architectures.every(Boolean)) |
|
return; |
|
return { name, platform: platform2, architectures }; |
|
} |
|
function matchTuple(platform2, arch2) { |
|
return function(tuple) { |
|
if (tuple == null) |
|
return false; |
|
if (tuple.platform !== platform2) |
|
return false; |
|
return tuple.architectures.includes(arch2); |
|
}; |
|
} |
|
function compareTuples(a, b) { |
|
return a.architectures.length - b.architectures.length; |
|
} |
|
function parseTags(file) { |
|
var arr = file.split("."); |
|
var extension2 = arr.pop(); |
|
var tags = { file, specificity: 0 }; |
|
if (extension2 !== "node") |
|
return; |
|
for (var i = 0; i < arr.length; i++) { |
|
var tag = arr[i]; |
|
if (tag === "node" || tag === "electron" || tag === "node-webkit") { |
|
tags.runtime = tag; |
|
} else if (tag === "napi") { |
|
tags.napi = true; |
|
} else if (tag.slice(0, 3) === "abi") { |
|
tags.abi = tag.slice(3); |
|
} else if (tag.slice(0, 2) === "uv") { |
|
tags.uv = tag.slice(2); |
|
} else if (tag.slice(0, 4) === "armv") { |
|
tags.armv = tag.slice(4); |
|
} else if (tag === "glibc" || tag === "musl") { |
|
tags.libc = tag; |
|
} else { |
|
continue; |
|
} |
|
tags.specificity++; |
|
} |
|
return tags; |
|
} |
|
function matchTags(runtime2, abi2) { |
|
return function(tags) { |
|
if (tags == null) |
|
return false; |
|
if (tags.runtime !== runtime2 && !runtimeAgnostic(tags)) |
|
return false; |
|
if (tags.abi !== abi2 && !tags.napi) |
|
return false; |
|
if (tags.uv && tags.uv !== uv) |
|
return false; |
|
if (tags.armv && tags.armv !== armv) |
|
return false; |
|
if (tags.libc && tags.libc !== libc) |
|
return false; |
|
return true; |
|
}; |
|
} |
|
function runtimeAgnostic(tags) { |
|
return tags.runtime === "node" && tags.napi; |
|
} |
|
function compareTags(runtime2) { |
|
return function(a, b) { |
|
if (a.runtime !== b.runtime) { |
|
return a.runtime === runtime2 ? -1 : 1; |
|
} else if (a.abi !== b.abi) { |
|
return a.abi ? -1 : 1; |
|
} else if (a.specificity !== b.specificity) { |
|
return a.specificity > b.specificity ? -1 : 1; |
|
} else { |
|
return 0; |
|
} |
|
}; |
|
} |
|
function isNwjs() { |
|
return !!(process.versions && process.versions.nw); |
|
} |
|
function isElectron() { |
|
if (process.versions && process.versions.electron) |
|
return true; |
|
if (process.env.ELECTRON_RUN_AS_NODE) |
|
return true; |
|
return typeof window !== "undefined" && window.process && window.process.type === "renderer"; |
|
} |
|
function isAlpine(platform2) { |
|
return platform2 === "linux" && fs.existsSync("/etc/alpine-release"); |
|
} |
|
load.parseTags = parseTags; |
|
load.matchTags = matchTags; |
|
load.compareTags = compareTags; |
|
load.parseTuple = parseTuple; |
|
load.matchTuple = matchTuple; |
|
load.compareTuples = compareTuples; |
|
return nodeGypBuild; |
|
} |
|
var hasRequiredNodeGypBuild; |
|
function requireNodeGypBuild() { |
|
if (hasRequiredNodeGypBuild) |
|
return nodeGypBuild$1.exports; |
|
hasRequiredNodeGypBuild = 1; |
|
if (typeof process.addon === "function") { |
|
nodeGypBuild$1.exports = process.addon.bind(process); |
|
} else { |
|
nodeGypBuild$1.exports = requireNodeGypBuild$1(); |
|
} |
|
return nodeGypBuild$1.exports; |
|
} |
|
var fallback; |
|
var hasRequiredFallback; |
|
function requireFallback() { |
|
if (hasRequiredFallback) |
|
return fallback; |
|
hasRequiredFallback = 1; |
|
const mask2 = (source, mask3, output, offset, length) => { |
|
for (var i = 0; i < length; i++) { |
|
output[offset + i] = source[i] ^ mask3[i & 3]; |
|
} |
|
}; |
|
const unmask2 = (buffer, mask3) => { |
|
const length = buffer.length; |
|
for (var i = 0; i < length; i++) { |
|
buffer[i] ^= mask3[i & 3]; |
|
} |
|
}; |
|
fallback = { mask: mask2, unmask: unmask2 }; |
|
return fallback; |
|
} |
|
var hasRequiredBufferutil; |
|
function requireBufferutil() { |
|
if (hasRequiredBufferutil) |
|
return bufferutil.exports; |
|
hasRequiredBufferutil = 1; |
|
try { |
|
bufferutil.exports = requireNodeGypBuild()(__dirname); |
|
} catch (e) { |
|
bufferutil.exports = requireFallback(); |
|
} |
|
return bufferutil.exports; |
|
} |
|
var unmask$1; |
|
var mask; |
|
const { EMPTY_BUFFER: EMPTY_BUFFER$3 } = constants; |
|
const FastBuffer$2 = Buffer[Symbol.species]; |
|
function concat$1(list, totalLength) { |
|
if (list.length === 0) |
|
return EMPTY_BUFFER$3; |
|
if (list.length === 1) |
|
return list[0]; |
|
const target = Buffer.allocUnsafe(totalLength); |
|
let offset = 0; |
|
for (let i = 0; i < list.length; i++) { |
|
const buf = list[i]; |
|
target.set(buf, offset); |
|
offset += buf.length; |
|
} |
|
if (offset < totalLength) { |
|
return new FastBuffer$2(target.buffer, target.byteOffset, offset); |
|
} |
|
return target; |
|
} |
|
function _mask(source, mask2, output, offset, length) { |
|
for (let i = 0; i < length; i++) { |
|
output[offset + i] = source[i] ^ mask2[i & 3]; |
|
} |
|
} |
|
function _unmask(buffer, mask2) { |
|
for (let i = 0; i < buffer.length; i++) { |
|
buffer[i] ^= mask2[i & 3]; |
|
} |
|
} |
|
function toArrayBuffer$1(buf) { |
|
if (buf.length === buf.buffer.byteLength) { |
|
return buf.buffer; |
|
} |
|
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length); |
|
} |
|
function toBuffer$2(data) { |
|
toBuffer$2.readOnly = true; |
|
if (Buffer.isBuffer(data)) |
|
return data; |
|
let buf; |
|
if (data instanceof ArrayBuffer) { |
|
buf = new FastBuffer$2(data); |
|
} else if (ArrayBuffer.isView(data)) { |
|
buf = new FastBuffer$2(data.buffer, data.byteOffset, data.byteLength); |
|
} else { |
|
buf = Buffer.from(data); |
|
toBuffer$2.readOnly = false; |
|
} |
|
return buf; |
|
} |
|
bufferUtil$1.exports = { |
|
concat: concat$1, |
|
mask: _mask, |
|
toArrayBuffer: toArrayBuffer$1, |
|
toBuffer: toBuffer$2, |
|
unmask: _unmask |
|
}; |
|
if (!process.env.WS_NO_BUFFER_UTIL) { |
|
try { |
|
const bufferUtil2 = requireBufferutil(); |
|
mask = bufferUtil$1.exports.mask = function(source, mask2, output, offset, length) { |
|
if (length < 48) |
|
_mask(source, mask2, output, offset, length); |
|
else |
|
bufferUtil2.mask(source, mask2, output, offset, length); |
|
}; |
|
unmask$1 = bufferUtil$1.exports.unmask = function(buffer, mask2) { |
|
if (buffer.length < 32) |
|
_unmask(buffer, mask2); |
|
else |
|
bufferUtil2.unmask(buffer, mask2); |
|
}; |
|
} catch (e) { |
|
} |
|
} |
|
var bufferUtilExports = bufferUtil$1.exports; |
|
const kDone = Symbol("kDone"); |
|
const kRun = Symbol("kRun"); |
|
let Limiter$1 = class Limiter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(concurrency) { |
|
this[kDone] = () => { |
|
this.pending--; |
|
this[kRun](); |
|
}; |
|
this.concurrency = concurrency || Infinity; |
|
this.jobs = []; |
|
this.pending = 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
add(job) { |
|
this.jobs.push(job); |
|
this[kRun](); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
[kRun]() { |
|
if (this.pending === this.concurrency) |
|
return; |
|
if (this.jobs.length) { |
|
const job = this.jobs.shift(); |
|
this.pending++; |
|
job(this[kDone]); |
|
} |
|
} |
|
}; |
|
var limiter = Limiter$1; |
|
const zlib = require$$0$2; |
|
const bufferUtil = bufferUtilExports; |
|
const Limiter2 = limiter; |
|
const { kStatusCode: kStatusCode$2 } = constants; |
|
const FastBuffer$1 = Buffer[Symbol.species]; |
|
const TRAILER = Buffer.from([0, 0, 255, 255]); |
|
const kPerMessageDeflate = Symbol("permessage-deflate"); |
|
const kTotalLength = Symbol("total-length"); |
|
const kCallback = Symbol("callback"); |
|
const kBuffers = Symbol("buffers"); |
|
const kError$1 = Symbol("error"); |
|
let zlibLimiter; |
|
let PerMessageDeflate$4 = class PerMessageDeflate { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(options, isServer, maxPayload) { |
|
this._maxPayload = maxPayload | 0; |
|
this._options = options || {}; |
|
this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; |
|
this._isServer = !!isServer; |
|
this._deflate = null; |
|
this._inflate = null; |
|
this.params = null; |
|
if (!zlibLimiter) { |
|
const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; |
|
zlibLimiter = new Limiter2(concurrency); |
|
} |
|
} |
|
|
|
|
|
|
|
static get extensionName() { |
|
return "permessage-deflate"; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
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(configurations) { |
|
configurations = this.normalizeParams(configurations); |
|
this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); |
|
return this.params; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
cleanup() { |
|
if (this._inflate) { |
|
this._inflate.close(); |
|
this._inflate = null; |
|
} |
|
if (this._deflate) { |
|
const callback = this._deflate[kCallback]; |
|
this._deflate.close(); |
|
this._deflate = null; |
|
if (callback) { |
|
callback( |
|
new Error( |
|
"The deflate stream was closed while data was being processed" |
|
) |
|
); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
normalizeParams(configurations) { |
|
configurations.forEach((params) => { |
|
Object.keys(params).forEach((key) => { |
|
let 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, fin, callback) { |
|
zlibLimiter.add((done) => { |
|
this._decompress(data, fin, (err, result) => { |
|
done(); |
|
callback(err, result); |
|
}); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
compress(data, fin, callback) { |
|
zlibLimiter.add((done) => { |
|
this._compress(data, fin, (err, result) => { |
|
done(); |
|
callback(err, result); |
|
}); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_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({ |
|
...this._options.zlibInflateOptions, |
|
windowBits |
|
}); |
|
this._inflate[kPerMessageDeflate] = this; |
|
this._inflate[kTotalLength] = 0; |
|
this._inflate[kBuffers] = []; |
|
this._inflate.on("error", inflateOnError); |
|
this._inflate.on("data", inflateOnData); |
|
} |
|
this._inflate[kCallback] = callback; |
|
this._inflate.write(data); |
|
if (fin) |
|
this._inflate.write(TRAILER); |
|
this._inflate.flush(() => { |
|
const err = this._inflate[kError$1]; |
|
if (err) { |
|
this._inflate.close(); |
|
this._inflate = null; |
|
callback(err); |
|
return; |
|
} |
|
const data2 = bufferUtil.concat( |
|
this._inflate[kBuffers], |
|
this._inflate[kTotalLength] |
|
); |
|
if (this._inflate._readableState.endEmitted) { |
|
this._inflate.close(); |
|
this._inflate = null; |
|
} else { |
|
this._inflate[kTotalLength] = 0; |
|
this._inflate[kBuffers] = []; |
|
if (fin && this.params[`${endpoint}_no_context_takeover`]) { |
|
this._inflate.reset(); |
|
} |
|
} |
|
callback(null, data2); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_compress(data, fin, callback) { |
|
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({ |
|
...this._options.zlibDeflateOptions, |
|
windowBits |
|
}); |
|
this._deflate[kTotalLength] = 0; |
|
this._deflate[kBuffers] = []; |
|
this._deflate.on("data", deflateOnData); |
|
} |
|
this._deflate[kCallback] = callback; |
|
this._deflate.write(data); |
|
this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { |
|
if (!this._deflate) { |
|
return; |
|
} |
|
let data2 = bufferUtil.concat( |
|
this._deflate[kBuffers], |
|
this._deflate[kTotalLength] |
|
); |
|
if (fin) { |
|
data2 = new FastBuffer$1(data2.buffer, data2.byteOffset, data2.length - 4); |
|
} |
|
this._deflate[kCallback] = null; |
|
this._deflate[kTotalLength] = 0; |
|
this._deflate[kBuffers] = []; |
|
if (fin && this.params[`${endpoint}_no_context_takeover`]) { |
|
this._deflate.reset(); |
|
} |
|
callback(null, data2); |
|
}); |
|
} |
|
}; |
|
var permessageDeflate = PerMessageDeflate$4; |
|
function deflateOnData(chunk) { |
|
this[kBuffers].push(chunk); |
|
this[kTotalLength] += chunk.length; |
|
} |
|
function inflateOnData(chunk) { |
|
this[kTotalLength] += chunk.length; |
|
if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { |
|
this[kBuffers].push(chunk); |
|
return; |
|
} |
|
this[kError$1] = new RangeError("Max payload size exceeded"); |
|
this[kError$1].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"; |
|
this[kError$1][kStatusCode$2] = 1009; |
|
this.removeListener("data", inflateOnData); |
|
this.reset(); |
|
} |
|
function inflateOnError(err) { |
|
this[kPerMessageDeflate]._inflate = null; |
|
err[kStatusCode$2] = 1007; |
|
this[kCallback](err); |
|
} |
|
var validation = { exports: {} }; |
|
const __viteOptionalPeerDep_utf8Validate_ws = {}; |
|
const __viteOptionalPeerDep_utf8Validate_ws$1 = Object.freeze( Object.defineProperty({ |
|
__proto__: null, |
|
default: __viteOptionalPeerDep_utf8Validate_ws |
|
}, Symbol.toStringTag, { value: "Module" })); |
|
const require$$1 = getAugmentedNamespace(__viteOptionalPeerDep_utf8Validate_ws$1); |
|
var isValidUTF8_1; |
|
const { isUtf8 } = require$$0$3; |
|
const tokenChars$2 = [ |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
|
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
|
|
0, |
|
1, |
|
0, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
0, |
|
0, |
|
1, |
|
1, |
|
0, |
|
1, |
|
1, |
|
0, |
|
|
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
|
|
0, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
|
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
0, |
|
0, |
|
0, |
|
1, |
|
1, |
|
|
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
|
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
1, |
|
0, |
|
1, |
|
0, |
|
1, |
|
0 |
|
|
|
]; |
|
function isValidStatusCode$2(code) { |
|
return code >= 1e3 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006 || code >= 3e3 && code <= 4999; |
|
} |
|
function _isValidUTF8(buf) { |
|
const len = buf.length; |
|
let i = 0; |
|
while (i < len) { |
|
if ((buf[i] & 128) === 0) { |
|
i++; |
|
} else if ((buf[i] & 224) === 192) { |
|
if (i + 1 === len || (buf[i + 1] & 192) !== 128 || (buf[i] & 254) === 192) { |
|
return false; |
|
} |
|
i += 2; |
|
} else if ((buf[i] & 240) === 224) { |
|
if (i + 2 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || buf[i] === 224 && (buf[i + 1] & 224) === 128 || |
|
buf[i] === 237 && (buf[i + 1] & 224) === 160) { |
|
return false; |
|
} |
|
i += 3; |
|
} else if ((buf[i] & 248) === 240) { |
|
if (i + 3 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || (buf[i + 3] & 192) !== 128 || buf[i] === 240 && (buf[i + 1] & 240) === 128 || |
|
buf[i] === 244 && buf[i + 1] > 143 || buf[i] > 244) { |
|
return false; |
|
} |
|
i += 4; |
|
} else { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
validation.exports = { |
|
isValidStatusCode: isValidStatusCode$2, |
|
isValidUTF8: _isValidUTF8, |
|
tokenChars: tokenChars$2 |
|
}; |
|
if (isUtf8) { |
|
isValidUTF8_1 = validation.exports.isValidUTF8 = function(buf) { |
|
return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf); |
|
}; |
|
} else if (!process.env.WS_NO_UTF_8_VALIDATE) { |
|
try { |
|
const isValidUTF82 = require$$1; |
|
isValidUTF8_1 = validation.exports.isValidUTF8 = function(buf) { |
|
return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF82(buf); |
|
}; |
|
} catch (e) { |
|
} |
|
} |
|
var validationExports = validation.exports; |
|
const { Writable } = require$$0; |
|
const PerMessageDeflate$3 = permessageDeflate; |
|
const { |
|
BINARY_TYPES: BINARY_TYPES$1, |
|
EMPTY_BUFFER: EMPTY_BUFFER$2, |
|
kStatusCode: kStatusCode$1, |
|
kWebSocket: kWebSocket$2 |
|
} = constants; |
|
const { concat, toArrayBuffer, unmask } = bufferUtilExports; |
|
const { isValidStatusCode: isValidStatusCode$1, isValidUTF8 } = validationExports; |
|
const FastBuffer = Buffer[Symbol.species]; |
|
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; |
|
let Receiver$1 = class Receiver extends Writable { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(options = {}) { |
|
super(); |
|
this._binaryType = options.binaryType || BINARY_TYPES$1[0]; |
|
this._extensions = options.extensions || {}; |
|
this._isServer = !!options.isServer; |
|
this._maxPayload = options.maxPayload | 0; |
|
this._skipUTF8Validation = !!options.skipUTF8Validation; |
|
this[kWebSocket$2] = void 0; |
|
this._bufferedBytes = 0; |
|
this._buffers = []; |
|
this._compressed = false; |
|
this._payloadLength = 0; |
|
this._mask = void 0; |
|
this._fragmented = 0; |
|
this._masked = false; |
|
this._fin = false; |
|
this._opcode = 0; |
|
this._totalPayloadLength = 0; |
|
this._messageLength = 0; |
|
this._fragments = []; |
|
this._state = GET_INFO; |
|
this._loop = false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_write(chunk, encoding, cb) { |
|
if (this._opcode === 8 && this._state == GET_INFO) |
|
return cb(); |
|
this._bufferedBytes += chunk.length; |
|
this._buffers.push(chunk); |
|
this.startLoop(cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
consume(n) { |
|
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] = new FastBuffer( |
|
buf.buffer, |
|
buf.byteOffset + n, |
|
buf.length - n |
|
); |
|
return new FastBuffer(buf.buffer, buf.byteOffset, n); |
|
} |
|
const dst = Buffer.allocUnsafe(n); |
|
do { |
|
const buf = this._buffers[0]; |
|
const offset = dst.length - n; |
|
if (n >= buf.length) { |
|
dst.set(this._buffers.shift(), offset); |
|
} else { |
|
dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); |
|
this._buffers[0] = new FastBuffer( |
|
buf.buffer, |
|
buf.byteOffset + n, |
|
buf.length - n |
|
); |
|
} |
|
n -= buf.length; |
|
} while (n > 0); |
|
return dst; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
startLoop(cb) { |
|
let err; |
|
this._loop = true; |
|
do { |
|
switch (this._state) { |
|
case GET_INFO: |
|
err = this.getInfo(); |
|
break; |
|
case GET_PAYLOAD_LENGTH_16: |
|
err = this.getPayloadLength16(); |
|
break; |
|
case GET_PAYLOAD_LENGTH_64: |
|
err = this.getPayloadLength64(); |
|
break; |
|
case GET_MASK: |
|
this.getMask(); |
|
break; |
|
case GET_DATA: |
|
err = this.getData(cb); |
|
break; |
|
default: |
|
this._loop = false; |
|
return; |
|
} |
|
} while (this._loop); |
|
cb(err); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
getInfo() { |
|
if (this._bufferedBytes < 2) { |
|
this._loop = false; |
|
return; |
|
} |
|
const buf = this.consume(2); |
|
if ((buf[0] & 48) !== 0) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"RSV2 and RSV3 must be clear", |
|
true, |
|
1002, |
|
"WS_ERR_UNEXPECTED_RSV_2_3" |
|
); |
|
} |
|
const compressed = (buf[0] & 64) === 64; |
|
if (compressed && !this._extensions[PerMessageDeflate$3.extensionName]) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"RSV1 must be clear", |
|
true, |
|
1002, |
|
"WS_ERR_UNEXPECTED_RSV_1" |
|
); |
|
} |
|
this._fin = (buf[0] & 128) === 128; |
|
this._opcode = buf[0] & 15; |
|
this._payloadLength = buf[1] & 127; |
|
if (this._opcode === 0) { |
|
if (compressed) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"RSV1 must be clear", |
|
true, |
|
1002, |
|
"WS_ERR_UNEXPECTED_RSV_1" |
|
); |
|
} |
|
if (!this._fragmented) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"invalid opcode 0", |
|
true, |
|
1002, |
|
"WS_ERR_INVALID_OPCODE" |
|
); |
|
} |
|
this._opcode = this._fragmented; |
|
} else if (this._opcode === 1 || this._opcode === 2) { |
|
if (this._fragmented) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
`invalid opcode ${this._opcode}`, |
|
true, |
|
1002, |
|
"WS_ERR_INVALID_OPCODE" |
|
); |
|
} |
|
this._compressed = compressed; |
|
} else if (this._opcode > 7 && this._opcode < 11) { |
|
if (!this._fin) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"FIN must be set", |
|
true, |
|
1002, |
|
"WS_ERR_EXPECTED_FIN" |
|
); |
|
} |
|
if (compressed) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"RSV1 must be clear", |
|
true, |
|
1002, |
|
"WS_ERR_UNEXPECTED_RSV_1" |
|
); |
|
} |
|
if (this._payloadLength > 125 || this._opcode === 8 && this._payloadLength === 1) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
`invalid payload length ${this._payloadLength}`, |
|
true, |
|
1002, |
|
"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" |
|
); |
|
} |
|
} else { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
`invalid opcode ${this._opcode}`, |
|
true, |
|
1002, |
|
"WS_ERR_INVALID_OPCODE" |
|
); |
|
} |
|
if (!this._fin && !this._fragmented) |
|
this._fragmented = this._opcode; |
|
this._masked = (buf[1] & 128) === 128; |
|
if (this._isServer) { |
|
if (!this._masked) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"MASK must be set", |
|
true, |
|
1002, |
|
"WS_ERR_EXPECTED_MASK" |
|
); |
|
} |
|
} else if (this._masked) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"MASK must be clear", |
|
true, |
|
1002, |
|
"WS_ERR_UNEXPECTED_MASK" |
|
); |
|
} |
|
if (this._payloadLength === 126) |
|
this._state = GET_PAYLOAD_LENGTH_16; |
|
else if (this._payloadLength === 127) |
|
this._state = GET_PAYLOAD_LENGTH_64; |
|
else |
|
return this.haveLength(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
getPayloadLength16() { |
|
if (this._bufferedBytes < 2) { |
|
this._loop = false; |
|
return; |
|
} |
|
this._payloadLength = this.consume(2).readUInt16BE(0); |
|
return this.haveLength(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
getPayloadLength64() { |
|
if (this._bufferedBytes < 8) { |
|
this._loop = false; |
|
return; |
|
} |
|
const buf = this.consume(8); |
|
const num = buf.readUInt32BE(0); |
|
if (num > Math.pow(2, 53 - 32) - 1) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"Unsupported WebSocket frame: payload length > 2^53 - 1", |
|
false, |
|
1009, |
|
"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" |
|
); |
|
} |
|
this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); |
|
return this.haveLength(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
haveLength() { |
|
if (this._payloadLength && this._opcode < 8) { |
|
this._totalPayloadLength += this._payloadLength; |
|
if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
"Max payload size exceeded", |
|
false, |
|
1009, |
|
"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" |
|
); |
|
} |
|
} |
|
if (this._masked) |
|
this._state = GET_MASK; |
|
else |
|
this._state = GET_DATA; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
getMask() { |
|
if (this._bufferedBytes < 4) { |
|
this._loop = false; |
|
return; |
|
} |
|
this._mask = this.consume(4); |
|
this._state = GET_DATA; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getData(cb) { |
|
let data = EMPTY_BUFFER$2; |
|
if (this._payloadLength) { |
|
if (this._bufferedBytes < this._payloadLength) { |
|
this._loop = false; |
|
return; |
|
} |
|
data = this.consume(this._payloadLength); |
|
if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) { |
|
unmask(data, this._mask); |
|
} |
|
} |
|
if (this._opcode > 7) |
|
return this.controlMessage(data); |
|
if (this._compressed) { |
|
this._state = INFLATING; |
|
this.decompress(data, cb); |
|
return; |
|
} |
|
if (data.length) { |
|
this._messageLength = this._totalPayloadLength; |
|
this._fragments.push(data); |
|
} |
|
return this.dataMessage(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decompress(data, cb) { |
|
const perMessageDeflate = this._extensions[PerMessageDeflate$3.extensionName]; |
|
perMessageDeflate.decompress(data, this._fin, (err, buf) => { |
|
if (err) |
|
return cb(err); |
|
if (buf.length) { |
|
this._messageLength += buf.length; |
|
if (this._messageLength > this._maxPayload && this._maxPayload > 0) { |
|
return cb( |
|
error( |
|
RangeError, |
|
"Max payload size exceeded", |
|
false, |
|
1009, |
|
"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" |
|
) |
|
); |
|
} |
|
this._fragments.push(buf); |
|
} |
|
const er = this.dataMessage(); |
|
if (er) |
|
return cb(er); |
|
this.startLoop(cb); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
let data; |
|
if (this._binaryType === "nodebuffer") { |
|
data = concat(fragments, messageLength); |
|
} else if (this._binaryType === "arraybuffer") { |
|
data = toArrayBuffer(concat(fragments, messageLength)); |
|
} else { |
|
data = fragments; |
|
} |
|
this.emit("message", data, true); |
|
} else { |
|
const buf = concat(fragments, messageLength); |
|
if (!this._skipUTF8Validation && !isValidUTF8(buf)) { |
|
this._loop = false; |
|
return error( |
|
Error, |
|
"invalid UTF-8 sequence", |
|
true, |
|
1007, |
|
"WS_ERR_INVALID_UTF8" |
|
); |
|
} |
|
this.emit("message", buf, false); |
|
} |
|
} |
|
this._state = GET_INFO; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
controlMessage(data) { |
|
if (this._opcode === 8) { |
|
this._loop = false; |
|
if (data.length === 0) { |
|
this.emit("conclude", 1005, EMPTY_BUFFER$2); |
|
this.end(); |
|
} else { |
|
const code = data.readUInt16BE(0); |
|
if (!isValidStatusCode$1(code)) { |
|
return error( |
|
RangeError, |
|
`invalid status code ${code}`, |
|
true, |
|
1002, |
|
"WS_ERR_INVALID_CLOSE_CODE" |
|
); |
|
} |
|
const buf = new FastBuffer( |
|
data.buffer, |
|
data.byteOffset + 2, |
|
data.length - 2 |
|
); |
|
if (!this._skipUTF8Validation && !isValidUTF8(buf)) { |
|
return error( |
|
Error, |
|
"invalid UTF-8 sequence", |
|
true, |
|
1007, |
|
"WS_ERR_INVALID_UTF8" |
|
); |
|
} |
|
this.emit("conclude", code, buf); |
|
this.end(); |
|
} |
|
} else if (this._opcode === 9) { |
|
this.emit("ping", data); |
|
} else { |
|
this.emit("pong", data); |
|
} |
|
this._state = GET_INFO; |
|
} |
|
}; |
|
var receiver = Receiver$1; |
|
function error(ErrorCtor, message, prefix, statusCode, errorCode) { |
|
const err = new ErrorCtor( |
|
prefix ? `Invalid WebSocket frame: ${message}` : message |
|
); |
|
Error.captureStackTrace(err, error); |
|
err.code = errorCode; |
|
err[kStatusCode$1] = statusCode; |
|
return err; |
|
} |
|
const receiver$1 = getDefaultExportFromCjs(receiver); |
|
const { randomFillSync } = require$$5; |
|
const PerMessageDeflate$2 = permessageDeflate; |
|
const { EMPTY_BUFFER: EMPTY_BUFFER$1 } = constants; |
|
const { isValidStatusCode } = validationExports; |
|
const { mask: applyMask, toBuffer: toBuffer$1 } = bufferUtilExports; |
|
const kByteLength = Symbol("kByteLength"); |
|
const maskBuffer = Buffer.alloc(4); |
|
let Sender$1 = class Sender { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(socket, extensions, generateMask) { |
|
this._extensions = extensions || {}; |
|
if (generateMask) { |
|
this._generateMask = generateMask; |
|
this._maskBuffer = Buffer.alloc(4); |
|
} |
|
this._socket = socket; |
|
this._firstFragment = true; |
|
this._compress = false; |
|
this._bufferedBytes = 0; |
|
this._deflating = false; |
|
this._queue = []; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static frame(data, options) { |
|
let mask2; |
|
let merge = false; |
|
let offset = 2; |
|
let skipMasking = false; |
|
if (options.mask) { |
|
mask2 = options.maskBuffer || maskBuffer; |
|
if (options.generateMask) { |
|
options.generateMask(mask2); |
|
} else { |
|
randomFillSync(mask2, 0, 4); |
|
} |
|
skipMasking = (mask2[0] | mask2[1] | mask2[2] | mask2[3]) === 0; |
|
offset = 6; |
|
} |
|
let dataLength; |
|
if (typeof data === "string") { |
|
if ((!options.mask || skipMasking) && options[kByteLength] !== void 0) { |
|
dataLength = options[kByteLength]; |
|
} else { |
|
data = Buffer.from(data); |
|
dataLength = data.length; |
|
} |
|
} else { |
|
dataLength = data.length; |
|
merge = options.mask && options.readOnly && !skipMasking; |
|
} |
|
let payloadLength = dataLength; |
|
if (dataLength >= 65536) { |
|
offset += 8; |
|
payloadLength = 127; |
|
} else if (dataLength > 125) { |
|
offset += 2; |
|
payloadLength = 126; |
|
} |
|
const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset); |
|
target[0] = options.fin ? options.opcode | 128 : options.opcode; |
|
if (options.rsv1) |
|
target[0] |= 64; |
|
target[1] = payloadLength; |
|
if (payloadLength === 126) { |
|
target.writeUInt16BE(dataLength, 2); |
|
} else if (payloadLength === 127) { |
|
target[2] = target[3] = 0; |
|
target.writeUIntBE(dataLength, 4, 6); |
|
} |
|
if (!options.mask) |
|
return [target, data]; |
|
target[1] |= 128; |
|
target[offset - 4] = mask2[0]; |
|
target[offset - 3] = mask2[1]; |
|
target[offset - 2] = mask2[2]; |
|
target[offset - 1] = mask2[3]; |
|
if (skipMasking) |
|
return [target, data]; |
|
if (merge) { |
|
applyMask(data, mask2, target, offset, dataLength); |
|
return [target]; |
|
} |
|
applyMask(data, mask2, data, 0, dataLength); |
|
return [target, data]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close(code, data, mask2, cb) { |
|
let buf; |
|
if (code === void 0) { |
|
buf = EMPTY_BUFFER$1; |
|
} else if (typeof code !== "number" || !isValidStatusCode(code)) { |
|
throw new TypeError("First argument must be a valid error code number"); |
|
} else if (data === void 0 || !data.length) { |
|
buf = Buffer.allocUnsafe(2); |
|
buf.writeUInt16BE(code, 0); |
|
} else { |
|
const length = Buffer.byteLength(data); |
|
if (length > 123) { |
|
throw new RangeError("The message must not be greater than 123 bytes"); |
|
} |
|
buf = Buffer.allocUnsafe(2 + length); |
|
buf.writeUInt16BE(code, 0); |
|
if (typeof data === "string") { |
|
buf.write(data, 2); |
|
} else { |
|
buf.set(data, 2); |
|
} |
|
} |
|
const options = { |
|
[kByteLength]: buf.length, |
|
fin: true, |
|
generateMask: this._generateMask, |
|
mask: mask2, |
|
maskBuffer: this._maskBuffer, |
|
opcode: 8, |
|
readOnly: false, |
|
rsv1: false |
|
}; |
|
if (this._deflating) { |
|
this.enqueue([this.dispatch, buf, false, options, cb]); |
|
} else { |
|
this.sendFrame(Sender.frame(buf, options), cb); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ping(data, mask2, cb) { |
|
let byteLength; |
|
let readOnly; |
|
if (typeof data === "string") { |
|
byteLength = Buffer.byteLength(data); |
|
readOnly = false; |
|
} else { |
|
data = toBuffer$1(data); |
|
byteLength = data.length; |
|
readOnly = toBuffer$1.readOnly; |
|
} |
|
if (byteLength > 125) { |
|
throw new RangeError("The data size must not be greater than 125 bytes"); |
|
} |
|
const options = { |
|
[kByteLength]: byteLength, |
|
fin: true, |
|
generateMask: this._generateMask, |
|
mask: mask2, |
|
maskBuffer: this._maskBuffer, |
|
opcode: 9, |
|
readOnly, |
|
rsv1: false |
|
}; |
|
if (this._deflating) { |
|
this.enqueue([this.dispatch, data, false, options, cb]); |
|
} else { |
|
this.sendFrame(Sender.frame(data, options), cb); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pong(data, mask2, cb) { |
|
let byteLength; |
|
let readOnly; |
|
if (typeof data === "string") { |
|
byteLength = Buffer.byteLength(data); |
|
readOnly = false; |
|
} else { |
|
data = toBuffer$1(data); |
|
byteLength = data.length; |
|
readOnly = toBuffer$1.readOnly; |
|
} |
|
if (byteLength > 125) { |
|
throw new RangeError("The data size must not be greater than 125 bytes"); |
|
} |
|
const options = { |
|
[kByteLength]: byteLength, |
|
fin: true, |
|
generateMask: this._generateMask, |
|
mask: mask2, |
|
maskBuffer: this._maskBuffer, |
|
opcode: 10, |
|
readOnly, |
|
rsv1: false |
|
}; |
|
if (this._deflating) { |
|
this.enqueue([this.dispatch, data, false, options, cb]); |
|
} else { |
|
this.sendFrame(Sender.frame(data, options), cb); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
send(data, options, cb) { |
|
const perMessageDeflate = this._extensions[PerMessageDeflate$2.extensionName]; |
|
let opcode = options.binary ? 2 : 1; |
|
let rsv1 = options.compress; |
|
let byteLength; |
|
let readOnly; |
|
if (typeof data === "string") { |
|
byteLength = Buffer.byteLength(data); |
|
readOnly = false; |
|
} else { |
|
data = toBuffer$1(data); |
|
byteLength = data.length; |
|
readOnly = toBuffer$1.readOnly; |
|
} |
|
if (this._firstFragment) { |
|
this._firstFragment = false; |
|
if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) { |
|
rsv1 = byteLength >= perMessageDeflate._threshold; |
|
} |
|
this._compress = rsv1; |
|
} else { |
|
rsv1 = false; |
|
opcode = 0; |
|
} |
|
if (options.fin) |
|
this._firstFragment = true; |
|
if (perMessageDeflate) { |
|
const opts = { |
|
[kByteLength]: byteLength, |
|
fin: options.fin, |
|
generateMask: this._generateMask, |
|
mask: options.mask, |
|
maskBuffer: this._maskBuffer, |
|
opcode, |
|
readOnly, |
|
rsv1 |
|
}; |
|
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, { |
|
[kByteLength]: byteLength, |
|
fin: options.fin, |
|
generateMask: this._generateMask, |
|
mask: options.mask, |
|
maskBuffer: this._maskBuffer, |
|
opcode, |
|
readOnly, |
|
rsv1: false |
|
}), |
|
cb |
|
); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dispatch(data, compress, options, cb) { |
|
if (!compress) { |
|
this.sendFrame(Sender.frame(data, options), cb); |
|
return; |
|
} |
|
const perMessageDeflate = this._extensions[PerMessageDeflate$2.extensionName]; |
|
this._bufferedBytes += options[kByteLength]; |
|
this._deflating = true; |
|
perMessageDeflate.compress(data, options.fin, (_, buf) => { |
|
if (this._socket.destroyed) { |
|
const err = new Error( |
|
"The socket was closed while data was being compressed" |
|
); |
|
if (typeof cb === "function") |
|
cb(err); |
|
for (let i = 0; i < this._queue.length; i++) { |
|
const params = this._queue[i]; |
|
const callback = params[params.length - 1]; |
|
if (typeof callback === "function") |
|
callback(err); |
|
} |
|
return; |
|
} |
|
this._bufferedBytes -= options[kByteLength]; |
|
this._deflating = false; |
|
options.readOnly = false; |
|
this.sendFrame(Sender.frame(buf, options), cb); |
|
this.dequeue(); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
dequeue() { |
|
while (!this._deflating && this._queue.length) { |
|
const params = this._queue.shift(); |
|
this._bufferedBytes -= params[3][kByteLength]; |
|
Reflect.apply(params[0], this, params.slice(1)); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
enqueue(params) { |
|
this._bufferedBytes += params[3][kByteLength]; |
|
this._queue.push(params); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sendFrame(list, cb) { |
|
if (list.length === 2) { |
|
this._socket.cork(); |
|
this._socket.write(list[0]); |
|
this._socket.write(list[1], cb); |
|
this._socket.uncork(); |
|
} else { |
|
this._socket.write(list[0], cb); |
|
} |
|
} |
|
}; |
|
var sender = Sender$1; |
|
const sender$1 = getDefaultExportFromCjs(sender); |
|
const { kForOnEventAttribute: kForOnEventAttribute$1, kListener: kListener$1 } = constants; |
|
const kCode = Symbol("kCode"); |
|
const kData = Symbol("kData"); |
|
const kError = Symbol("kError"); |
|
const kMessage = Symbol("kMessage"); |
|
const kReason = Symbol("kReason"); |
|
const kTarget = Symbol("kTarget"); |
|
const kType = Symbol("kType"); |
|
const kWasClean = Symbol("kWasClean"); |
|
class Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type) { |
|
this[kTarget] = null; |
|
this[kType] = type; |
|
} |
|
|
|
|
|
|
|
get target() { |
|
return this[kTarget]; |
|
} |
|
|
|
|
|
|
|
get type() { |
|
return this[kType]; |
|
} |
|
} |
|
Object.defineProperty(Event.prototype, "target", { enumerable: true }); |
|
Object.defineProperty(Event.prototype, "type", { enumerable: true }); |
|
class CloseEvent extends Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type, options = {}) { |
|
super(type); |
|
this[kCode] = options.code === void 0 ? 0 : options.code; |
|
this[kReason] = options.reason === void 0 ? "" : options.reason; |
|
this[kWasClean] = options.wasClean === void 0 ? false : options.wasClean; |
|
} |
|
|
|
|
|
|
|
get code() { |
|
return this[kCode]; |
|
} |
|
|
|
|
|
|
|
get reason() { |
|
return this[kReason]; |
|
} |
|
|
|
|
|
|
|
get wasClean() { |
|
return this[kWasClean]; |
|
} |
|
} |
|
Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true }); |
|
Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true }); |
|
Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true }); |
|
class ErrorEvent extends Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type, options = {}) { |
|
super(type); |
|
this[kError] = options.error === void 0 ? null : options.error; |
|
this[kMessage] = options.message === void 0 ? "" : options.message; |
|
} |
|
|
|
|
|
|
|
get error() { |
|
return this[kError]; |
|
} |
|
|
|
|
|
|
|
get message() { |
|
return this[kMessage]; |
|
} |
|
} |
|
Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true }); |
|
Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true }); |
|
class MessageEvent extends Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type, options = {}) { |
|
super(type); |
|
this[kData] = options.data === void 0 ? null : options.data; |
|
} |
|
|
|
|
|
|
|
get data() { |
|
return this[kData]; |
|
} |
|
} |
|
Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true }); |
|
const EventTarget = { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addEventListener(type, handler, options = {}) { |
|
for (const listener of this.listeners(type)) { |
|
if (!options[kForOnEventAttribute$1] && listener[kListener$1] === handler && !listener[kForOnEventAttribute$1]) { |
|
return; |
|
} |
|
} |
|
let wrapper; |
|
if (type === "message") { |
|
wrapper = function onMessage(data, isBinary) { |
|
const event = new MessageEvent("message", { |
|
data: isBinary ? data : data.toString() |
|
}); |
|
event[kTarget] = this; |
|
callListener(handler, this, event); |
|
}; |
|
} else if (type === "close") { |
|
wrapper = function onClose(code, message) { |
|
const event = new CloseEvent("close", { |
|
code, |
|
reason: message.toString(), |
|
wasClean: this._closeFrameReceived && this._closeFrameSent |
|
}); |
|
event[kTarget] = this; |
|
callListener(handler, this, event); |
|
}; |
|
} else if (type === "error") { |
|
wrapper = function onError(error2) { |
|
const event = new ErrorEvent("error", { |
|
error: error2, |
|
message: error2.message |
|
}); |
|
event[kTarget] = this; |
|
callListener(handler, this, event); |
|
}; |
|
} else if (type === "open") { |
|
wrapper = function onOpen() { |
|
const event = new Event("open"); |
|
event[kTarget] = this; |
|
callListener(handler, this, event); |
|
}; |
|
} else { |
|
return; |
|
} |
|
wrapper[kForOnEventAttribute$1] = !!options[kForOnEventAttribute$1]; |
|
wrapper[kListener$1] = handler; |
|
if (options.once) { |
|
this.once(type, wrapper); |
|
} else { |
|
this.on(type, wrapper); |
|
} |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
removeEventListener(type, handler) { |
|
for (const listener of this.listeners(type)) { |
|
if (listener[kListener$1] === handler && !listener[kForOnEventAttribute$1]) { |
|
this.removeListener(type, listener); |
|
break; |
|
} |
|
} |
|
} |
|
}; |
|
var eventTarget = { |
|
CloseEvent, |
|
ErrorEvent, |
|
Event, |
|
EventTarget, |
|
MessageEvent |
|
}; |
|
function callListener(listener, thisArg, event) { |
|
if (typeof listener === "object" && listener.handleEvent) { |
|
listener.handleEvent.call(listener, event); |
|
} else { |
|
listener.call(thisArg, event); |
|
} |
|
} |
|
const { tokenChars: tokenChars$1 } = validationExports; |
|
function push(dest, name, elem) { |
|
if (dest[name] === void 0) |
|
dest[name] = [elem]; |
|
else |
|
dest[name].push(elem); |
|
} |
|
function parse$2(header) { |
|
const offers = Object.create(null); |
|
let params = Object.create(null); |
|
let mustUnescape = false; |
|
let isEscaping = false; |
|
let inQuotes = false; |
|
let extensionName; |
|
let paramName; |
|
let start = -1; |
|
let code = -1; |
|
let end = -1; |
|
let i = 0; |
|
for (; i < header.length; i++) { |
|
code = header.charCodeAt(i); |
|
if (extensionName === void 0) { |
|
if (end === -1 && tokenChars$1[code] === 1) { |
|
if (start === -1) |
|
start = i; |
|
} else if (i !== 0 && (code === 32 || code === 9)) { |
|
if (end === -1 && start !== -1) |
|
end = i; |
|
} else if (code === 59 || code === 44) { |
|
if (start === -1) { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
if (end === -1) |
|
end = i; |
|
const name = header.slice(start, end); |
|
if (code === 44) { |
|
push(offers, name, params); |
|
params = Object.create(null); |
|
} else { |
|
extensionName = name; |
|
} |
|
start = end = -1; |
|
} else { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
} else if (paramName === void 0) { |
|
if (end === -1 && tokenChars$1[code] === 1) { |
|
if (start === -1) |
|
start = i; |
|
} else if (code === 32 || code === 9) { |
|
if (end === -1 && start !== -1) |
|
end = i; |
|
} else if (code === 59 || code === 44) { |
|
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 === 44) { |
|
push(offers, extensionName, params); |
|
params = Object.create(null); |
|
extensionName = void 0; |
|
} |
|
start = end = -1; |
|
} else if (code === 61 && start !== -1 && end === -1) { |
|
paramName = header.slice(start, i); |
|
start = end = -1; |
|
} else { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
} else { |
|
if (isEscaping) { |
|
if (tokenChars$1[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$1[code] === 1) { |
|
if (start === -1) |
|
start = i; |
|
} else if (code === 34 && start !== -1) { |
|
inQuotes = false; |
|
end = i; |
|
} else if (code === 92) { |
|
isEscaping = true; |
|
} else { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
} else if (code === 34 && header.charCodeAt(i - 1) === 61) { |
|
inQuotes = true; |
|
} else if (end === -1 && tokenChars$1[code] === 1) { |
|
if (start === -1) |
|
start = i; |
|
} else if (start !== -1 && (code === 32 || code === 9)) { |
|
if (end === -1) |
|
end = i; |
|
} else if (code === 59 || code === 44) { |
|
if (start === -1) { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
if (end === -1) |
|
end = i; |
|
let value = header.slice(start, end); |
|
if (mustUnescape) { |
|
value = value.replace(/\\/g, ""); |
|
mustUnescape = false; |
|
} |
|
push(params, paramName, value); |
|
if (code === 44) { |
|
push(offers, extensionName, params); |
|
params = Object.create(null); |
|
extensionName = void 0; |
|
} |
|
paramName = void 0; |
|
start = end = -1; |
|
} else { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
} |
|
} |
|
if (start === -1 || inQuotes || code === 32 || code === 9) { |
|
throw new SyntaxError("Unexpected end of input"); |
|
} |
|
if (end === -1) |
|
end = i; |
|
const token = header.slice(start, end); |
|
if (extensionName === void 0) { |
|
push(offers, token, params); |
|
} else { |
|
if (paramName === void 0) { |
|
push(params, token, true); |
|
} else if (mustUnescape) { |
|
push(params, paramName, token.replace(/\\/g, "")); |
|
} else { |
|
push(params, paramName, token); |
|
} |
|
push(offers, extensionName, params); |
|
} |
|
return offers; |
|
} |
|
function format$1(extensions) { |
|
return Object.keys(extensions).map((extension2) => { |
|
let configurations = extensions[extension2]; |
|
if (!Array.isArray(configurations)) |
|
configurations = [configurations]; |
|
return configurations.map((params) => { |
|
return [extension2].concat( |
|
Object.keys(params).map((k) => { |
|
let values = params[k]; |
|
if (!Array.isArray(values)) |
|
values = [values]; |
|
return values.map((v) => v === true ? k : `${k}=${v}`).join("; "); |
|
}) |
|
).join("; "); |
|
}).join(", "); |
|
}).join(", "); |
|
} |
|
var extension$1 = { format: format$1, parse: parse$2 }; |
|
const EventEmitter$1 = require$$0$4; |
|
const https = require$$1$2; |
|
const http$1 = require$$2$1; |
|
const net = require$$3; |
|
const tls = require$$4; |
|
const { randomBytes, createHash: createHash$1 } = require$$5; |
|
const { URL } = require$$7; |
|
const PerMessageDeflate$1 = permessageDeflate; |
|
const Receiver2 = receiver; |
|
const Sender2 = sender; |
|
const { |
|
BINARY_TYPES, |
|
EMPTY_BUFFER, |
|
GUID: GUID$1, |
|
kForOnEventAttribute, |
|
kListener, |
|
kStatusCode, |
|
kWebSocket: kWebSocket$1, |
|
NOOP |
|
} = constants; |
|
const { |
|
EventTarget: { addEventListener, removeEventListener } |
|
} = eventTarget; |
|
const { format, parse: parse$1 } = extension$1; |
|
const { toBuffer } = bufferUtilExports; |
|
const closeTimeout = 30 * 1e3; |
|
const kAborted = Symbol("kAborted"); |
|
const protocolVersions = [8, 13]; |
|
const readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; |
|
const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; |
|
let WebSocket$1 = class WebSocket extends EventEmitter$1 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(address, protocols, options) { |
|
super(); |
|
this._binaryType = BINARY_TYPES[0]; |
|
this._closeCode = 1006; |
|
this._closeFrameReceived = false; |
|
this._closeFrameSent = false; |
|
this._closeMessage = EMPTY_BUFFER; |
|
this._closeTimer = null; |
|
this._extensions = {}; |
|
this._paused = false; |
|
this._protocol = ""; |
|
this._readyState = WebSocket.CONNECTING; |
|
this._receiver = null; |
|
this._sender = null; |
|
this._socket = null; |
|
if (address !== null) { |
|
this._bufferedAmount = 0; |
|
this._isServer = false; |
|
this._redirects = 0; |
|
if (protocols === void 0) { |
|
protocols = []; |
|
} else if (!Array.isArray(protocols)) { |
|
if (typeof protocols === "object" && protocols !== null) { |
|
options = protocols; |
|
protocols = []; |
|
} else { |
|
protocols = [protocols]; |
|
} |
|
} |
|
initAsClient(this, address, protocols, options); |
|
} else { |
|
this._isServer = true; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get binaryType() { |
|
return this._binaryType; |
|
} |
|
set binaryType(type) { |
|
if (!BINARY_TYPES.includes(type)) |
|
return; |
|
this._binaryType = type; |
|
if (this._receiver) |
|
this._receiver._binaryType = type; |
|
} |
|
|
|
|
|
|
|
get bufferedAmount() { |
|
if (!this._socket) |
|
return this._bufferedAmount; |
|
return this._socket._writableState.length + this._sender._bufferedBytes; |
|
} |
|
|
|
|
|
|
|
get extensions() { |
|
return Object.keys(this._extensions).join(); |
|
} |
|
|
|
|
|
|
|
get isPaused() { |
|
return this._paused; |
|
} |
|
|
|
|
|
|
|
|
|
get onclose() { |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
get onerror() { |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
get onopen() { |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
get onmessage() { |
|
return null; |
|
} |
|
|
|
|
|
|
|
get protocol() { |
|
return this._protocol; |
|
} |
|
|
|
|
|
|
|
get readyState() { |
|
return this._readyState; |
|
} |
|
|
|
|
|
|
|
get url() { |
|
return this._url; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setSocket(socket, head, options) { |
|
const receiver2 = new Receiver2({ |
|
binaryType: this.binaryType, |
|
extensions: this._extensions, |
|
isServer: this._isServer, |
|
maxPayload: options.maxPayload, |
|
skipUTF8Validation: options.skipUTF8Validation |
|
}); |
|
this._sender = new Sender2(socket, this._extensions, options.generateMask); |
|
this._receiver = receiver2; |
|
this._socket = socket; |
|
receiver2[kWebSocket$1] = this; |
|
socket[kWebSocket$1] = this; |
|
receiver2.on("conclude", receiverOnConclude); |
|
receiver2.on("drain", receiverOnDrain); |
|
receiver2.on("error", receiverOnError); |
|
receiver2.on("message", receiverOnMessage); |
|
receiver2.on("ping", receiverOnPing); |
|
receiver2.on("pong", receiverOnPong); |
|
socket.setTimeout(0); |
|
socket.setNoDelay(); |
|
if (head.length > 0) |
|
socket.unshift(head); |
|
socket.on("close", socketOnClose); |
|
socket.on("data", socketOnData); |
|
socket.on("end", socketOnEnd); |
|
socket.on("error", socketOnError$1); |
|
this._readyState = WebSocket.OPEN; |
|
this.emit("open"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
emitClose() { |
|
if (!this._socket) { |
|
this._readyState = WebSocket.CLOSED; |
|
this.emit("close", this._closeCode, this._closeMessage); |
|
return; |
|
} |
|
if (this._extensions[PerMessageDeflate$1.extensionName]) { |
|
this._extensions[PerMessageDeflate$1.extensionName].cleanup(); |
|
} |
|
this._receiver.removeAllListeners(); |
|
this._readyState = WebSocket.CLOSED; |
|
this.emit("close", this._closeCode, this._closeMessage); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close(code, data) { |
|
if (this.readyState === WebSocket.CLOSED) |
|
return; |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
const msg = "WebSocket was closed before the connection was established"; |
|
abortHandshake$1(this, this._req, msg); |
|
return; |
|
} |
|
if (this.readyState === WebSocket.CLOSING) { |
|
if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) { |
|
this._socket.end(); |
|
} |
|
return; |
|
} |
|
this._readyState = WebSocket.CLOSING; |
|
this._sender.close(code, data, !this._isServer, (err) => { |
|
if (err) |
|
return; |
|
this._closeFrameSent = true; |
|
if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) { |
|
this._socket.end(); |
|
} |
|
}); |
|
this._closeTimer = setTimeout( |
|
this._socket.destroy.bind(this._socket), |
|
closeTimeout |
|
); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
pause() { |
|
if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) { |
|
return; |
|
} |
|
this._paused = true; |
|
this._socket.pause(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ping(data, mask2, cb) { |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); |
|
} |
|
if (typeof data === "function") { |
|
cb = data; |
|
data = mask2 = void 0; |
|
} else if (typeof mask2 === "function") { |
|
cb = mask2; |
|
mask2 = void 0; |
|
} |
|
if (typeof data === "number") |
|
data = data.toString(); |
|
if (this.readyState !== WebSocket.OPEN) { |
|
sendAfterClose(this, data, cb); |
|
return; |
|
} |
|
if (mask2 === void 0) |
|
mask2 = !this._isServer; |
|
this._sender.ping(data || EMPTY_BUFFER, mask2, cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pong(data, mask2, cb) { |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); |
|
} |
|
if (typeof data === "function") { |
|
cb = data; |
|
data = mask2 = void 0; |
|
} else if (typeof mask2 === "function") { |
|
cb = mask2; |
|
mask2 = void 0; |
|
} |
|
if (typeof data === "number") |
|
data = data.toString(); |
|
if (this.readyState !== WebSocket.OPEN) { |
|
sendAfterClose(this, data, cb); |
|
return; |
|
} |
|
if (mask2 === void 0) |
|
mask2 = !this._isServer; |
|
this._sender.pong(data || EMPTY_BUFFER, mask2, cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
resume() { |
|
if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) { |
|
return; |
|
} |
|
this._paused = false; |
|
if (!this._receiver._writableState.needDrain) |
|
this._socket.resume(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
send(data, options, cb) { |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); |
|
} |
|
if (typeof options === "function") { |
|
cb = options; |
|
options = {}; |
|
} |
|
if (typeof data === "number") |
|
data = data.toString(); |
|
if (this.readyState !== WebSocket.OPEN) { |
|
sendAfterClose(this, data, cb); |
|
return; |
|
} |
|
const opts = { |
|
binary: typeof data !== "string", |
|
mask: !this._isServer, |
|
compress: true, |
|
fin: true, |
|
...options |
|
}; |
|
if (!this._extensions[PerMessageDeflate$1.extensionName]) { |
|
opts.compress = false; |
|
} |
|
this._sender.send(data || EMPTY_BUFFER, opts, cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
terminate() { |
|
if (this.readyState === WebSocket.CLOSED) |
|
return; |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
const msg = "WebSocket was closed before the connection was established"; |
|
abortHandshake$1(this, this._req, msg); |
|
return; |
|
} |
|
if (this._socket) { |
|
this._readyState = WebSocket.CLOSING; |
|
this._socket.destroy(); |
|
} |
|
} |
|
}; |
|
Object.defineProperty(WebSocket$1, "CONNECTING", { |
|
enumerable: true, |
|
value: readyStates.indexOf("CONNECTING") |
|
}); |
|
Object.defineProperty(WebSocket$1.prototype, "CONNECTING", { |
|
enumerable: true, |
|
value: readyStates.indexOf("CONNECTING") |
|
}); |
|
Object.defineProperty(WebSocket$1, "OPEN", { |
|
enumerable: true, |
|
value: readyStates.indexOf("OPEN") |
|
}); |
|
Object.defineProperty(WebSocket$1.prototype, "OPEN", { |
|
enumerable: true, |
|
value: readyStates.indexOf("OPEN") |
|
}); |
|
Object.defineProperty(WebSocket$1, "CLOSING", { |
|
enumerable: true, |
|
value: readyStates.indexOf("CLOSING") |
|
}); |
|
Object.defineProperty(WebSocket$1.prototype, "CLOSING", { |
|
enumerable: true, |
|
value: readyStates.indexOf("CLOSING") |
|
}); |
|
Object.defineProperty(WebSocket$1, "CLOSED", { |
|
enumerable: true, |
|
value: readyStates.indexOf("CLOSED") |
|
}); |
|
Object.defineProperty(WebSocket$1.prototype, "CLOSED", { |
|
enumerable: true, |
|
value: readyStates.indexOf("CLOSED") |
|
}); |
|
[ |
|
"binaryType", |
|
"bufferedAmount", |
|
"extensions", |
|
"isPaused", |
|
"protocol", |
|
"readyState", |
|
"url" |
|
].forEach((property) => { |
|
Object.defineProperty(WebSocket$1.prototype, property, { enumerable: true }); |
|
}); |
|
["open", "error", "close", "message"].forEach((method) => { |
|
Object.defineProperty(WebSocket$1.prototype, `on${method}`, { |
|
enumerable: true, |
|
get() { |
|
for (const listener of this.listeners(method)) { |
|
if (listener[kForOnEventAttribute]) |
|
return listener[kListener]; |
|
} |
|
return null; |
|
}, |
|
set(handler) { |
|
for (const listener of this.listeners(method)) { |
|
if (listener[kForOnEventAttribute]) { |
|
this.removeListener(method, listener); |
|
break; |
|
} |
|
} |
|
if (typeof handler !== "function") |
|
return; |
|
this.addEventListener(method, handler, { |
|
[kForOnEventAttribute]: true |
|
}); |
|
} |
|
}); |
|
}); |
|
WebSocket$1.prototype.addEventListener = addEventListener; |
|
WebSocket$1.prototype.removeEventListener = removeEventListener; |
|
var websocket = WebSocket$1; |
|
function initAsClient(websocket2, address, protocols, options) { |
|
const opts = { |
|
protocolVersion: protocolVersions[1], |
|
maxPayload: 100 * 1024 * 1024, |
|
skipUTF8Validation: false, |
|
perMessageDeflate: true, |
|
followRedirects: false, |
|
maxRedirects: 10, |
|
...options, |
|
createConnection: void 0, |
|
socketPath: void 0, |
|
hostname: void 0, |
|
protocol: void 0, |
|
timeout: void 0, |
|
method: "GET", |
|
host: void 0, |
|
path: void 0, |
|
port: void 0 |
|
}; |
|
if (!protocolVersions.includes(opts.protocolVersion)) { |
|
throw new RangeError( |
|
`Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})` |
|
); |
|
} |
|
let parsedUrl; |
|
if (address instanceof URL) { |
|
parsedUrl = address; |
|
websocket2._url = address.href; |
|
} else { |
|
try { |
|
parsedUrl = new URL(address); |
|
} catch (e) { |
|
throw new SyntaxError(`Invalid URL: ${address}`); |
|
} |
|
websocket2._url = address; |
|
} |
|
const isSecure = parsedUrl.protocol === "wss:"; |
|
const isIpcUrl = parsedUrl.protocol === "ws+unix:"; |
|
let invalidUrlMessage; |
|
if (parsedUrl.protocol !== "ws:" && !isSecure && !isIpcUrl) { |
|
invalidUrlMessage = `The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"`; |
|
} else if (isIpcUrl && !parsedUrl.pathname) { |
|
invalidUrlMessage = "The URL's pathname is empty"; |
|
} else if (parsedUrl.hash) { |
|
invalidUrlMessage = "The URL contains a fragment identifier"; |
|
} |
|
if (invalidUrlMessage) { |
|
const err = new SyntaxError(invalidUrlMessage); |
|
if (websocket2._redirects === 0) { |
|
throw err; |
|
} else { |
|
emitErrorAndClose(websocket2, err); |
|
return; |
|
} |
|
} |
|
const defaultPort = isSecure ? 443 : 80; |
|
const key = randomBytes(16).toString("base64"); |
|
const request = isSecure ? https.request : http$1.request; |
|
const protocolSet = new Set(); |
|
let perMessageDeflate; |
|
opts.createConnection = isSecure ? tlsConnect : netConnect; |
|
opts.defaultPort = opts.defaultPort || defaultPort; |
|
opts.port = parsedUrl.port || defaultPort; |
|
opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; |
|
opts.headers = { |
|
...opts.headers, |
|
"Sec-WebSocket-Version": opts.protocolVersion, |
|
"Sec-WebSocket-Key": key, |
|
Connection: "Upgrade", |
|
Upgrade: "websocket" |
|
}; |
|
opts.path = parsedUrl.pathname + parsedUrl.search; |
|
opts.timeout = opts.handshakeTimeout; |
|
if (opts.perMessageDeflate) { |
|
perMessageDeflate = new PerMessageDeflate$1( |
|
opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, |
|
false, |
|
opts.maxPayload |
|
); |
|
opts.headers["Sec-WebSocket-Extensions"] = format({ |
|
[PerMessageDeflate$1.extensionName]: perMessageDeflate.offer() |
|
}); |
|
} |
|
if (protocols.length) { |
|
for (const protocol of protocols) { |
|
if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) { |
|
throw new SyntaxError( |
|
"An invalid or duplicated subprotocol was specified" |
|
); |
|
} |
|
protocolSet.add(protocol); |
|
} |
|
opts.headers["Sec-WebSocket-Protocol"] = protocols.join(","); |
|
} |
|
if (opts.origin) { |
|
if (opts.protocolVersion < 13) { |
|
opts.headers["Sec-WebSocket-Origin"] = opts.origin; |
|
} else { |
|
opts.headers.Origin = opts.origin; |
|
} |
|
} |
|
if (parsedUrl.username || parsedUrl.password) { |
|
opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; |
|
} |
|
if (isIpcUrl) { |
|
const parts = opts.path.split(":"); |
|
opts.socketPath = parts[0]; |
|
opts.path = parts[1]; |
|
} |
|
let req; |
|
if (opts.followRedirects) { |
|
if (websocket2._redirects === 0) { |
|
websocket2._originalIpc = isIpcUrl; |
|
websocket2._originalSecure = isSecure; |
|
websocket2._originalHostOrSocketPath = isIpcUrl ? opts.socketPath : parsedUrl.host; |
|
const headers = options && options.headers; |
|
options = { ...options, headers: {} }; |
|
if (headers) { |
|
for (const [key2, value] of Object.entries(headers)) { |
|
options.headers[key2.toLowerCase()] = value; |
|
} |
|
} |
|
} else if (websocket2.listenerCount("redirect") === 0) { |
|
const isSameHost = isIpcUrl ? websocket2._originalIpc ? opts.socketPath === websocket2._originalHostOrSocketPath : false : websocket2._originalIpc ? false : parsedUrl.host === websocket2._originalHostOrSocketPath; |
|
if (!isSameHost || websocket2._originalSecure && !isSecure) { |
|
delete opts.headers.authorization; |
|
delete opts.headers.cookie; |
|
if (!isSameHost) |
|
delete opts.headers.host; |
|
opts.auth = void 0; |
|
} |
|
} |
|
if (opts.auth && !options.headers.authorization) { |
|
options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64"); |
|
} |
|
req = websocket2._req = request(opts); |
|
if (websocket2._redirects) { |
|
websocket2.emit("redirect", websocket2.url, req); |
|
} |
|
} else { |
|
req = websocket2._req = request(opts); |
|
} |
|
if (opts.timeout) { |
|
req.on("timeout", () => { |
|
abortHandshake$1(websocket2, req, "Opening handshake has timed out"); |
|
}); |
|
} |
|
req.on("error", (err) => { |
|
if (req === null || req[kAborted]) |
|
return; |
|
req = websocket2._req = null; |
|
emitErrorAndClose(websocket2, err); |
|
}); |
|
req.on("response", (res) => { |
|
const location = res.headers.location; |
|
const statusCode = res.statusCode; |
|
if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) { |
|
if (++websocket2._redirects > opts.maxRedirects) { |
|
abortHandshake$1(websocket2, req, "Maximum redirects exceeded"); |
|
return; |
|
} |
|
req.abort(); |
|
let addr; |
|
try { |
|
addr = new URL(location, address); |
|
} catch (e) { |
|
const err = new SyntaxError(`Invalid URL: ${location}`); |
|
emitErrorAndClose(websocket2, err); |
|
return; |
|
} |
|
initAsClient(websocket2, addr, protocols, options); |
|
} else if (!websocket2.emit("unexpected-response", req, res)) { |
|
abortHandshake$1( |
|
websocket2, |
|
req, |
|
`Unexpected server response: ${res.statusCode}` |
|
); |
|
} |
|
}); |
|
req.on("upgrade", (res, socket, head) => { |
|
websocket2.emit("upgrade", res); |
|
if (websocket2.readyState !== WebSocket$1.CONNECTING) |
|
return; |
|
req = websocket2._req = null; |
|
if (res.headers.upgrade.toLowerCase() !== "websocket") { |
|
abortHandshake$1(websocket2, socket, "Invalid Upgrade header"); |
|
return; |
|
} |
|
const digest = createHash$1("sha1").update(key + GUID$1).digest("base64"); |
|
if (res.headers["sec-websocket-accept"] !== digest) { |
|
abortHandshake$1(websocket2, socket, "Invalid Sec-WebSocket-Accept header"); |
|
return; |
|
} |
|
const serverProt = res.headers["sec-websocket-protocol"]; |
|
let protError; |
|
if (serverProt !== void 0) { |
|
if (!protocolSet.size) { |
|
protError = "Server sent a subprotocol but none was requested"; |
|
} else if (!protocolSet.has(serverProt)) { |
|
protError = "Server sent an invalid subprotocol"; |
|
} |
|
} else if (protocolSet.size) { |
|
protError = "Server sent no subprotocol"; |
|
} |
|
if (protError) { |
|
abortHandshake$1(websocket2, socket, protError); |
|
return; |
|
} |
|
if (serverProt) |
|
websocket2._protocol = serverProt; |
|
const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; |
|
if (secWebSocketExtensions !== void 0) { |
|
if (!perMessageDeflate) { |
|
const message = "Server sent a Sec-WebSocket-Extensions header but no extension was requested"; |
|
abortHandshake$1(websocket2, socket, message); |
|
return; |
|
} |
|
let extensions; |
|
try { |
|
extensions = parse$1(secWebSocketExtensions); |
|
} catch (err) { |
|
const message = "Invalid Sec-WebSocket-Extensions header"; |
|
abortHandshake$1(websocket2, socket, message); |
|
return; |
|
} |
|
const extensionNames = Object.keys(extensions); |
|
if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate$1.extensionName) { |
|
const message = "Server indicated an extension that was not requested"; |
|
abortHandshake$1(websocket2, socket, message); |
|
return; |
|
} |
|
try { |
|
perMessageDeflate.accept(extensions[PerMessageDeflate$1.extensionName]); |
|
} catch (err) { |
|
const message = "Invalid Sec-WebSocket-Extensions header"; |
|
abortHandshake$1(websocket2, socket, message); |
|
return; |
|
} |
|
websocket2._extensions[PerMessageDeflate$1.extensionName] = perMessageDeflate; |
|
} |
|
websocket2.setSocket(socket, head, { |
|
generateMask: opts.generateMask, |
|
maxPayload: opts.maxPayload, |
|
skipUTF8Validation: opts.skipUTF8Validation |
|
}); |
|
}); |
|
if (opts.finishRequest) { |
|
opts.finishRequest(req, websocket2); |
|
} else { |
|
req.end(); |
|
} |
|
} |
|
function emitErrorAndClose(websocket2, err) { |
|
websocket2._readyState = WebSocket$1.CLOSING; |
|
websocket2.emit("error", err); |
|
websocket2.emitClose(); |
|
} |
|
function netConnect(options) { |
|
options.path = options.socketPath; |
|
return net.connect(options); |
|
} |
|
function tlsConnect(options) { |
|
options.path = void 0; |
|
if (!options.servername && options.servername !== "") { |
|
options.servername = net.isIP(options.host) ? "" : options.host; |
|
} |
|
return tls.connect(options); |
|
} |
|
function abortHandshake$1(websocket2, stream2, message) { |
|
websocket2._readyState = WebSocket$1.CLOSING; |
|
const err = new Error(message); |
|
Error.captureStackTrace(err, abortHandshake$1); |
|
if (stream2.setHeader) { |
|
stream2[kAborted] = true; |
|
stream2.abort(); |
|
if (stream2.socket && !stream2.socket.destroyed) { |
|
stream2.socket.destroy(); |
|
} |
|
process.nextTick(emitErrorAndClose, websocket2, err); |
|
} else { |
|
stream2.destroy(err); |
|
stream2.once("error", websocket2.emit.bind(websocket2, "error")); |
|
stream2.once("close", websocket2.emitClose.bind(websocket2)); |
|
} |
|
} |
|
function sendAfterClose(websocket2, data, cb) { |
|
if (data) { |
|
const length = toBuffer(data).length; |
|
if (websocket2._socket) |
|
websocket2._sender._bufferedBytes += length; |
|
else |
|
websocket2._bufferedAmount += length; |
|
} |
|
if (cb) { |
|
const err = new Error( |
|
`WebSocket is not open: readyState ${websocket2.readyState} (${readyStates[websocket2.readyState]})` |
|
); |
|
process.nextTick(cb, err); |
|
} |
|
} |
|
function receiverOnConclude(code, reason) { |
|
const websocket2 = this[kWebSocket$1]; |
|
websocket2._closeFrameReceived = true; |
|
websocket2._closeMessage = reason; |
|
websocket2._closeCode = code; |
|
if (websocket2._socket[kWebSocket$1] === void 0) |
|
return; |
|
websocket2._socket.removeListener("data", socketOnData); |
|
process.nextTick(resume, websocket2._socket); |
|
if (code === 1005) |
|
websocket2.close(); |
|
else |
|
websocket2.close(code, reason); |
|
} |
|
function receiverOnDrain() { |
|
const websocket2 = this[kWebSocket$1]; |
|
if (!websocket2.isPaused) |
|
websocket2._socket.resume(); |
|
} |
|
function receiverOnError(err) { |
|
const websocket2 = this[kWebSocket$1]; |
|
if (websocket2._socket[kWebSocket$1] !== void 0) { |
|
websocket2._socket.removeListener("data", socketOnData); |
|
process.nextTick(resume, websocket2._socket); |
|
websocket2.close(err[kStatusCode]); |
|
} |
|
websocket2.emit("error", err); |
|
} |
|
function receiverOnFinish() { |
|
this[kWebSocket$1].emitClose(); |
|
} |
|
function receiverOnMessage(data, isBinary) { |
|
this[kWebSocket$1].emit("message", data, isBinary); |
|
} |
|
function receiverOnPing(data) { |
|
const websocket2 = this[kWebSocket$1]; |
|
websocket2.pong(data, !websocket2._isServer, NOOP); |
|
websocket2.emit("ping", data); |
|
} |
|
function receiverOnPong(data) { |
|
this[kWebSocket$1].emit("pong", data); |
|
} |
|
function resume(stream2) { |
|
stream2.resume(); |
|
} |
|
function socketOnClose() { |
|
const websocket2 = this[kWebSocket$1]; |
|
this.removeListener("close", socketOnClose); |
|
this.removeListener("data", socketOnData); |
|
this.removeListener("end", socketOnEnd); |
|
websocket2._readyState = WebSocket$1.CLOSING; |
|
let chunk; |
|
if (!this._readableState.endEmitted && !websocket2._closeFrameReceived && !websocket2._receiver._writableState.errorEmitted && (chunk = websocket2._socket.read()) !== null) { |
|
websocket2._receiver.write(chunk); |
|
} |
|
websocket2._receiver.end(); |
|
this[kWebSocket$1] = void 0; |
|
clearTimeout(websocket2._closeTimer); |
|
if (websocket2._receiver._writableState.finished || websocket2._receiver._writableState.errorEmitted) { |
|
websocket2.emitClose(); |
|
} else { |
|
websocket2._receiver.on("error", receiverOnFinish); |
|
websocket2._receiver.on("finish", receiverOnFinish); |
|
} |
|
} |
|
function socketOnData(chunk) { |
|
if (!this[kWebSocket$1]._receiver.write(chunk)) { |
|
this.pause(); |
|
} |
|
} |
|
function socketOnEnd() { |
|
const websocket2 = this[kWebSocket$1]; |
|
websocket2._readyState = WebSocket$1.CLOSING; |
|
websocket2._receiver.end(); |
|
this.end(); |
|
} |
|
function socketOnError$1() { |
|
const websocket2 = this[kWebSocket$1]; |
|
this.removeListener("error", socketOnError$1); |
|
this.on("error", NOOP); |
|
if (websocket2) { |
|
websocket2._readyState = WebSocket$1.CLOSING; |
|
this.destroy(); |
|
} |
|
} |
|
const WebSocket$2 = getDefaultExportFromCjs(websocket); |
|
const { tokenChars } = validationExports; |
|
function parse(header) { |
|
const protocols = new Set(); |
|
let start = -1; |
|
let end = -1; |
|
let i = 0; |
|
for (i; i < header.length; i++) { |
|
const code = header.charCodeAt(i); |
|
if (end === -1 && tokenChars[code] === 1) { |
|
if (start === -1) |
|
start = i; |
|
} else if (i !== 0 && (code === 32 || code === 9)) { |
|
if (end === -1 && start !== -1) |
|
end = i; |
|
} else if (code === 44) { |
|
if (start === -1) { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
if (end === -1) |
|
end = i; |
|
const protocol2 = header.slice(start, end); |
|
if (protocols.has(protocol2)) { |
|
throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`); |
|
} |
|
protocols.add(protocol2); |
|
start = end = -1; |
|
} else { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
} |
|
if (start === -1 || end !== -1) { |
|
throw new SyntaxError("Unexpected end of input"); |
|
} |
|
const protocol = header.slice(start, i); |
|
if (protocols.has(protocol)) { |
|
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); |
|
} |
|
protocols.add(protocol); |
|
return protocols; |
|
} |
|
var subprotocol$1 = { parse }; |
|
const EventEmitter = require$$0$4; |
|
const http = require$$2$1; |
|
const { createHash } = require$$5; |
|
const extension = extension$1; |
|
const PerMessageDeflate2 = permessageDeflate; |
|
const subprotocol = subprotocol$1; |
|
const WebSocket2 = websocket; |
|
const { GUID, kWebSocket } = constants; |
|
const keyRegex = /^[+/0-9A-Za-z]{22}==$/; |
|
const RUNNING = 0; |
|
const CLOSING = 1; |
|
const CLOSED = 2; |
|
class WebSocketServer extends EventEmitter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(options, callback) { |
|
super(); |
|
options = { |
|
maxPayload: 100 * 1024 * 1024, |
|
skipUTF8Validation: false, |
|
perMessageDeflate: false, |
|
handleProtocols: null, |
|
clientTracking: true, |
|
verifyClient: null, |
|
noServer: false, |
|
backlog: null, |
|
|
|
server: null, |
|
host: null, |
|
path: null, |
|
port: null, |
|
WebSocket: WebSocket2, |
|
...options |
|
}; |
|
if (options.port == null && !options.server && !options.noServer || options.port != null && (options.server || options.noServer) || options.server && options.noServer) { |
|
throw new TypeError( |
|
'One and only 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) { |
|
const emitConnection = this.emit.bind(this, "connection"); |
|
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, emitConnection); |
|
} |
|
}); |
|
} |
|
if (options.perMessageDeflate === true) |
|
options.perMessageDeflate = {}; |
|
if (options.clientTracking) { |
|
this.clients = new Set(); |
|
this._shouldEmitClose = false; |
|
} |
|
this.options = options; |
|
this._state = RUNNING; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(cb) { |
|
if (this._state === CLOSED) { |
|
if (cb) { |
|
this.once("close", () => { |
|
cb(new Error("The server is not running")); |
|
}); |
|
} |
|
process.nextTick(emitClose, this); |
|
return; |
|
} |
|
if (cb) |
|
this.once("close", cb); |
|
if (this._state === CLOSING) |
|
return; |
|
this._state = CLOSING; |
|
if (this.options.noServer || this.options.server) { |
|
if (this._server) { |
|
this._removeListeners(); |
|
this._removeListeners = this._server = null; |
|
} |
|
if (this.clients) { |
|
if (!this.clients.size) { |
|
process.nextTick(emitClose, this); |
|
} else { |
|
this._shouldEmitClose = true; |
|
} |
|
} else { |
|
process.nextTick(emitClose, this); |
|
} |
|
} else { |
|
const server = this._server; |
|
this._removeListeners(); |
|
this._removeListeners = this._server = null; |
|
server.close(() => { |
|
emitClose(this); |
|
}); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shouldHandle(req) { |
|
if (this.options.path) { |
|
const index = req.url.indexOf("?"); |
|
const pathname = index !== -1 ? req.url.slice(0, index) : req.url; |
|
if (pathname !== this.options.path) |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleUpgrade(req, socket, head, cb) { |
|
socket.on("error", socketOnError); |
|
const key = req.headers["sec-websocket-key"]; |
|
const version = +req.headers["sec-websocket-version"]; |
|
if (req.method !== "GET") { |
|
const message = "Invalid HTTP method"; |
|
abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); |
|
return; |
|
} |
|
if (req.headers.upgrade.toLowerCase() !== "websocket") { |
|
const message = "Invalid Upgrade header"; |
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); |
|
return; |
|
} |
|
if (!key || !keyRegex.test(key)) { |
|
const message = "Missing or invalid Sec-WebSocket-Key header"; |
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); |
|
return; |
|
} |
|
if (version !== 8 && version !== 13) { |
|
const message = "Missing or invalid Sec-WebSocket-Version header"; |
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); |
|
return; |
|
} |
|
if (!this.shouldHandle(req)) { |
|
abortHandshake(socket, 400); |
|
return; |
|
} |
|
const secWebSocketProtocol = req.headers["sec-websocket-protocol"]; |
|
let protocols = new Set(); |
|
if (secWebSocketProtocol !== void 0) { |
|
try { |
|
protocols = subprotocol.parse(secWebSocketProtocol); |
|
} catch (err) { |
|
const message = "Invalid Sec-WebSocket-Protocol header"; |
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); |
|
return; |
|
} |
|
} |
|
const secWebSocketExtensions = req.headers["sec-websocket-extensions"]; |
|
const extensions = {}; |
|
if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) { |
|
const perMessageDeflate = new PerMessageDeflate2( |
|
this.options.perMessageDeflate, |
|
true, |
|
this.options.maxPayload |
|
); |
|
try { |
|
const offers = extension.parse(secWebSocketExtensions); |
|
if (offers[PerMessageDeflate2.extensionName]) { |
|
perMessageDeflate.accept(offers[PerMessageDeflate2.extensionName]); |
|
extensions[PerMessageDeflate2.extensionName] = perMessageDeflate; |
|
} |
|
} catch (err) { |
|
const message = "Invalid or unacceptable Sec-WebSocket-Extensions header"; |
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); |
|
return; |
|
} |
|
} |
|
if (this.options.verifyClient) { |
|
const info = { |
|
origin: req.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`], |
|
secure: !!(req.socket.authorized || req.socket.encrypted), |
|
req |
|
}; |
|
if (this.options.verifyClient.length === 2) { |
|
this.options.verifyClient(info, (verified, code, message, headers) => { |
|
if (!verified) { |
|
return abortHandshake(socket, code || 401, message, headers); |
|
} |
|
this.completeUpgrade( |
|
extensions, |
|
key, |
|
protocols, |
|
req, |
|
socket, |
|
head, |
|
cb |
|
); |
|
}); |
|
return; |
|
} |
|
if (!this.options.verifyClient(info)) |
|
return abortHandshake(socket, 401); |
|
} |
|
this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
completeUpgrade(extensions, key, protocols, req, socket, head, cb) { |
|
if (!socket.readable || !socket.writable) |
|
return socket.destroy(); |
|
if (socket[kWebSocket]) { |
|
throw new Error( |
|
"server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration" |
|
); |
|
} |
|
if (this._state > RUNNING) |
|
return abortHandshake(socket, 503); |
|
const digest = createHash("sha1").update(key + GUID).digest("base64"); |
|
const headers = [ |
|
"HTTP/1.1 101 Switching Protocols", |
|
"Upgrade: websocket", |
|
"Connection: Upgrade", |
|
`Sec-WebSocket-Accept: ${digest}` |
|
]; |
|
const ws = new this.options.WebSocket(null); |
|
if (protocols.size) { |
|
const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; |
|
if (protocol) { |
|
headers.push(`Sec-WebSocket-Protocol: ${protocol}`); |
|
ws._protocol = protocol; |
|
} |
|
} |
|
if (extensions[PerMessageDeflate2.extensionName]) { |
|
const params = extensions[PerMessageDeflate2.extensionName].params; |
|
const value = extension.format({ |
|
[PerMessageDeflate2.extensionName]: [params] |
|
}); |
|
headers.push(`Sec-WebSocket-Extensions: ${value}`); |
|
ws._extensions = extensions; |
|
} |
|
this.emit("headers", headers, req); |
|
socket.write(headers.concat("\r\n").join("\r\n")); |
|
socket.removeListener("error", socketOnError); |
|
ws.setSocket(socket, head, { |
|
maxPayload: this.options.maxPayload, |
|
skipUTF8Validation: this.options.skipUTF8Validation |
|
}); |
|
if (this.clients) { |
|
this.clients.add(ws); |
|
ws.on("close", () => { |
|
this.clients.delete(ws); |
|
if (this._shouldEmitClose && !this.clients.size) { |
|
process.nextTick(emitClose, this); |
|
} |
|
}); |
|
} |
|
cb(ws, req); |
|
} |
|
} |
|
var websocketServer = WebSocketServer; |
|
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]); |
|
} |
|
}; |
|
} |
|
function emitClose(server) { |
|
server._state = CLOSED; |
|
server.emit("close"); |
|
} |
|
function socketOnError() { |
|
this.destroy(); |
|
} |
|
function abortHandshake(socket, code, message, headers) { |
|
message = message || http.STATUS_CODES[code]; |
|
headers = { |
|
Connection: "close", |
|
"Content-Type": "text/html", |
|
"Content-Length": Buffer.byteLength(message), |
|
...headers |
|
}; |
|
socket.once("finish", socket.destroy); |
|
socket.end( |
|
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r |
|
` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message |
|
); |
|
} |
|
function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) { |
|
if (server.listenerCount("wsClientError")) { |
|
const err = new Error(message); |
|
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); |
|
server.emit("wsClientError", err, socket, req); |
|
} else { |
|
abortHandshake(socket, code, message); |
|
} |
|
} |
|
const websocketServer$1 = getDefaultExportFromCjs(websocketServer); |
|
export { |
|
receiver$1 as Receiver, |
|
sender$1 as Sender, |
|
WebSocket$2 as WebSocket, |
|
websocketServer$1 as WebSocketServer, |
|
stream$1 as createWebSocketStream, |
|
WebSocket$2 as default |
|
}; |
|
|