|
(() => { |
|
var __webpack_modules__ = ([ |
|
, |
|
|
|
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
|
|
|
"use strict"; |
|
__webpack_require__.r(__webpack_exports__); |
|
__webpack_require__.d(__webpack_exports__, { |
|
"__assign": () => ( __assign), |
|
"__asyncDelegator": () => ( __asyncDelegator), |
|
"__asyncGenerator": () => ( __asyncGenerator), |
|
"__asyncValues": () => ( __asyncValues), |
|
"__await": () => ( __await), |
|
"__awaiter": () => ( __awaiter), |
|
"__classPrivateFieldGet": () => ( __classPrivateFieldGet), |
|
"__classPrivateFieldIn": () => ( __classPrivateFieldIn), |
|
"__classPrivateFieldSet": () => ( __classPrivateFieldSet), |
|
"__createBinding": () => ( __createBinding), |
|
"__decorate": () => ( __decorate), |
|
"__esDecorate": () => ( __esDecorate), |
|
"__exportStar": () => ( __exportStar), |
|
"__extends": () => ( __extends), |
|
"__generator": () => ( __generator), |
|
"__importDefault": () => ( __importDefault), |
|
"__importStar": () => ( __importStar), |
|
"__makeTemplateObject": () => ( __makeTemplateObject), |
|
"__metadata": () => ( __metadata), |
|
"__param": () => ( __param), |
|
"__propKey": () => ( __propKey), |
|
"__read": () => ( __read), |
|
"__rest": () => ( __rest), |
|
"__runInitializers": () => ( __runInitializers), |
|
"__setFunctionName": () => ( __setFunctionName), |
|
"__spread": () => ( __spread), |
|
"__spreadArray": () => ( __spreadArray), |
|
"__spreadArrays": () => ( __spreadArrays), |
|
"__values": () => ( __values) |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var extendStatics = function(d, b) { |
|
extendStatics = Object.setPrototypeOf || |
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
|
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; |
|
return extendStatics(d, b); |
|
}; |
|
|
|
function __extends(d, b) { |
|
if (typeof b !== "function" && b !== null) |
|
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); |
|
extendStatics(d, b); |
|
function __() { this.constructor = d; } |
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
|
} |
|
|
|
var __assign = function() { |
|
__assign = Object.assign || function __assign(t) { |
|
for (var s, i = 1, n = arguments.length; i < n; i++) { |
|
s = arguments[i]; |
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; |
|
} |
|
return t; |
|
} |
|
return __assign.apply(this, arguments); |
|
} |
|
|
|
function __rest(s, e) { |
|
var t = {}; |
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) |
|
t[p] = s[p]; |
|
if (s != null && typeof Object.getOwnPropertySymbols === "function") |
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { |
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) |
|
t[p[i]] = s[p[i]]; |
|
} |
|
return t; |
|
} |
|
|
|
function __decorate(decorators, target, key, desc) { |
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; |
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); |
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; |
|
return c > 3 && r && Object.defineProperty(target, key, r), r; |
|
} |
|
|
|
function __param(paramIndex, decorator) { |
|
return function (target, key) { decorator(target, key, paramIndex); } |
|
} |
|
|
|
function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { |
|
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } |
|
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; |
|
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; |
|
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); |
|
var _, done = false; |
|
for (var i = decorators.length - 1; i >= 0; i--) { |
|
var context = {}; |
|
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; |
|
for (var p in contextIn.access) context.access[p] = contextIn.access[p]; |
|
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; |
|
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); |
|
if (kind === "accessor") { |
|
if (result === void 0) continue; |
|
if (result === null || typeof result !== "object") throw new TypeError("Object expected"); |
|
if (_ = accept(result.get)) descriptor.get = _; |
|
if (_ = accept(result.set)) descriptor.set = _; |
|
if (_ = accept(result.init)) initializers.push(_); |
|
} |
|
else if (_ = accept(result)) { |
|
if (kind === "field") initializers.push(_); |
|
else descriptor[key] = _; |
|
} |
|
} |
|
if (target) Object.defineProperty(target, contextIn.name, descriptor); |
|
done = true; |
|
}; |
|
|
|
function __runInitializers(thisArg, initializers, value) { |
|
var useValue = arguments.length > 2; |
|
for (var i = 0; i < initializers.length; i++) { |
|
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); |
|
} |
|
return useValue ? value : void 0; |
|
}; |
|
|
|
function __propKey(x) { |
|
return typeof x === "symbol" ? x : "".concat(x); |
|
}; |
|
|
|
function __setFunctionName(f, name, prefix) { |
|
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; |
|
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); |
|
}; |
|
|
|
function __metadata(metadataKey, metadataValue) { |
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); |
|
} |
|
|
|
function __awaiter(thisArg, _arguments, P, generator) { |
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |
|
return new (P || (P = Promise))(function (resolve, reject) { |
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } |
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } |
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } |
|
step((generator = generator.apply(thisArg, _arguments || [])).next()); |
|
}); |
|
} |
|
|
|
function __generator(thisArg, body) { |
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; |
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; |
|
function verb(n) { return function (v) { return step([n, v]); }; } |
|
function step(op) { |
|
if (f) throw new TypeError("Generator is already executing."); |
|
while (g && (g = 0, op[0] && (_ = 0)), _) try { |
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; |
|
if (y = 0, t) op = [op[0] & 2, t.value]; |
|
switch (op[0]) { |
|
case 0: case 1: t = op; break; |
|
case 4: _.label++; return { value: op[1], done: false }; |
|
case 5: _.label++; y = op[1]; op = [0]; continue; |
|
case 7: op = _.ops.pop(); _.trys.pop(); continue; |
|
default: |
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } |
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } |
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } |
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } |
|
if (t[2]) _.ops.pop(); |
|
_.trys.pop(); continue; |
|
} |
|
op = body.call(thisArg, _); |
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } |
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; |
|
} |
|
} |
|
|
|
var __createBinding = Object.create ? (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
var desc = Object.getOwnPropertyDescriptor(m, k); |
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { |
|
desc = { enumerable: true, get: function() { return m[k]; } }; |
|
} |
|
Object.defineProperty(o, k2, desc); |
|
}) : (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
o[k2] = m[k]; |
|
}); |
|
|
|
function __exportStar(m, o) { |
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); |
|
} |
|
|
|
function __values(o) { |
|
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; |
|
if (m) return m.call(o); |
|
if (o && typeof o.length === "number") return { |
|
next: function () { |
|
if (o && i >= o.length) o = void 0; |
|
return { value: o && o[i++], done: !o }; |
|
} |
|
}; |
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); |
|
} |
|
|
|
function __read(o, n) { |
|
var m = typeof Symbol === "function" && o[Symbol.iterator]; |
|
if (!m) return o; |
|
var i = m.call(o), r, ar = [], e; |
|
try { |
|
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); |
|
} |
|
catch (error) { e = { error: error }; } |
|
finally { |
|
try { |
|
if (r && !r.done && (m = i["return"])) m.call(i); |
|
} |
|
finally { if (e) throw e.error; } |
|
} |
|
return ar; |
|
} |
|
|
|
|
|
function __spread() { |
|
for (var ar = [], i = 0; i < arguments.length; i++) |
|
ar = ar.concat(__read(arguments[i])); |
|
return ar; |
|
} |
|
|
|
|
|
function __spreadArrays() { |
|
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; |
|
for (var r = Array(s), k = 0, i = 0; i < il; i++) |
|
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) |
|
r[k] = a[j]; |
|
return r; |
|
} |
|
|
|
function __spreadArray(to, from, pack) { |
|
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { |
|
if (ar || !(i in from)) { |
|
if (!ar) ar = Array.prototype.slice.call(from, 0, i); |
|
ar[i] = from[i]; |
|
} |
|
} |
|
return to.concat(ar || Array.prototype.slice.call(from)); |
|
} |
|
|
|
function __await(v) { |
|
return this instanceof __await ? (this.v = v, this) : new __await(v); |
|
} |
|
|
|
function __asyncGenerator(thisArg, _arguments, generator) { |
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); |
|
var g = generator.apply(thisArg, _arguments || []), i, q = []; |
|
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; |
|
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } |
|
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } |
|
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } |
|
function fulfill(value) { resume("next", value); } |
|
function reject(value) { resume("throw", value); } |
|
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } |
|
} |
|
|
|
function __asyncDelegator(o) { |
|
var i, p; |
|
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; |
|
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } |
|
} |
|
|
|
function __asyncValues(o) { |
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); |
|
var m = o[Symbol.asyncIterator], i; |
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); |
|
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } |
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } |
|
} |
|
|
|
function __makeTemplateObject(cooked, raw) { |
|
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } |
|
return cooked; |
|
}; |
|
|
|
var __setModuleDefault = Object.create ? (function(o, v) { |
|
Object.defineProperty(o, "default", { enumerable: true, value: v }); |
|
}) : function(o, v) { |
|
o["default"] = v; |
|
}; |
|
|
|
function __importStar(mod) { |
|
if (mod && mod.__esModule) return mod; |
|
var result = {}; |
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
|
__setModuleDefault(result, mod); |
|
return result; |
|
} |
|
|
|
function __importDefault(mod) { |
|
return (mod && mod.__esModule) ? mod : { default: mod }; |
|
} |
|
|
|
function __classPrivateFieldGet(receiver, state, kind, f) { |
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); |
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); |
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); |
|
} |
|
|
|
function __classPrivateFieldSet(receiver, state, value, kind, f) { |
|
if (kind === "m") throw new TypeError("Private method is not writable"); |
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); |
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); |
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; |
|
} |
|
|
|
function __classPrivateFieldIn(state, receiver) { |
|
if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); |
|
return typeof state === "function" ? receiver === state : state.has(receiver); |
|
} |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("http"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("url"); |
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const WebSocket = __webpack_require__(5); |
|
|
|
WebSocket.createWebSocketStream = __webpack_require__(23); |
|
WebSocket.Server = __webpack_require__(24); |
|
WebSocket.Receiver = __webpack_require__(17); |
|
WebSocket.Sender = __webpack_require__(20); |
|
|
|
WebSocket.WebSocket = WebSocket; |
|
WebSocket.WebSocketServer = WebSocket.Server; |
|
|
|
module.exports = WebSocket; |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
|
|
|
|
const EventEmitter = __webpack_require__(6); |
|
const https = __webpack_require__(7); |
|
const http = __webpack_require__(2); |
|
const net = __webpack_require__(8); |
|
const tls = __webpack_require__(9); |
|
const { randomBytes, createHash } = __webpack_require__(10); |
|
const { Readable } = __webpack_require__(11); |
|
const { URL } = __webpack_require__(3); |
|
|
|
const PerMessageDeflate = __webpack_require__(12); |
|
const Receiver = __webpack_require__(17); |
|
const Sender = __webpack_require__(20); |
|
const { |
|
BINARY_TYPES, |
|
EMPTY_BUFFER, |
|
GUID, |
|
kForOnEventAttribute, |
|
kListener, |
|
kStatusCode, |
|
kWebSocket, |
|
NOOP |
|
} = __webpack_require__(15); |
|
const { |
|
EventTarget: { addEventListener, removeEventListener } |
|
} = __webpack_require__(21); |
|
const { format, parse } = __webpack_require__(22); |
|
const { toBuffer } = __webpack_require__(14); |
|
|
|
const closeTimeout = 30 * 1000; |
|
const kAborted = Symbol('kAborted'); |
|
const protocolVersions = [8, 13]; |
|
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; |
|
const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; |
|
|
|
|
|
|
|
|
|
|
|
|
|
class WebSocket extends EventEmitter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 === undefined) { |
|
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 receiver = new Receiver({ |
|
binaryType: this.binaryType, |
|
extensions: this._extensions, |
|
isServer: this._isServer, |
|
maxPayload: options.maxPayload, |
|
skipUTF8Validation: options.skipUTF8Validation |
|
}); |
|
|
|
this._sender = new Sender(socket, this._extensions, options.generateMask); |
|
this._receiver = receiver; |
|
this._socket = socket; |
|
|
|
receiver[kWebSocket] = this; |
|
socket[kWebSocket] = this; |
|
|
|
receiver.on('conclude', receiverOnConclude); |
|
receiver.on('drain', receiverOnDrain); |
|
receiver.on('error', receiverOnError); |
|
receiver.on('message', receiverOnMessage); |
|
receiver.on('ping', receiverOnPing); |
|
receiver.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); |
|
|
|
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.extensionName]) { |
|
this._extensions[PerMessageDeflate.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(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, mask, cb) { |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); |
|
} |
|
|
|
if (typeof data === 'function') { |
|
cb = data; |
|
data = mask = undefined; |
|
} else if (typeof mask === 'function') { |
|
cb = mask; |
|
mask = undefined; |
|
} |
|
|
|
if (typeof data === 'number') data = data.toString(); |
|
|
|
if (this.readyState !== WebSocket.OPEN) { |
|
sendAfterClose(this, data, cb); |
|
return; |
|
} |
|
|
|
if (mask === undefined) mask = !this._isServer; |
|
this._sender.ping(data || EMPTY_BUFFER, mask, cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pong(data, mask, cb) { |
|
if (this.readyState === WebSocket.CONNECTING) { |
|
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); |
|
} |
|
|
|
if (typeof data === 'function') { |
|
cb = data; |
|
data = mask = undefined; |
|
} else if (typeof mask === 'function') { |
|
cb = mask; |
|
mask = undefined; |
|
} |
|
|
|
if (typeof data === 'number') data = data.toString(); |
|
|
|
if (this.readyState !== WebSocket.OPEN) { |
|
sendAfterClose(this, data, cb); |
|
return; |
|
} |
|
|
|
if (mask === undefined) mask = !this._isServer; |
|
this._sender.pong(data || EMPTY_BUFFER, mask, 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.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(this, this._req, msg); |
|
return; |
|
} |
|
|
|
if (this._socket) { |
|
this._readyState = WebSocket.CLOSING; |
|
this._socket.destroy(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket, 'CONNECTING', { |
|
enumerable: true, |
|
value: readyStates.indexOf('CONNECTING') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket.prototype, 'CONNECTING', { |
|
enumerable: true, |
|
value: readyStates.indexOf('CONNECTING') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket, 'OPEN', { |
|
enumerable: true, |
|
value: readyStates.indexOf('OPEN') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket.prototype, 'OPEN', { |
|
enumerable: true, |
|
value: readyStates.indexOf('OPEN') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket, 'CLOSING', { |
|
enumerable: true, |
|
value: readyStates.indexOf('CLOSING') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket.prototype, 'CLOSING', { |
|
enumerable: true, |
|
value: readyStates.indexOf('CLOSING') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket, 'CLOSED', { |
|
enumerable: true, |
|
value: readyStates.indexOf('CLOSED') |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(WebSocket.prototype, 'CLOSED', { |
|
enumerable: true, |
|
value: readyStates.indexOf('CLOSED') |
|
}); |
|
|
|
[ |
|
'binaryType', |
|
'bufferedAmount', |
|
'extensions', |
|
'isPaused', |
|
'protocol', |
|
'readyState', |
|
'url' |
|
].forEach((property) => { |
|
Object.defineProperty(WebSocket.prototype, property, { enumerable: true }); |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
['open', 'error', 'close', 'message'].forEach((method) => { |
|
Object.defineProperty(WebSocket.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.prototype.addEventListener = addEventListener; |
|
WebSocket.prototype.removeEventListener = removeEventListener; |
|
|
|
module.exports = WebSocket; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function initAsClient(websocket, address, protocols, options) { |
|
const opts = { |
|
protocolVersion: protocolVersions[1], |
|
maxPayload: 100 * 1024 * 1024, |
|
skipUTF8Validation: false, |
|
perMessageDeflate: true, |
|
followRedirects: false, |
|
maxRedirects: 10, |
|
...options, |
|
createConnection: undefined, |
|
socketPath: undefined, |
|
hostname: undefined, |
|
protocol: undefined, |
|
timeout: undefined, |
|
method: 'GET', |
|
host: undefined, |
|
path: undefined, |
|
port: undefined |
|
}; |
|
|
|
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; |
|
websocket._url = address.href; |
|
} else { |
|
try { |
|
parsedUrl = new URL(address); |
|
} catch (e) { |
|
throw new SyntaxError(`Invalid URL: ${address}`); |
|
} |
|
|
|
websocket._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 (websocket._redirects === 0) { |
|
throw err; |
|
} else { |
|
emitErrorAndClose(websocket, err); |
|
return; |
|
} |
|
} |
|
|
|
const defaultPort = isSecure ? 443 : 80; |
|
const key = randomBytes(16).toString('base64'); |
|
const request = isSecure ? https.request : http.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( |
|
opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, |
|
false, |
|
opts.maxPayload |
|
); |
|
opts.headers['Sec-WebSocket-Extensions'] = format({ |
|
[PerMessageDeflate.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 (websocket._redirects === 0) { |
|
websocket._originalIpc = isIpcUrl; |
|
websocket._originalSecure = isSecure; |
|
websocket._originalHostOrSocketPath = isIpcUrl |
|
? opts.socketPath |
|
: parsedUrl.host; |
|
|
|
const headers = options && options.headers; |
|
|
|
|
|
|
|
|
|
|
|
options = { ...options, headers: {} }; |
|
|
|
if (headers) { |
|
for (const [key, value] of Object.entries(headers)) { |
|
options.headers[key.toLowerCase()] = value; |
|
} |
|
} |
|
} else if (websocket.listenerCount('redirect') === 0) { |
|
const isSameHost = isIpcUrl |
|
? websocket._originalIpc |
|
? opts.socketPath === websocket._originalHostOrSocketPath |
|
: false |
|
: websocket._originalIpc |
|
? false |
|
: parsedUrl.host === websocket._originalHostOrSocketPath; |
|
|
|
if (!isSameHost || (websocket._originalSecure && !isSecure)) { |
|
|
|
|
|
|
|
|
|
delete opts.headers.authorization; |
|
delete opts.headers.cookie; |
|
|
|
if (!isSameHost) delete opts.headers.host; |
|
|
|
opts.auth = undefined; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (opts.auth && !options.headers.authorization) { |
|
options.headers.authorization = |
|
'Basic ' + Buffer.from(opts.auth).toString('base64'); |
|
} |
|
|
|
req = websocket._req = request(opts); |
|
|
|
if (websocket._redirects) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
websocket.emit('redirect', websocket.url, req); |
|
} |
|
} else { |
|
req = websocket._req = request(opts); |
|
} |
|
|
|
if (opts.timeout) { |
|
req.on('timeout', () => { |
|
abortHandshake(websocket, req, 'Opening handshake has timed out'); |
|
}); |
|
} |
|
|
|
req.on('error', (err) => { |
|
if (req === null || req[kAborted]) return; |
|
|
|
req = websocket._req = null; |
|
emitErrorAndClose(websocket, err); |
|
}); |
|
|
|
req.on('response', (res) => { |
|
const location = res.headers.location; |
|
const statusCode = res.statusCode; |
|
|
|
if ( |
|
location && |
|
opts.followRedirects && |
|
statusCode >= 300 && |
|
statusCode < 400 |
|
) { |
|
if (++websocket._redirects > opts.maxRedirects) { |
|
abortHandshake(websocket, 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(websocket, err); |
|
return; |
|
} |
|
|
|
initAsClient(websocket, addr, protocols, options); |
|
} else if (!websocket.emit('unexpected-response', req, res)) { |
|
abortHandshake( |
|
websocket, |
|
req, |
|
`Unexpected server response: ${res.statusCode}` |
|
); |
|
} |
|
}); |
|
|
|
req.on('upgrade', (res, socket, head) => { |
|
websocket.emit('upgrade', res); |
|
|
|
|
|
|
|
|
|
|
|
if (websocket.readyState !== WebSocket.CONNECTING) return; |
|
|
|
req = websocket._req = null; |
|
|
|
if (res.headers.upgrade.toLowerCase() !== 'websocket') { |
|
abortHandshake(websocket, socket, 'Invalid Upgrade header'); |
|
return; |
|
} |
|
|
|
const digest = createHash('sha1') |
|
.update(key + GUID) |
|
.digest('base64'); |
|
|
|
if (res.headers['sec-websocket-accept'] !== digest) { |
|
abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header'); |
|
return; |
|
} |
|
|
|
const serverProt = res.headers['sec-websocket-protocol']; |
|
let protError; |
|
|
|
if (serverProt !== undefined) { |
|
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(websocket, socket, protError); |
|
return; |
|
} |
|
|
|
if (serverProt) websocket._protocol = serverProt; |
|
|
|
const secWebSocketExtensions = res.headers['sec-websocket-extensions']; |
|
|
|
if (secWebSocketExtensions !== undefined) { |
|
if (!perMessageDeflate) { |
|
const message = |
|
'Server sent a Sec-WebSocket-Extensions header but no extension ' + |
|
'was requested'; |
|
abortHandshake(websocket, socket, message); |
|
return; |
|
} |
|
|
|
let extensions; |
|
|
|
try { |
|
extensions = parse(secWebSocketExtensions); |
|
} catch (err) { |
|
const message = 'Invalid Sec-WebSocket-Extensions header'; |
|
abortHandshake(websocket, socket, message); |
|
return; |
|
} |
|
|
|
const extensionNames = Object.keys(extensions); |
|
|
|
if ( |
|
extensionNames.length !== 1 || |
|
extensionNames[0] !== PerMessageDeflate.extensionName |
|
) { |
|
const message = 'Server indicated an extension that was not requested'; |
|
abortHandshake(websocket, socket, message); |
|
return; |
|
} |
|
|
|
try { |
|
perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); |
|
} catch (err) { |
|
const message = 'Invalid Sec-WebSocket-Extensions header'; |
|
abortHandshake(websocket, socket, message); |
|
return; |
|
} |
|
|
|
websocket._extensions[PerMessageDeflate.extensionName] = |
|
perMessageDeflate; |
|
} |
|
|
|
websocket.setSocket(socket, head, { |
|
generateMask: opts.generateMask, |
|
maxPayload: opts.maxPayload, |
|
skipUTF8Validation: opts.skipUTF8Validation |
|
}); |
|
}); |
|
|
|
if (opts.finishRequest) { |
|
opts.finishRequest(req, websocket); |
|
} else { |
|
req.end(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function emitErrorAndClose(websocket, err) { |
|
websocket._readyState = WebSocket.CLOSING; |
|
websocket.emit('error', err); |
|
websocket.emitClose(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function netConnect(options) { |
|
options.path = options.socketPath; |
|
return net.connect(options); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tlsConnect(options) { |
|
options.path = undefined; |
|
|
|
if (!options.servername && options.servername !== '') { |
|
options.servername = net.isIP(options.host) ? '' : options.host; |
|
} |
|
|
|
return tls.connect(options); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function abortHandshake(websocket, stream, message) { |
|
websocket._readyState = WebSocket.CLOSING; |
|
|
|
const err = new Error(message); |
|
Error.captureStackTrace(err, abortHandshake); |
|
|
|
if (stream.setHeader) { |
|
stream[kAborted] = true; |
|
stream.abort(); |
|
|
|
if (stream.socket && !stream.socket.destroyed) { |
|
|
|
|
|
|
|
|
|
|
|
stream.socket.destroy(); |
|
} |
|
|
|
process.nextTick(emitErrorAndClose, websocket, err); |
|
} else { |
|
stream.destroy(err); |
|
stream.once('error', websocket.emit.bind(websocket, 'error')); |
|
stream.once('close', websocket.emitClose.bind(websocket)); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function sendAfterClose(websocket, data, cb) { |
|
if (data) { |
|
const length = toBuffer(data).length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (websocket._socket) websocket._sender._bufferedBytes += length; |
|
else websocket._bufferedAmount += length; |
|
} |
|
|
|
if (cb) { |
|
const err = new Error( |
|
`WebSocket is not open: readyState ${websocket.readyState} ` + |
|
`(${readyStates[websocket.readyState]})` |
|
); |
|
process.nextTick(cb, err); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnConclude(code, reason) { |
|
const websocket = this[kWebSocket]; |
|
|
|
websocket._closeFrameReceived = true; |
|
websocket._closeMessage = reason; |
|
websocket._closeCode = code; |
|
|
|
if (websocket._socket[kWebSocket] === undefined) return; |
|
|
|
websocket._socket.removeListener('data', socketOnData); |
|
process.nextTick(resume, websocket._socket); |
|
|
|
if (code === 1005) websocket.close(); |
|
else websocket.close(code, reason); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnDrain() { |
|
const websocket = this[kWebSocket]; |
|
|
|
if (!websocket.isPaused) websocket._socket.resume(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnError(err) { |
|
const websocket = this[kWebSocket]; |
|
|
|
if (websocket._socket[kWebSocket] !== undefined) { |
|
websocket._socket.removeListener('data', socketOnData); |
|
|
|
|
|
|
|
|
|
|
|
process.nextTick(resume, websocket._socket); |
|
|
|
websocket.close(err[kStatusCode]); |
|
} |
|
|
|
websocket.emit('error', err); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnFinish() { |
|
this[kWebSocket].emitClose(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnMessage(data, isBinary) { |
|
this[kWebSocket].emit('message', data, isBinary); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnPing(data) { |
|
const websocket = this[kWebSocket]; |
|
|
|
websocket.pong(data, !websocket._isServer, NOOP); |
|
websocket.emit('ping', data); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function receiverOnPong(data) { |
|
this[kWebSocket].emit('pong', data); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resume(stream) { |
|
stream.resume(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function socketOnClose() { |
|
const websocket = this[kWebSocket]; |
|
|
|
this.removeListener('close', socketOnClose); |
|
this.removeListener('data', socketOnData); |
|
this.removeListener('end', socketOnEnd); |
|
|
|
websocket._readyState = WebSocket.CLOSING; |
|
|
|
let chunk; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( |
|
!this._readableState.endEmitted && |
|
!websocket._closeFrameReceived && |
|
!websocket._receiver._writableState.errorEmitted && |
|
(chunk = websocket._socket.read()) !== null |
|
) { |
|
websocket._receiver.write(chunk); |
|
} |
|
|
|
websocket._receiver.end(); |
|
|
|
this[kWebSocket] = undefined; |
|
|
|
clearTimeout(websocket._closeTimer); |
|
|
|
if ( |
|
websocket._receiver._writableState.finished || |
|
websocket._receiver._writableState.errorEmitted |
|
) { |
|
websocket.emitClose(); |
|
} else { |
|
websocket._receiver.on('error', receiverOnFinish); |
|
websocket._receiver.on('finish', receiverOnFinish); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function socketOnData(chunk) { |
|
if (!this[kWebSocket]._receiver.write(chunk)) { |
|
this.pause(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function socketOnEnd() { |
|
const websocket = this[kWebSocket]; |
|
|
|
websocket._readyState = WebSocket.CLOSING; |
|
websocket._receiver.end(); |
|
this.end(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function socketOnError() { |
|
const websocket = this[kWebSocket]; |
|
|
|
this.removeListener('error', socketOnError); |
|
this.on('error', NOOP); |
|
|
|
if (websocket) { |
|
websocket._readyState = WebSocket.CLOSING; |
|
this.destroy(); |
|
} |
|
} |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("events"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("https"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("net"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("tls"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("crypto"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("stream"); |
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const zlib = __webpack_require__(13); |
|
|
|
const bufferUtil = __webpack_require__(14); |
|
const Limiter = __webpack_require__(16); |
|
const { kStatusCode } = __webpack_require__(15); |
|
|
|
const FastBuffer = Buffer[Symbol.species]; |
|
const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); |
|
const kPerMessageDeflate = Symbol('permessage-deflate'); |
|
const kTotalLength = Symbol('total-length'); |
|
const kCallback = Symbol('callback'); |
|
const kBuffers = Symbol('buffers'); |
|
const kError = Symbol('error'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let zlibLimiter; |
|
|
|
|
|
|
|
|
|
class PerMessageDeflate { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
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]; |
|
|
|
if (err) { |
|
this._inflate.close(); |
|
this._inflate = null; |
|
callback(err); |
|
return; |
|
} |
|
|
|
const data = 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, data); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_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 data = bufferUtil.concat( |
|
this._deflate[kBuffers], |
|
this._deflate[kTotalLength] |
|
); |
|
|
|
if (fin) { |
|
data = new FastBuffer(data.buffer, data.byteOffset, data.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, data); |
|
}); |
|
} |
|
} |
|
|
|
module.exports = PerMessageDeflate; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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] = new RangeError('Max payload size exceeded'); |
|
this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; |
|
this[kError][kStatusCode] = 1009; |
|
this.removeListener('data', inflateOnData); |
|
this.reset(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function inflateOnError(err) { |
|
|
|
|
|
|
|
|
|
this[kPerMessageDeflate]._inflate = null; |
|
err[kStatusCode] = 1007; |
|
this[kCallback](err); |
|
} |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("zlib"); |
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { EMPTY_BUFFER } = __webpack_require__(15); |
|
|
|
const FastBuffer = Buffer[Symbol.species]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function concat(list, totalLength) { |
|
if (list.length === 0) return EMPTY_BUFFER; |
|
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(target.buffer, target.byteOffset, offset); |
|
} |
|
|
|
return target; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function _mask(source, mask, output, offset, length) { |
|
for (let i = 0; i < length; i++) { |
|
output[offset + i] = source[i] ^ mask[i & 3]; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function _unmask(buffer, mask) { |
|
for (let i = 0; i < buffer.length; i++) { |
|
buffer[i] ^= mask[i & 3]; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toArrayBuffer(buf) { |
|
if (buf.length === buf.buffer.byteLength) { |
|
return buf.buffer; |
|
} |
|
|
|
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toBuffer(data) { |
|
toBuffer.readOnly = true; |
|
|
|
if (Buffer.isBuffer(data)) return data; |
|
|
|
let buf; |
|
|
|
if (data instanceof ArrayBuffer) { |
|
buf = new FastBuffer(data); |
|
} else if (ArrayBuffer.isView(data)) { |
|
buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength); |
|
} else { |
|
buf = Buffer.from(data); |
|
toBuffer.readOnly = false; |
|
} |
|
|
|
return buf; |
|
} |
|
|
|
module.exports = { |
|
concat, |
|
mask: _mask, |
|
toArrayBuffer, |
|
toBuffer, |
|
unmask: _unmask |
|
}; |
|
|
|
|
|
if (!process.env.WS_NO_BUFFER_UTIL) { |
|
try { |
|
const bufferUtil = __webpack_require__(Object(function webpackMissingModule() { var e = new Error("Cannot find module 'bufferutil'"); e.code = 'MODULE_NOT_FOUND'; throw e; }())); |
|
|
|
module.exports.mask = function (source, mask, output, offset, length) { |
|
if (length < 48) _mask(source, mask, output, offset, length); |
|
else bufferUtil.mask(source, mask, output, offset, length); |
|
}; |
|
|
|
module.exports.unmask = function (buffer, mask) { |
|
if (buffer.length < 32) _unmask(buffer, mask); |
|
else bufferUtil.unmask(buffer, mask); |
|
}; |
|
} catch (e) { |
|
|
|
} |
|
} |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
|
|
|
|
module.exports = { |
|
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: () => {} |
|
}; |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const kDone = Symbol('kDone'); |
|
const kRun = Symbol('kRun'); |
|
|
|
|
|
|
|
|
|
|
|
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]); |
|
} |
|
} |
|
} |
|
|
|
module.exports = Limiter; |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { Writable } = __webpack_require__(11); |
|
|
|
const PerMessageDeflate = __webpack_require__(12); |
|
const { |
|
BINARY_TYPES, |
|
EMPTY_BUFFER, |
|
kStatusCode, |
|
kWebSocket |
|
} = __webpack_require__(15); |
|
const { concat, toArrayBuffer, unmask } = __webpack_require__(14); |
|
const { isValidStatusCode, isValidUTF8 } = __webpack_require__(18); |
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
class Receiver extends Writable { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(options = {}) { |
|
super(); |
|
|
|
this._binaryType = options.binaryType || BINARY_TYPES[0]; |
|
this._extensions = options.extensions || {}; |
|
this._isServer = !!options.isServer; |
|
this._maxPayload = options.maxPayload | 0; |
|
this._skipUTF8Validation = !!options.skipUTF8Validation; |
|
this[kWebSocket] = undefined; |
|
|
|
this._bufferedBytes = 0; |
|
this._buffers = []; |
|
|
|
this._compressed = false; |
|
this._payloadLength = 0; |
|
this._mask = undefined; |
|
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 === 0x08 && 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] & 0x30) !== 0x00) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
'RSV2 and RSV3 must be clear', |
|
true, |
|
1002, |
|
'WS_ERR_UNEXPECTED_RSV_2_3' |
|
); |
|
} |
|
|
|
const compressed = (buf[0] & 0x40) === 0x40; |
|
|
|
if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { |
|
this._loop = false; |
|
return error( |
|
RangeError, |
|
'RSV1 must be clear', |
|
true, |
|
1002, |
|
'WS_ERR_UNEXPECTED_RSV_1' |
|
); |
|
} |
|
|
|
this._fin = (buf[0] & 0x80) === 0x80; |
|
this._opcode = buf[0] & 0x0f; |
|
this._payloadLength = buf[1] & 0x7f; |
|
|
|
if (this._opcode === 0x00) { |
|
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 === 0x01 || this._opcode === 0x02) { |
|
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 > 0x07 && this._opcode < 0x0b) { |
|
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 > 0x7d || |
|
(this._opcode === 0x08 && 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] & 0x80) === 0x80; |
|
|
|
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 < 0x08) { |
|
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; |
|
|
|
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 > 0x07) 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.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 === 0x08) { |
|
this._loop = false; |
|
|
|
if (data.length === 0) { |
|
this.emit('conclude', 1005, EMPTY_BUFFER); |
|
this.end(); |
|
} else { |
|
const code = data.readUInt16BE(0); |
|
|
|
if (!isValidStatusCode(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 === 0x09) { |
|
this.emit('ping', data); |
|
} else { |
|
this.emit('pong', data); |
|
} |
|
|
|
this._state = GET_INFO; |
|
} |
|
} |
|
|
|
module.exports = Receiver; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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] = statusCode; |
|
return err; |
|
} |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { isUtf8 } = __webpack_require__(19); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const tokenChars = [ |
|
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(code) { |
|
return ( |
|
(code >= 1000 && |
|
code <= 1014 && |
|
code !== 1004 && |
|
code !== 1005 && |
|
code !== 1006) || |
|
(code >= 3000 && code <= 4999) |
|
); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function _isValidUTF8(buf) { |
|
const len = buf.length; |
|
let i = 0; |
|
|
|
while (i < len) { |
|
if ((buf[i] & 0x80) === 0) { |
|
|
|
i++; |
|
} else if ((buf[i] & 0xe0) === 0xc0) { |
|
|
|
if ( |
|
i + 1 === len || |
|
(buf[i + 1] & 0xc0) !== 0x80 || |
|
(buf[i] & 0xfe) === 0xc0 |
|
) { |
|
return false; |
|
} |
|
|
|
i += 2; |
|
} else if ((buf[i] & 0xf0) === 0xe0) { |
|
|
|
if ( |
|
i + 2 >= len || |
|
(buf[i + 1] & 0xc0) !== 0x80 || |
|
(buf[i + 2] & 0xc0) !== 0x80 || |
|
(buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || |
|
(buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) |
|
) { |
|
return false; |
|
} |
|
|
|
i += 3; |
|
} else if ((buf[i] & 0xf8) === 0xf0) { |
|
|
|
if ( |
|
i + 3 >= len || |
|
(buf[i + 1] & 0xc0) !== 0x80 || |
|
(buf[i + 2] & 0xc0) !== 0x80 || |
|
(buf[i + 3] & 0xc0) !== 0x80 || |
|
(buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || |
|
(buf[i] === 0xf4 && buf[i + 1] > 0x8f) || |
|
buf[i] > 0xf4 |
|
) { |
|
return false; |
|
} |
|
|
|
i += 4; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
module.exports = { |
|
isValidStatusCode, |
|
isValidUTF8: _isValidUTF8, |
|
tokenChars |
|
}; |
|
|
|
if (isUtf8) { |
|
module.exports.isValidUTF8 = function (buf) { |
|
return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf); |
|
}; |
|
} else if (!process.env.WS_NO_UTF_8_VALIDATE) { |
|
try { |
|
const isValidUTF8 = __webpack_require__(Object(function webpackMissingModule() { var e = new Error("Cannot find module 'utf-8-validate'"); e.code = 'MODULE_NOT_FOUND'; throw e; }())); |
|
|
|
module.exports.isValidUTF8 = function (buf) { |
|
return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf); |
|
}; |
|
} catch (e) { |
|
|
|
} |
|
} |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("buffer"); |
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
|
|
|
|
const net = __webpack_require__(8); |
|
const tls = __webpack_require__(9); |
|
const { randomFillSync } = __webpack_require__(10); |
|
|
|
const PerMessageDeflate = __webpack_require__(12); |
|
const { EMPTY_BUFFER } = __webpack_require__(15); |
|
const { isValidStatusCode } = __webpack_require__(18); |
|
const { mask: applyMask, toBuffer } = __webpack_require__(14); |
|
|
|
const kByteLength = Symbol('kByteLength'); |
|
const maskBuffer = Buffer.alloc(4); |
|
|
|
|
|
|
|
|
|
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 mask; |
|
let merge = false; |
|
let offset = 2; |
|
let skipMasking = false; |
|
|
|
if (options.mask) { |
|
mask = options.maskBuffer || maskBuffer; |
|
|
|
if (options.generateMask) { |
|
options.generateMask(mask); |
|
} else { |
|
randomFillSync(mask, 0, 4); |
|
} |
|
|
|
skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; |
|
offset = 6; |
|
} |
|
|
|
let dataLength; |
|
|
|
if (typeof data === 'string') { |
|
if ( |
|
(!options.mask || skipMasking) && |
|
options[kByteLength] !== undefined |
|
) { |
|
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 | 0x80 : options.opcode; |
|
if (options.rsv1) target[0] |= 0x40; |
|
|
|
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] |= 0x80; |
|
target[offset - 4] = mask[0]; |
|
target[offset - 3] = mask[1]; |
|
target[offset - 2] = mask[2]; |
|
target[offset - 1] = mask[3]; |
|
|
|
if (skipMasking) return [target, data]; |
|
|
|
if (merge) { |
|
applyMask(data, mask, target, offset, dataLength); |
|
return [target]; |
|
} |
|
|
|
applyMask(data, mask, data, 0, dataLength); |
|
return [target, data]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close(code, data, mask, cb) { |
|
let buf; |
|
|
|
if (code === undefined) { |
|
buf = EMPTY_BUFFER; |
|
} else if (typeof code !== 'number' || !isValidStatusCode(code)) { |
|
throw new TypeError('First argument must be a valid error code number'); |
|
} else if (data === undefined || !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, |
|
maskBuffer: this._maskBuffer, |
|
opcode: 0x08, |
|
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, mask, cb) { |
|
let byteLength; |
|
let readOnly; |
|
|
|
if (typeof data === 'string') { |
|
byteLength = Buffer.byteLength(data); |
|
readOnly = false; |
|
} else { |
|
data = toBuffer(data); |
|
byteLength = data.length; |
|
readOnly = toBuffer.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, |
|
maskBuffer: this._maskBuffer, |
|
opcode: 0x09, |
|
readOnly, |
|
rsv1: false |
|
}; |
|
|
|
if (this._deflating) { |
|
this.enqueue([this.dispatch, data, false, options, cb]); |
|
} else { |
|
this.sendFrame(Sender.frame(data, options), cb); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pong(data, mask, cb) { |
|
let byteLength; |
|
let readOnly; |
|
|
|
if (typeof data === 'string') { |
|
byteLength = Buffer.byteLength(data); |
|
readOnly = false; |
|
} else { |
|
data = toBuffer(data); |
|
byteLength = data.length; |
|
readOnly = toBuffer.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, |
|
maskBuffer: this._maskBuffer, |
|
opcode: 0x0a, |
|
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.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(data); |
|
byteLength = data.length; |
|
readOnly = toBuffer.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.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); |
|
} |
|
} |
|
} |
|
|
|
module.exports = Sender; |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { kForOnEventAttribute, kListener } = __webpack_require__(15); |
|
|
|
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 === undefined ? 0 : options.code; |
|
this[kReason] = options.reason === undefined ? '' : options.reason; |
|
this[kWasClean] = options.wasClean === undefined ? 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 === undefined ? null : options.error; |
|
this[kMessage] = options.message === undefined ? '' : 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 === undefined ? 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] && |
|
listener[kListener] === handler && |
|
!listener[kForOnEventAttribute] |
|
) { |
|
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(error) { |
|
const event = new ErrorEvent('error', { |
|
error, |
|
message: error.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] = !!options[kForOnEventAttribute]; |
|
wrapper[kListener] = 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] === handler && !listener[kForOnEventAttribute]) { |
|
this.removeListener(type, listener); |
|
break; |
|
} |
|
} |
|
} |
|
}; |
|
|
|
module.exports = { |
|
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); |
|
} |
|
} |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { tokenChars } = __webpack_require__(18); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function push(dest, name, elem) { |
|
if (dest[name] === undefined) dest[name] = [elem]; |
|
else dest[name].push(elem); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function parse(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 === undefined) { |
|
if (end === -1 && tokenChars[code] === 1) { |
|
if (start === -1) start = i; |
|
} else if ( |
|
i !== 0 && |
|
(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; |
|
const name = header.slice(start, end); |
|
if (code === 0x2c) { |
|
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 === 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 = Object.create(null); |
|
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 { |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
let 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 = Object.create(null); |
|
extensionName = undefined; |
|
} |
|
|
|
paramName = undefined; |
|
start = end = -1; |
|
} else { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
} |
|
} |
|
|
|
if (start === -1 || inQuotes || code === 0x20 || code === 0x09) { |
|
throw new SyntaxError('Unexpected end of input'); |
|
} |
|
|
|
if (end === -1) end = i; |
|
const token = header.slice(start, end); |
|
if (extensionName === undefined) { |
|
push(offers, token, params); |
|
} 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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function format(extensions) { |
|
return Object.keys(extensions) |
|
.map((extension) => { |
|
let configurations = extensions[extension]; |
|
if (!Array.isArray(configurations)) configurations = [configurations]; |
|
return configurations |
|
.map((params) => { |
|
return [extension] |
|
.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(', '); |
|
} |
|
|
|
module.exports = { format, parse }; |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { Duplex } = __webpack_require__(11); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function emitClose(stream) { |
|
stream.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 error(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, duplex); |
|
return; |
|
} |
|
|
|
let called = false; |
|
|
|
ws.once('error', function error(err) { |
|
called = true; |
|
callback(err); |
|
}); |
|
|
|
ws.once('close', function close() { |
|
if (!called) callback(err); |
|
process.nextTick(emitClose, duplex); |
|
}); |
|
|
|
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; |
|
} |
|
|
|
module.exports = createWebSocketStream; |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
|
|
|
|
const EventEmitter = __webpack_require__(6); |
|
const http = __webpack_require__(2); |
|
const https = __webpack_require__(7); |
|
const net = __webpack_require__(8); |
|
const tls = __webpack_require__(9); |
|
const { createHash } = __webpack_require__(10); |
|
|
|
const extension = __webpack_require__(22); |
|
const PerMessageDeflate = __webpack_require__(12); |
|
const subprotocol = __webpack_require__(25); |
|
const WebSocket = __webpack_require__(5); |
|
const { GUID, kWebSocket } = __webpack_require__(15); |
|
|
|
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, |
|
...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 !== undefined) { |
|
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 !== undefined |
|
) { |
|
const perMessageDeflate = new PerMessageDeflate( |
|
this.options.perMessageDeflate, |
|
true, |
|
this.options.maxPayload |
|
); |
|
|
|
try { |
|
const offers = extension.parse(secWebSocketExtensions); |
|
|
|
if (offers[PerMessageDeflate.extensionName]) { |
|
perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); |
|
extensions[PerMessageDeflate.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[PerMessageDeflate.extensionName]) { |
|
const params = extensions[PerMessageDeflate.extensionName].params; |
|
const value = extension.format({ |
|
[PerMessageDeflate.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); |
|
} |
|
} |
|
|
|
module.exports = 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\n` + |
|
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); |
|
} |
|
} |
|
|
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
|
|
const { tokenChars } = __webpack_require__(18); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 === 0x20 || code === 0x09) |
|
) { |
|
if (end === -1 && start !== -1) end = i; |
|
} else if (code === 0x2c ) { |
|
if (start === -1) { |
|
throw new SyntaxError(`Unexpected character at index ${i}`); |
|
} |
|
|
|
if (end === -1) end = i; |
|
|
|
const protocol = header.slice(start, end); |
|
|
|
if (protocols.has(protocol)) { |
|
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); |
|
} |
|
|
|
protocols.add(protocol); |
|
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; |
|
} |
|
|
|
module.exports = { parse }; |
|
|
|
|
|
}), |
|
|
|
((__unused_webpack_module, exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
Object.defineProperty(exports, "__esModule", ({ value: true })); |
|
exports.serverIndexPage = exports.index401 = exports.serverStaticFile = void 0; |
|
const node_fs_1 = __webpack_require__(27); |
|
const node_path_1 = __webpack_require__(28); |
|
const pretty_cache_header_1 = __webpack_require__(29); |
|
const mimeLookup = { |
|
'.js': 'application/javascript,charset=UTF-8', |
|
'.html': 'text/html,charset=UTF-8', |
|
'.css': 'text/css; charset=UTF-8', |
|
}; |
|
const staticPath = 'dist/apps/cf-page/'; |
|
const file401 = 'dist/apps/node-vless/assets/401.html'; |
|
let filepath = null; |
|
function serverStaticFile(req, resp) { |
|
const url = new URL(req.url, `http://${req.headers['host']}`); |
|
let fileurl = url.pathname; |
|
fileurl = (0, node_path_1.join)(staticPath, fileurl); |
|
console.log('....', fileurl); |
|
filepath = (0, node_path_1.resolve)(fileurl); |
|
console.log(filepath); |
|
if ((0, node_fs_1.existsSync)(filepath)) { |
|
let fileExt = (0, node_path_1.extname)(filepath); |
|
console.log('fileExt', fileExt); |
|
let mimeType = mimeLookup[fileExt]; |
|
resp.writeHead(200, { |
|
'Content-Type': mimeType, |
|
'Cache-Control': (0, pretty_cache_header_1.cacheHeader)({ |
|
public: true, |
|
maxAge: '1year', |
|
staleWhileRevalidate: '1year', |
|
}), |
|
}); |
|
return (0, node_fs_1.createReadStream)(filepath).pipe(resp); |
|
} |
|
else { |
|
resp.writeHead(404); |
|
resp.write('not found'); |
|
resp.end(); |
|
return resp; |
|
} |
|
} |
|
exports.serverStaticFile = serverStaticFile; |
|
function index401(req, resp) { |
|
const file401Path = (0, node_path_1.resolve)(file401); |
|
if ((0, node_fs_1.existsSync)(file401Path)) { |
|
(0, node_fs_1.createReadStream)(file401Path).pipe(resp); |
|
} |
|
else { |
|
resp.writeHead(401); |
|
resp.write('UUID env not set'); |
|
resp.end(); |
|
} |
|
} |
|
exports.index401 = index401; |
|
function serverIndexPage(req, resp, uuid) { |
|
|
|
} |
|
exports.serverIndexPage = serverIndexPage; |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("node:fs"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("node:path"); |
|
|
|
}), |
|
|
|
((module, __unused_webpack_exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
var __create = Object.create; |
|
var __defProp = Object.defineProperty; |
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; |
|
var __getOwnPropNames = Object.getOwnPropertyNames; |
|
var __getProtoOf = Object.getPrototypeOf; |
|
var __hasOwnProp = Object.prototype.hasOwnProperty; |
|
var __export = (target, all) => { |
|
for (var name in all) |
|
__defProp(target, name, { get: all[name], enumerable: true }); |
|
}; |
|
var __copyProps = (to, from, except, desc) => { |
|
if (from && typeof from === "object" || typeof from === "function") { |
|
for (let key of __getOwnPropNames(from)) |
|
if (!__hasOwnProp.call(to, key) && key !== except) |
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); |
|
} |
|
return to; |
|
}; |
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( |
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, |
|
mod |
|
)); |
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); |
|
|
|
|
|
var src_exports = {}; |
|
__export(src_exports, { |
|
cacheHeader: () => cacheHeader |
|
}); |
|
module.exports = __toCommonJS(src_exports); |
|
|
|
|
|
var import_timestring = __toESM(__webpack_require__(30), 1); |
|
function cacheHeader(params) { |
|
const transformed = Object.entries(params).reduce((acc, [key, value]) => { |
|
const kebabKey = key.replace(/[A-Z]/g, (char) => "-" + char.toLowerCase()); |
|
return typeof value === "string" || value === true ? [...acc, value === true ? kebabKey : `${kebabKey}=${(0, import_timestring.default)(value)}`] : acc; |
|
}, []); |
|
return transformed.join(", "); |
|
} |
|
|
|
0 && (0); |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
|
|
|
|
|
|
|
|
module.exports = parseTimestring |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const DEFAULT_OPTS = { |
|
hoursPerDay: 24, |
|
daysPerWeek: 7, |
|
weeksPerMonth: 4, |
|
monthsPerYear: 12, |
|
daysPerYear: 365.25 |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const UNIT_MAP = { |
|
ms: ['ms', 'milli', 'millisecond', 'milliseconds'], |
|
s: ['s', 'sec', 'secs', 'second', 'seconds'], |
|
m: ['m', 'min', 'mins', 'minute', 'minutes'], |
|
h: ['h', 'hr', 'hrs', 'hour', 'hours'], |
|
d: ['d', 'day', 'days'], |
|
w: ['w', 'week', 'weeks'], |
|
mth: ['mon', 'mth', 'mths', 'month', 'months'], |
|
y: ['y', 'yr', 'yrs', 'year', 'years'] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function parseTimestring (string, returnUnit, opts) { |
|
opts = Object.assign({}, DEFAULT_OPTS, opts || {}) |
|
|
|
let totalSeconds = 0 |
|
let unitValues = getUnitValues(opts) |
|
let groups = string |
|
.toLowerCase() |
|
.replace(/[^.\w+-]+/g, '') |
|
.match(/[-+]?[0-9.]+[a-z]+/g) |
|
|
|
if (groups === null) { |
|
throw new Error(`The string [${string}] could not be parsed by timestring`) |
|
} |
|
|
|
groups.forEach(group => { |
|
let value = group.match(/[0-9.]+/g)[0] |
|
let unit = group.match(/[a-z]+/g)[0] |
|
|
|
totalSeconds += getSeconds(value, unit, unitValues) |
|
}) |
|
|
|
if (returnUnit) { |
|
return convert(totalSeconds, returnUnit, unitValues) |
|
} |
|
|
|
return totalSeconds |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getUnitValues (opts) { |
|
let unitValues = { |
|
ms: 0.001, |
|
s: 1, |
|
m: 60, |
|
h: 3600 |
|
} |
|
|
|
unitValues.d = opts.hoursPerDay * unitValues.h |
|
unitValues.w = opts.daysPerWeek * unitValues.d |
|
unitValues.mth = (opts.daysPerYear / opts.monthsPerYear) * unitValues.d |
|
unitValues.y = opts.daysPerYear * unitValues.d |
|
|
|
return unitValues |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getUnitKey (unit) { |
|
for (let key of Object.keys(UNIT_MAP)) { |
|
if (UNIT_MAP[key].indexOf(unit) > -1) { |
|
return key |
|
} |
|
} |
|
|
|
throw new Error(`The unit [${unit}] is not supported by timestring`) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getSeconds (value, unit, unitValues) { |
|
return value * unitValues[getUnitKey(unit)] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function convert (value, unit, unitValues) { |
|
return value / unitValues[getUnitKey(unit)] |
|
} |
|
|
|
|
|
}), |
|
|
|
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
__webpack_require__.r(__webpack_exports__); |
|
|
|
|
|
__webpack_require__.d(__webpack_exports__, { |
|
"NIL": () => ( nil), |
|
"parse": () => ( esm_node_parse), |
|
"stringify": () => ( esm_node_stringify), |
|
"v1": () => ( esm_node_v1), |
|
"v3": () => ( esm_node_v3), |
|
"v4": () => ( esm_node_v4), |
|
"v5": () => ( esm_node_v5), |
|
"validate": () => ( esm_node_validate), |
|
"version": () => ( esm_node_version) |
|
}); |
|
|
|
|
|
var external_crypto_ = __webpack_require__(10); |
|
var external_crypto_default = __webpack_require__.n(external_crypto_); |
|
; |
|
|
|
const rnds8Pool = new Uint8Array(256); |
|
|
|
let poolPtr = rnds8Pool.length; |
|
function rng() { |
|
if (poolPtr > rnds8Pool.length - 16) { |
|
external_crypto_default().randomFillSync(rnds8Pool); |
|
poolPtr = 0; |
|
} |
|
|
|
return rnds8Pool.slice(poolPtr, poolPtr += 16); |
|
} |
|
; |
|
const regex = (/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i); |
|
; |
|
|
|
|
|
function validate(uuid) { |
|
return typeof uuid === 'string' && regex.test(uuid); |
|
} |
|
|
|
const esm_node_validate = (validate); |
|
; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const byteToHex = []; |
|
|
|
for (let i = 0; i < 256; ++i) { |
|
byteToHex.push((i + 0x100).toString(16).slice(1)); |
|
} |
|
|
|
function unsafeStringify(arr, offset = 0) { |
|
|
|
|
|
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); |
|
} |
|
|
|
function stringify(arr, offset = 0) { |
|
const uuid = unsafeStringify(arr, offset); |
|
|
|
|
|
|
|
|
|
|
|
if (!esm_node_validate(uuid)) { |
|
throw TypeError('Stringified UUID is invalid'); |
|
} |
|
|
|
return uuid; |
|
} |
|
|
|
const esm_node_stringify = (stringify); |
|
; |
|
|
|
|
|
|
|
|
|
|
|
|
|
let _nodeId; |
|
|
|
let _clockseq; |
|
|
|
|
|
let _lastMSecs = 0; |
|
let _lastNSecs = 0; |
|
|
|
function v1(options, buf, offset) { |
|
let i = buf && offset || 0; |
|
const b = buf || new Array(16); |
|
options = options || {}; |
|
let node = options.node || _nodeId; |
|
let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; |
|
|
|
|
|
|
|
if (node == null || clockseq == null) { |
|
const seedBytes = options.random || (options.rng || rng)(); |
|
|
|
if (node == null) { |
|
|
|
node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; |
|
} |
|
|
|
if (clockseq == null) { |
|
|
|
clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
let msecs = options.msecs !== undefined ? options.msecs : Date.now(); |
|
|
|
|
|
let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; |
|
|
|
const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; |
|
|
|
if (dt < 0 && options.clockseq === undefined) { |
|
clockseq = clockseq + 1 & 0x3fff; |
|
} |
|
|
|
|
|
|
|
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { |
|
nsecs = 0; |
|
} |
|
|
|
|
|
if (nsecs >= 10000) { |
|
throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); |
|
} |
|
|
|
_lastMSecs = msecs; |
|
_lastNSecs = nsecs; |
|
_clockseq = clockseq; |
|
|
|
msecs += 12219292800000; |
|
|
|
const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; |
|
b[i++] = tl >>> 24 & 0xff; |
|
b[i++] = tl >>> 16 & 0xff; |
|
b[i++] = tl >>> 8 & 0xff; |
|
b[i++] = tl & 0xff; |
|
|
|
const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; |
|
b[i++] = tmh >>> 8 & 0xff; |
|
b[i++] = tmh & 0xff; |
|
|
|
b[i++] = tmh >>> 24 & 0xf | 0x10; |
|
|
|
b[i++] = tmh >>> 16 & 0xff; |
|
|
|
b[i++] = clockseq >>> 8 | 0x80; |
|
|
|
b[i++] = clockseq & 0xff; |
|
|
|
for (let n = 0; n < 6; ++n) { |
|
b[i + n] = node[n]; |
|
} |
|
|
|
return buf || unsafeStringify(b); |
|
} |
|
|
|
const esm_node_v1 = (v1); |
|
; |
|
|
|
|
|
function parse(uuid) { |
|
if (!esm_node_validate(uuid)) { |
|
throw TypeError('Invalid UUID'); |
|
} |
|
|
|
let v; |
|
const arr = new Uint8Array(16); |
|
|
|
arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; |
|
arr[1] = v >>> 16 & 0xff; |
|
arr[2] = v >>> 8 & 0xff; |
|
arr[3] = v & 0xff; |
|
|
|
arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; |
|
arr[5] = v & 0xff; |
|
|
|
arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; |
|
arr[7] = v & 0xff; |
|
|
|
arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; |
|
arr[9] = v & 0xff; |
|
|
|
|
|
arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; |
|
arr[11] = v / 0x100000000 & 0xff; |
|
arr[12] = v >>> 24 & 0xff; |
|
arr[13] = v >>> 16 & 0xff; |
|
arr[14] = v >>> 8 & 0xff; |
|
arr[15] = v & 0xff; |
|
return arr; |
|
} |
|
|
|
const esm_node_parse = (parse); |
|
; |
|
|
|
|
|
|
|
function stringToBytes(str) { |
|
str = unescape(encodeURIComponent(str)); |
|
|
|
const bytes = []; |
|
|
|
for (let i = 0; i < str.length; ++i) { |
|
bytes.push(str.charCodeAt(i)); |
|
} |
|
|
|
return bytes; |
|
} |
|
|
|
const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; |
|
const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; |
|
function v35(name, version, hashfunc) { |
|
function generateUUID(value, namespace, buf, offset) { |
|
var _namespace; |
|
|
|
if (typeof value === 'string') { |
|
value = stringToBytes(value); |
|
} |
|
|
|
if (typeof namespace === 'string') { |
|
namespace = esm_node_parse(namespace); |
|
} |
|
|
|
if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { |
|
throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); |
|
} |
|
|
|
|
|
|
|
|
|
let bytes = new Uint8Array(16 + value.length); |
|
bytes.set(namespace); |
|
bytes.set(value, namespace.length); |
|
bytes = hashfunc(bytes); |
|
bytes[6] = bytes[6] & 0x0f | version; |
|
bytes[8] = bytes[8] & 0x3f | 0x80; |
|
|
|
if (buf) { |
|
offset = offset || 0; |
|
|
|
for (let i = 0; i < 16; ++i) { |
|
buf[offset + i] = bytes[i]; |
|
} |
|
|
|
return buf; |
|
} |
|
|
|
return unsafeStringify(bytes); |
|
} |
|
|
|
|
|
try { |
|
generateUUID.name = name; |
|
} catch (err) {} |
|
|
|
|
|
generateUUID.DNS = DNS; |
|
generateUUID.URL = URL; |
|
return generateUUID; |
|
} |
|
; |
|
|
|
|
|
function md5(bytes) { |
|
if (Array.isArray(bytes)) { |
|
bytes = Buffer.from(bytes); |
|
} else if (typeof bytes === 'string') { |
|
bytes = Buffer.from(bytes, 'utf8'); |
|
} |
|
|
|
return external_crypto_default().createHash('md5').update(bytes).digest(); |
|
} |
|
|
|
const esm_node_md5 = (md5); |
|
; |
|
|
|
|
|
const v3 = v35('v3', 0x30, esm_node_md5); |
|
const esm_node_v3 = (v3); |
|
; |
|
|
|
const esm_node_native = ({ |
|
randomUUID: (external_crypto_default()).randomUUID |
|
}); |
|
; |
|
|
|
|
|
|
|
|
|
function v4(options, buf, offset) { |
|
if (esm_node_native.randomUUID && !buf && !options) { |
|
return esm_node_native.randomUUID(); |
|
} |
|
|
|
options = options || {}; |
|
const rnds = options.random || (options.rng || rng)(); |
|
|
|
rnds[6] = rnds[6] & 0x0f | 0x40; |
|
rnds[8] = rnds[8] & 0x3f | 0x80; |
|
|
|
if (buf) { |
|
offset = offset || 0; |
|
|
|
for (let i = 0; i < 16; ++i) { |
|
buf[offset + i] = rnds[i]; |
|
} |
|
|
|
return buf; |
|
} |
|
|
|
return unsafeStringify(rnds); |
|
} |
|
|
|
const esm_node_v4 = (v4); |
|
; |
|
|
|
|
|
function sha1(bytes) { |
|
if (Array.isArray(bytes)) { |
|
bytes = Buffer.from(bytes); |
|
} else if (typeof bytes === 'string') { |
|
bytes = Buffer.from(bytes, 'utf8'); |
|
} |
|
|
|
return external_crypto_default().createHash('sha1').update(bytes).digest(); |
|
} |
|
|
|
const esm_node_sha1 = (sha1); |
|
; |
|
|
|
|
|
const v5 = v35('v5', 0x50, esm_node_sha1); |
|
const esm_node_v5 = (v5); |
|
; |
|
const nil = ('00000000-0000-0000-0000-000000000000'); |
|
; |
|
|
|
|
|
function version(uuid) { |
|
if (!esm_node_validate(uuid)) { |
|
throw TypeError('Invalid UUID'); |
|
} |
|
|
|
return parseInt(uuid.slice(14, 15), 16); |
|
} |
|
|
|
const esm_node_version = (version); |
|
; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("node:dns"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("node:dgram"); |
|
|
|
}), |
|
|
|
((__unused_webpack_module, exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
Object.defineProperty(exports, "__esModule", ({ value: true })); |
|
exports.vlessJs = exports.processVlessHeader = exports.closeWebSocket = exports.makeReadableWebSocketStream = exports.delay = void 0; |
|
var vless_js_1 = __webpack_require__(35); |
|
Object.defineProperty(exports, "delay", ({ enumerable: true, get: function () { return vless_js_1.delay; } })); |
|
Object.defineProperty(exports, "makeReadableWebSocketStream", ({ enumerable: true, get: function () { return vless_js_1.makeReadableWebSocketStream; } })); |
|
Object.defineProperty(exports, "closeWebSocket", ({ enumerable: true, get: function () { return vless_js_1.safeCloseWebSocket; } })); |
|
Object.defineProperty(exports, "processVlessHeader", ({ enumerable: true, get: function () { return vless_js_1.processVlessHeader; } })); |
|
Object.defineProperty(exports, "vlessJs", ({ enumerable: true, get: function () { return vless_js_1.vlessJs; } })); |
|
|
|
|
|
}), |
|
|
|
((__unused_webpack_module, exports, __webpack_require__) => { |
|
|
|
"use strict"; |
|
|
|
Object.defineProperty(exports, "__esModule", ({ value: true })); |
|
exports.processVlessHeader = exports.safeCloseWebSocket = exports.makeReadableWebSocketStream = exports.delay = exports.vlessJs = void 0; |
|
const tslib_1 = __webpack_require__(1); |
|
const uuid_1 = __webpack_require__(31); |
|
function vlessJs() { |
|
return 'vless-js'; |
|
} |
|
exports.vlessJs = vlessJs; |
|
function delay(ms) { |
|
return new Promise((resolve, rej) => { |
|
setTimeout(resolve, ms); |
|
}); |
|
} |
|
exports.delay = delay; |
|
function makeReadableWebSocketStream(ws, earlyDataHeader, log) { |
|
let readableStreamCancel = false; |
|
return new ReadableStream({ |
|
start(controller) { |
|
ws.addEventListener('message', (e) => tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
|
|
if (readableStreamCancel) { |
|
return; |
|
} |
|
const vlessBuffer = e.data; |
|
|
|
|
|
|
|
|
|
controller.enqueue(vlessBuffer); |
|
})); |
|
ws.addEventListener('error', (e) => { |
|
log('socket has error'); |
|
readableStreamCancel = true; |
|
controller.error(e); |
|
}); |
|
ws.addEventListener('close', () => { |
|
try { |
|
log('webSocket is close'); |
|
|
|
if (readableStreamCancel) { |
|
return; |
|
} |
|
controller.close(); |
|
} |
|
catch (error) { |
|
log(`websocketStream can't close DUE to `, error); |
|
} |
|
}); |
|
|
|
const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader); |
|
if (error) { |
|
log(`earlyDataHeader has invaild base64`); |
|
safeCloseWebSocket(ws); |
|
return; |
|
} |
|
if (earlyData) { |
|
controller.enqueue(earlyData); |
|
} |
|
}, |
|
pull(controller) { |
|
|
|
|
|
}, |
|
cancel(reason) { |
|
|
|
log(`websocketStream is cancel DUE to `, reason); |
|
if (readableStreamCancel) { |
|
return; |
|
} |
|
readableStreamCancel = true; |
|
safeCloseWebSocket(ws); |
|
}, |
|
}); |
|
} |
|
exports.makeReadableWebSocketStream = makeReadableWebSocketStream; |
|
function base64ToArrayBuffer(base64Str) { |
|
if (!base64Str) { |
|
return { error: null }; |
|
} |
|
try { |
|
|
|
base64Str = base64Str.replace(/-/g, '+').replace(/_/g, '/'); |
|
const decode = atob(base64Str); |
|
const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0)); |
|
return { earlyData: arryBuffer.buffer, error: null }; |
|
} |
|
catch (error) { |
|
return { error }; |
|
} |
|
} |
|
function safeCloseWebSocket(socket) { |
|
try { |
|
if (socket.readyState === socket.OPEN) { |
|
socket.close(); |
|
} |
|
} |
|
catch (error) { |
|
console.error('safeCloseWebSocket error', error); |
|
} |
|
} |
|
exports.safeCloseWebSocket = safeCloseWebSocket; |
|
|
|
|
|
|
|
|
|
|
|
|
|
function processVlessHeader(vlessBuffer, userID |
|
|
|
|
|
) { |
|
if (vlessBuffer.byteLength < 24) { |
|
|
|
|
|
return { |
|
hasError: true, |
|
message: 'invalid data', |
|
}; |
|
} |
|
const version = new Uint8Array(vlessBuffer.slice(0, 1)); |
|
let isValidUser = false; |
|
let isUDP = false; |
|
if ((0, uuid_1.stringify)(new Uint8Array(vlessBuffer.slice(1, 17))) === userID) { |
|
isValidUser = true; |
|
} |
|
if (!isValidUser) { |
|
|
|
|
|
return { |
|
hasError: true, |
|
message: 'invalid user', |
|
}; |
|
} |
|
const optLength = new Uint8Array(vlessBuffer.slice(17, 18))[0]; |
|
|
|
const command = new Uint8Array(vlessBuffer.slice(18 + optLength, 18 + optLength + 1))[0]; |
|
|
|
|
|
|
|
if (command === 1) { |
|
} |
|
else if (command === 2) { |
|
isUDP = true; |
|
} |
|
else { |
|
return { |
|
hasError: true, |
|
message: `command ${command} is not support, command 01-tcp,02-udp,03-mux`, |
|
}; |
|
} |
|
const portIndex = 18 + optLength + 1; |
|
const portBuffer = vlessBuffer.slice(portIndex, portIndex + 2); |
|
|
|
const portRemote = new DataView(portBuffer).getInt16(0); |
|
let addressIndex = portIndex + 2; |
|
const addressBuffer = new Uint8Array(vlessBuffer.slice(addressIndex, addressIndex + 1)); |
|
|
|
|
|
|
|
const addressType = addressBuffer[0]; |
|
let addressLength = 0; |
|
let addressValueIndex = addressIndex + 1; |
|
let addressValue = ''; |
|
switch (addressType) { |
|
case 1: |
|
addressLength = 4; |
|
addressValue = new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)).join('.'); |
|
break; |
|
case 2: |
|
addressLength = new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex + 1))[0]; |
|
addressValueIndex += 1; |
|
addressValue = new TextDecoder().decode(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)); |
|
break; |
|
case 3: |
|
addressLength = 16; |
|
const dataView = new DataView(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)); |
|
|
|
const ipv6 = []; |
|
for (let i = 0; i < 8; i++) { |
|
ipv6.push(dataView.getUint16(i * 2).toString(16)); |
|
} |
|
addressValue = ipv6.join(':'); |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
default: |
|
console.log(`invild addressType is ${addressType}`); |
|
} |
|
if (!addressValue) { |
|
|
|
|
|
return { |
|
hasError: true, |
|
message: `addressValue is empty, addressType is ${addressType}`, |
|
}; |
|
} |
|
return { |
|
hasError: false, |
|
addressRemote: addressValue, |
|
portRemote, |
|
rawDataIndex: addressValueIndex + addressLength, |
|
vlessVersion: version, |
|
isUDP, |
|
}; |
|
} |
|
exports.processVlessHeader = processVlessHeader; |
|
|
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("node:net"); |
|
|
|
}), |
|
|
|
((module) => { |
|
|
|
"use strict"; |
|
module.exports = require("node:stream/web"); |
|
|
|
}) |
|
]); |
|
|
|
|
|
var __webpack_module_cache__ = {}; |
|
|
|
|
|
function __webpack_require__(moduleId) { |
|
|
|
var cachedModule = __webpack_module_cache__[moduleId]; |
|
if (cachedModule !== undefined) { |
|
return cachedModule.exports; |
|
} |
|
|
|
var module = __webpack_module_cache__[moduleId] = { |
|
|
|
|
|
exports: {} |
|
}; |
|
|
|
|
|
__webpack_modules__[moduleId](module, module.exports, __webpack_require__); |
|
|
|
|
|
return module.exports; |
|
} |
|
|
|
|
|
|
|
(() => { |
|
|
|
__webpack_require__.n = (module) => { |
|
var getter = module && module.__esModule ? |
|
() => (module['default']) : |
|
() => (module); |
|
__webpack_require__.d(getter, { a: getter }); |
|
return getter; |
|
}; |
|
})(); |
|
|
|
|
|
(() => { |
|
|
|
__webpack_require__.d = (exports, definition) => { |
|
for(var key in definition) { |
|
if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
|
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
|
} |
|
} |
|
}; |
|
})(); |
|
|
|
|
|
(() => { |
|
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) |
|
})(); |
|
|
|
|
|
(() => { |
|
|
|
__webpack_require__.r = (exports) => { |
|
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
|
} |
|
Object.defineProperty(exports, '__esModule', { value: true }); |
|
}; |
|
})(); |
|
|
|
|
|
var __webpack_exports__ = {}; |
|
|
|
(() => { |
|
"use strict"; |
|
var exports = __webpack_exports__; |
|
|
|
Object.defineProperty(exports, "__esModule", ({ value: true })); |
|
const tslib_1 = __webpack_require__(1); |
|
const http_1 = __webpack_require__(2); |
|
const url_1 = __webpack_require__(3); |
|
const ws_1 = __webpack_require__(4); |
|
const utils_1 = __webpack_require__(26); |
|
const uuid_1 = __webpack_require__(31); |
|
const node_fs_1 = __webpack_require__(27); |
|
const node_dns_1 = __webpack_require__(32); |
|
const node_dgram_1 = __webpack_require__(33); |
|
const vless_js_1 = __webpack_require__(34); |
|
const node_net_1 = __webpack_require__(36); |
|
const stream_1 = __webpack_require__(11); |
|
const web_1 = __webpack_require__(37); |
|
const port = process.env.PORT; |
|
const smallRAM = process.env.SMALLRAM || false; |
|
const userID = process.env.UUID || ''; |
|
|
|
const dnOder = process.env.DNSORDER || 'verbatim'; |
|
if (dnOder === 'ipv4first') { |
|
(0, node_dns_1.setDefaultResultOrder)(dnOder); |
|
} |
|
let isVaildUser = (0, uuid_1.validate)(userID); |
|
if (!isVaildUser) { |
|
console.log('not set valid UUID'); |
|
} |
|
const server = (0, http_1.createServer)((req, resp) => { |
|
var _a; |
|
if (!isVaildUser) { |
|
return (0, utils_1.index401)(req, resp); |
|
} |
|
const url = new URL(req.url, `http://${req.headers['host']}`); |
|
|
|
if (req.method === 'GET' && url.pathname.startsWith('/health')) { |
|
resp.writeHead(200); |
|
resp.write('health 200'); |
|
resp.end(); |
|
return; |
|
} |
|
|
|
if (url.pathname.includes(userID)) { |
|
const index = 'dist/apps/cf-page/index.html'; |
|
resp.writeHead(200, { |
|
'Content-Type': 'text/html,charset=UTF-8', |
|
}); |
|
return (0, node_fs_1.createReadStream)(index).pipe(resp); |
|
} |
|
if (req.method === 'GET' && url.pathname.startsWith('/assets')) { |
|
return (0, utils_1.serverStaticFile)(req, resp); |
|
} |
|
const basicAuth = req.headers.authorization || ''; |
|
const authStringBase64 = ((_a = basicAuth.split(' ')) === null || _a === void 0 ? void 0 : _a[1]) || ''; |
|
const authString = Buffer.from(authStringBase64, 'base64').toString('ascii'); |
|
if (authString && authString.includes(userID)) { |
|
resp.writeHead(302, { |
|
'content-type': 'text/html; charset=utf-8', |
|
Location: `./${userID}`, |
|
}); |
|
resp.end(); |
|
} |
|
else { |
|
resp.writeHead(401, { |
|
'content-type': 'text/html; charset=utf-8', |
|
'WWW-Authenticate': 'Basic', |
|
}); |
|
resp.end(); |
|
} |
|
}); |
|
const vlessWServer = new ws_1.WebSocketServer({ noServer: true }); |
|
vlessWServer.on('connection', function connection(ws, request) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
let address = ''; |
|
let portWithRandomLog = ''; |
|
try { |
|
const log = (info, event) => { |
|
console.log(`[${address}:${portWithRandomLog}] ${info}`, event || ''); |
|
}; |
|
let remoteConnection = null; |
|
let udpClientStream = null; |
|
let remoteConnectionReadyResolve; |
|
const earlyDataHeader = request.headers['sec-websocket-protocol']; |
|
const readableWebSocketStream = (0, vless_js_1.makeReadableWebSocketStream)(ws, earlyDataHeader, log); |
|
let vlessResponseHeader = null; |
|
|
|
readableWebSocketStream |
|
.pipeTo(new web_1.WritableStream({ |
|
write(chunk, controller) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
if (!Buffer.isBuffer(chunk)) { |
|
chunk = Buffer.from(chunk); |
|
} |
|
if (udpClientStream) { |
|
const writer = udpClientStream.writable.getWriter(); |
|
|
|
|
|
yield writer.write(chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.length)); |
|
writer.releaseLock(); |
|
return; |
|
} |
|
if (remoteConnection) { |
|
yield socketAsyncWrite(remoteConnection, chunk); |
|
|
|
return; |
|
} |
|
const vlessBuffer = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.length); |
|
const { hasError, message, portRemote, addressRemote, rawDataIndex, vlessVersion, isUDP, } = (0, vless_js_1.processVlessHeader)(vlessBuffer, userID); |
|
address = addressRemote || ''; |
|
portWithRandomLog = `${portRemote}--${Math.random()} ${isUDP ? 'udp ' : 'tcp '} `; |
|
if (hasError) { |
|
controller.error(`[${address}:${portWithRandomLog}] ${message} `); |
|
return; |
|
} |
|
|
|
|
|
console.log(`[${address}:${portWithRandomLog}] connecting`); |
|
vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]); |
|
const rawClientData = vlessBuffer.slice(rawDataIndex); |
|
if (isUDP) { |
|
|
|
|
|
|
|
|
|
udpClientStream = makeUDPSocketStream(portRemote, address); |
|
const writer = udpClientStream.writable.getWriter(); |
|
writer.write(rawClientData).catch((error) => console.log); |
|
writer.releaseLock(); |
|
remoteConnectionReadyResolve(udpClientStream); |
|
} |
|
else { |
|
remoteConnection = yield connect2Remote(portRemote, address, log); |
|
remoteConnection.write(new Uint8Array(rawClientData)); |
|
remoteConnectionReadyResolve(remoteConnection); |
|
} |
|
}); |
|
}, |
|
close() { |
|
|
|
|
|
|
|
|
|
console.log(`[${address}:${portWithRandomLog}] readableWebSocketStream is close`); |
|
}, |
|
abort(reason) { |
|
|
|
console.log(`[${address}:${portWithRandomLog}] readableWebSocketStream is abort`, JSON.stringify(reason)); |
|
}, |
|
})) |
|
.catch((error) => { |
|
console.error(`[${address}:${portWithRandomLog}] readableWebSocketStream pipeto has exception`, error.stack || error); |
|
|
|
|
|
|
|
|
|
}); |
|
yield new Promise((resolve) => (remoteConnectionReadyResolve = resolve)); |
|
|
|
let responseStream = udpClientStream === null || udpClientStream === void 0 ? void 0 : udpClientStream.readable; |
|
if (remoteConnection) { |
|
|
|
|
|
responseStream = stream_1.Readable.toWeb(remoteConnection, { |
|
strategy: { |
|
|
|
highWaterMark: smallRAM ? 100 : 1000, |
|
}, |
|
}); |
|
} |
|
let count = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
yield responseStream.pipeTo(new web_1.WritableStream({ |
|
start() { |
|
if (ws.readyState === ws.OPEN) { |
|
ws.send(vlessResponseHeader); |
|
} |
|
}, |
|
write(chunk, controller) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ws.readyState === ws.OPEN) { |
|
yield wsAsyncWrite(ws, chunk); |
|
} |
|
else { |
|
if (!remoteConnection.destroyed) { |
|
remoteConnection.destroy(); |
|
} |
|
} |
|
}); |
|
}, |
|
close() { |
|
console.log(`[${address}:${portWithRandomLog}] remoteConnection!.readable is close`); |
|
}, |
|
abort(reason) { |
|
(0, vless_js_1.closeWebSocket)(ws); |
|
console.error(`[${address}:${portWithRandomLog}] remoteConnection!.readable abort`, reason); |
|
}, |
|
})); |
|
} |
|
catch (error) { |
|
console.error(`[${address}:${portWithRandomLog}] processWebSocket has exception `, error.stack || error); |
|
(0, vless_js_1.closeWebSocket)(ws); |
|
} |
|
}); |
|
}); |
|
server.on('upgrade', function upgrade(request, socket, head) { |
|
const { pathname } = (0, url_1.parse)(request.url); |
|
vlessWServer.handleUpgrade(request, socket, head, function done(ws) { |
|
vlessWServer.emit('connection', ws, request); |
|
}); |
|
}); |
|
server.listen({ |
|
port: port, |
|
host: '::', |
|
|
|
}, () => { |
|
console.log(`server listen in http://127.0.0.1:${port}`); |
|
}); |
|
function connect2Remote(port, host, log) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
return new Promise((resole, reject) => { |
|
const remoteSocket = (0, node_net_1.connect)({ |
|
port: port, |
|
host: host, |
|
|
|
|
|
}, () => { |
|
log(`connected`); |
|
resole(remoteSocket); |
|
}); |
|
remoteSocket.addListener('error', () => { |
|
reject('remoteSocket has error'); |
|
}); |
|
}); |
|
}); |
|
} |
|
function socketAsyncWrite(ws, chunk) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
return new Promise((resolve, reject) => { |
|
ws.write(chunk, (error) => { |
|
if (error) { |
|
reject(error); |
|
} |
|
else { |
|
resolve(''); |
|
} |
|
}); |
|
}); |
|
}); |
|
} |
|
function wsAsyncWrite(ws, chunk) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
return new Promise((resolve, reject) => { |
|
ws.send(chunk, (error) => { |
|
if (error) { |
|
reject(error); |
|
} |
|
else { |
|
resolve(''); |
|
} |
|
}); |
|
}); |
|
}); |
|
} |
|
function makeUDPSocketStream(portRemote, address) { |
|
const udpClient = (0, node_dgram_1.createSocket)('udp4'); |
|
const transformStream = new web_1.TransformStream({ |
|
start(controller) { |
|
|
|
udpClient.on('message', (message, info) => { |
|
|
|
|
|
|
|
|
|
controller.enqueue(Buffer.concat([ |
|
new Uint8Array([(info.size >> 8) & 0xff, info.size & 0xff]), |
|
message, |
|
])); |
|
}); |
|
udpClient.on('error', (error) => { |
|
console.log('udpClient error event', error); |
|
controller.error(error); |
|
}); |
|
}, |
|
transform(chunk, controller) { |
|
return tslib_1.__awaiter(this, void 0, void 0, function* () { |
|
|
|
|
|
for (let index = 0; index < chunk.byteLength;) { |
|
const lengthBuffer = chunk.slice(index, index + 2); |
|
const udpPakcetLength = new DataView(lengthBuffer).getInt16(0); |
|
const udpData = new Uint8Array(chunk.slice(index + 2, index + 2 + udpPakcetLength)); |
|
index = index + 2 + udpPakcetLength; |
|
yield new Promise((resolve, reject) => { |
|
udpClient.send(udpData, portRemote, address, (err) => { |
|
if (err) { |
|
console.log('udps send error', err); |
|
controller.error(`Failed to send UDP packet !! ${err}`); |
|
safeCloseUDP(udpClient); |
|
} |
|
|
|
|
|
|
|
|
|
resolve(true); |
|
}); |
|
}); |
|
index = index; |
|
} |
|
|
|
|
|
|
|
}); |
|
}, |
|
flush(controller) { |
|
safeCloseUDP(udpClient); |
|
controller.terminate(); |
|
}, |
|
}); |
|
return transformStream; |
|
} |
|
function safeCloseUDP(client) { |
|
try { |
|
client.close(); |
|
} |
|
catch (error) { |
|
console.log('error close udp', error); |
|
} |
|
} |
|
|
|
})(); |
|
|
|
var __webpack_export_target__ = exports; |
|
for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; |
|
if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true }); |
|
})() |
|
; |
|
|