aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/ws.exports.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/ws.exports.js')
-rw-r--r--src/bun.js/ws.exports.js1118
1 files changed, 0 insertions, 1118 deletions
diff --git a/src/bun.js/ws.exports.js b/src/bun.js/ws.exports.js
deleted file mode 100644
index e1f042220..000000000
--- a/src/bun.js/ws.exports.js
+++ /dev/null
@@ -1,1118 +0,0 @@
-// Mocking https://github.com/websockets/ws
-// this just wraps WebSocket to look like an EventEmitter
-// without actually using an EventEmitter polyfill
-
-import EventEmitter from "events";
-import http from "http";
-
-const kBunInternals = Symbol.for("::bunternal::");
-const readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
-const encoder = new TextEncoder();
-
-const emittedWarnings = new Set();
-function emitWarning(type, message) {
- if (emittedWarnings.has(type)) return;
- emittedWarnings.add(type);
- // process.emitWarning(message); // our printing is bad
- console.warn("[bun] Warning:", message);
-}
-
-/*
- * deviations: we do not implement these events
- * - "unexpected-response"
- * - "upgrade"
- * - "ping"
- * - "pong"
- * - "redirect"
- */
-class BunWebSocket extends EventEmitter {
- static CONNECTING = 0;
- static OPEN = 1;
- static CLOSING = 2;
- static CLOSED = 3;
-
- #ws;
- #paused = false;
- #fragments = false;
- #binaryType = "nodebuffer";
- readyState = BunWebSocket.CONNECTING;
-
- constructor(url, protocols, options) {
- // deviation: we don't support anything in `options`
- super();
- let ws = (this.#ws = new WebSocket(url, protocols));
- ws.binaryType = "nodebuffer"; // bun's WebSocket supports "nodebuffer"
- ws.addEventListener("open", () => {
- this.readyState = BunWebSocket.OPEN;
- this.emit("open");
- });
- ws.addEventListener("error", err => {
- this.readyState = BunWebSocket.CLOSED;
- this.emit("error", err);
- });
- ws.addEventListener("close", ev => {
- this.readyState = BunWebSocket.CLOSED;
- this.emit("close", ev.code, ev.reason);
- });
- ws.addEventListener("message", ev => {
- const isBinary = typeof ev.data !== "string";
- if (isBinary) {
- this.emit("message", this.#fragments ? [ev.data] : ev.data, isBinary);
- } else {
- var encoded = encoder.encode(ev.data);
- if (this.#binaryType !== "arraybuffer") {
- encoded = Buffer.from(encoded.buffer, encoded.byteOffset, encoded.byteLength);
- }
- this.emit("message", this.#fragments ? [encoded] : encoded, isBinary);
- }
- });
- }
-
- on(event, listener) {
- if (
- event === "unexpected-response" ||
- event === "upgrade" ||
- event === "ping" ||
- event === "pong" ||
- event === "redirect"
- ) {
- emitWarning(event, "ws.WebSocket '" + event + "' event is not implemented in bun");
- }
- return super.on(event, listener);
- }
-
- send(data, opts, cb) {
- this.#ws.send(data, opts?.compress);
- // deviation: this should be called once the data is written, not immediately
- typeof cb === "function" && cb();
- }
-
- close(code, reason) {
- this.#ws.close(code, reason);
- }
-
- get binaryType() {
- return this.#binaryType;
- }
-
- set binaryType(value) {
- if (value) this.#ws.binaryType = value;
- }
-
- set binaryType(value) {
- if (value === "nodebuffer" || value === "arraybuffer") {
- this.#ws.binaryType = this.#binaryType = value;
- this.#fragments = false;
- } else if (value === "fragments") {
- this.#ws.binaryType = "nodebuffer";
- this.#binaryType = "fragments";
- this.#fragments = true;
- }
- }
-
- get protocol() {
- return this.#ws.protocol;
- }
-
- get extensions() {
- return this.#ws.extensions;
- }
-
- // deviation: this does not support `message` with `binaryType = "fragments"`
- addEventListener(type, listener, options) {
- this.#ws.addEventListener(type, listener, options);
- }
-
- removeEventListener(type, listener) {
- this.#ws.removeEventListener(type, listener);
- }
-
- get onopen() {
- return this.#ws.onopen;
- }
-
- set onopen(value) {
- this.#ws.onopen = value;
- }
-
- get onerror() {
- return this.#ws.onerror;
- }
-
- set onerror(value) {
- this.#ws.onerror = value;
- }
-
- get onclose() {
- return this.#ws.onclose;
- }
-
- set onclose(value) {
- this.#ws.onclose = value;
- }
-
- get onmessage() {
- return this.#ws.onmessage;
- }
-
- // deviation: this does not support `binaryType = "fragments"`
- set onmessage(value) {
- this.#ws.onmessage = value;
- }
-
- get bufferedAmount() {
- return this.#ws.bufferedAmount;
- }
-
- get isPaused() {
- return this.#paused;
- }
-
- ping(data, mask, cb) {
- if (this.readyState === BunWebSocket.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();
-
- // deviation: we don't support ping
- emitWarning("ping()", "ws.WebSocket.ping() is not implemented in bun");
- typeof cb === "function" && cb();
- }
-
- pong(data, mask, cb) {
- if (this.readyState === BunWebSocket.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();
-
- // deviation: we don't support pong
- emitWarning("pong()", "ws.WebSocket.pong() is not implemented in bun");
- typeof cb === "function" && cb();
- }
-
- pause() {
- if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) {
- return;
- }
-
- this.#paused = true;
-
- // deviation: we dont support pause()
- emitWarning("pause()", "ws.WebSocket.pause() is not implemented in bun");
- }
-
- resume() {
- if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) {
- return;
- }
-
- this.#paused = false;
-
- // deviation: we dont support resume()
- emitWarning("resume()", "ws.WebSocket.resume() is not implemented in bun");
- }
-}
-
-BunWebSocket.WebSocket = BunWebSocket;
-
-const wsKeyRegex = /^[+/0-9A-Za-z]{22}==$/;
-const wsTokenChars = [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0, // 0 - 15
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0, // 16 - 31
- 0,
- 1,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 0,
- 0,
- 1,
- 1,
- 0,
- 1,
- 1,
- 0, // 32 - 47
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0, // 48 - 63
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1, // 64 - 79
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 0,
- 0,
- 0,
- 1,
- 1, // 80 - 95
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1, // 96 - 111
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 0,
- 1,
- 0,
- 1,
- 0, // 112 - 127
-];
-
-/**
- * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
- *
- * @param {String} header The field value of the header
- * @return {Set} The subprotocol names
- * @public
- */
-function subprotocolParse(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 && wsTokenChars[code] === 1) {
- if (start === -1) start = i;
- } else if (i !== 0 && (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */) {
- 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;
-}
-
-/**
- * Emit a `'close'` event on an `EventEmitter`.
- *
- * @param {EventEmitter} server The event emitter
- * @private
- */
-function wsEmitClose(server) {
- server._state = CLOSED;
- server.emit("close");
-}
-
-function abortHandshake(response, code, message, headers) {
- message = message || http.STATUS_CODES[code];
- headers = {
- Connection: "close",
- "Content-Type": "text/html",
- "Content-Length": Buffer.byteLength(message),
- ...headers,
- };
-
- response.writeHead(code, headers);
- response.write(message);
- response.end();
-}
-
-function abortHandshakeOrEmitwsClientError(server, req, response, socket, code, message) {
- if (server.listenerCount("wsClientError")) {
- const err = new Error(message);
- Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
-
- server.emit("wsClientError", err, socket, req);
- } else {
- abortHandshake(response, code, message);
- }
-}
-
-const RUNNING = 0;
-const CLOSING = 1;
-const CLOSED = 2;
-
-class BunWebSocketMocked extends EventEmitter {
- #ws;
- #state;
- #enquedMessages = [];
- #url;
- #protocol;
- #extensions;
- #bufferedAmount = 0;
- #binaryType = "arraybuffer";
-
- #onclose;
- #onerror;
- #onmessage;
- #onopen;
-
- constructor(url, protocol, extensions, binaryType) {
- super();
- this.#ws = null;
- this.#state = 0;
- this.#url = url;
- this.#bufferedAmount = 0;
- binaryType = binaryType || "arraybuffer";
- if (binaryType !== "nodebuffer" && binaryType !== "blob" && binaryType !== "arraybuffer") {
- throw new TypeError("binaryType must be either 'blob', 'arraybuffer' or 'nodebuffer'");
- }
- this.#binaryType = binaryType;
- this.#protocol = protocol;
- this.#extensions = extensions;
-
- const message = this.#message.bind(this);
- const open = this.#open.bind(this);
- const close = this.#close.bind(this);
- const drain = this.#drain.bind(this);
-
- this[kBunInternals] = {
- message, // a message is received
- open, // a socket is opened
- close, // a socket is closed
- drain, // the socket is ready to receive more data
- };
- }
-
- #message(ws, message) {
- this.#ws = ws;
-
- if (typeof message === "string") {
- if (this.#binaryType === "arraybuffer") {
- message = encoder.encode(message).buffer;
- } else if (this.#binaryType === "blob") {
- message = new Blob([message], { type: "text/plain" });
- } else {
- // nodebuffer
- message = Buffer.from(message);
- }
- } else {
- //Buffer
- if (this.#binaryType !== "nodebuffer") {
- if (this.#binaryType === "arraybuffer") {
- message = new Uint8Array(message);
- } else if (this.#binaryType === "blob") {
- message = new Blob([message]);
- }
- }
- }
-
- this.emit("message", message);
- }
-
- #open(ws) {
- this.#ws = ws;
- this.#state = 1;
- this.emit("open", this);
- // first drain event
- this.#drain(ws);
- }
-
- #close(ws, code, reason) {
- this.#state = 3;
- this.#ws = null;
-
- this.emit("close", code, reason);
- }
-
- #drain(ws) {
- const chunk = this.#enquedMessages[0];
- if (chunk) {
- const [data, compress, cb] = chunk;
- const written = ws.send(data, compress);
- if (written == -1) {
- // backpressure wait until next drain event
- return;
- }
-
- typeof cb === "function" && cb();
-
- this.#bufferedAmount -= chunk.length;
- this.#enquedMessages.shift();
- }
- }
-
- send(data, opts, cb) {
- if (this.#state === 1) {
- const compress = opts?.compress;
- const written = this.#ws.send(data, compress);
- if (written == -1) {
- // backpressure
- this.#enquedMessages.push([data, compress, cb]);
- this.#bufferedAmount += data.length;
- return;
- }
-
- typeof cb === "function" && cb();
- } else if (this.#state === 0) {
- // not connected yet
- this.#enquedMessages.push([data, opts?.compress, cb]);
- this.#bufferedAmount += data.length;
- }
- }
-
- close(code, reason) {
- if (this.#state === 1) {
- this.#state = 2;
- this.#ws.close(code, reason);
- }
- }
- get binaryType() {
- return this.#binaryType;
- }
-
- set binaryType(type) {
- if (type !== "nodebuffer" && type !== "blob" && type !== "arraybuffer") {
- throw new TypeError("binaryType must be either 'blob', 'arraybuffer' or 'nodebuffer'");
- }
- this.#binaryType = type;
- }
-
- get readyState() {
- return readyStates[this.#state];
- }
- get url() {
- return this.#url;
- }
-
- get protocol() {
- return this.#protocol;
- }
-
- get extensions() {
- return this.#extensions;
- }
-
- get bufferedAmount() {
- return this.#bufferedAmount ?? 0;
- }
- /**
- * Set up the socket and the internal resources.
- *
- * @param {(net.Socket|tls.Socket)} socket The network socket between the
- * server and client
- * @param {Buffer} head The first packet of the upgraded stream
- * @param {Object} options Options object
- * @param {Function} [options.generateMask] The function used to generate the
- * masking key
- * @param {Number} [options.maxPayload=0] The maximum allowed message size
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
- * not to skip UTF-8 validation for text and close messages
- * @private
- */
- setSocket(socket, head, options) {
- throw new Error("Not implemented");
- }
-
- set onclose(cb) {
- if (this.#onclose) {
- this.removeListener("close", this.#onclose);
- }
- this.on("close", cb);
- this.#onclose = cb;
- }
-
- set onerror(cb) {
- if (this.#onerror) {
- this.removeListener("error", this.#onerror);
- }
- this.on("error", cb);
- this.#onerror = cb;
- }
-
- set onmessage(cb) {
- if (this.#onmessage) {
- this.removeListener("message", this.#onmessage);
- }
- this.on("message", cb);
- this.#onmessage = cb;
- }
-
- set onopen(cb) {
- if (this.#onopen) {
- this.removeListener("open", this.#onopen);
- }
- this.on("open", cb);
- this.#onopen = cb;
- }
-
- get onclose() {
- return this.#onclose;
- }
-
- get onerror() {
- return this.#onerror;
- }
-
- get onmessage() {
- return this.#onmessage;
- }
-
- get onopen() {
- return this.#onopen;
- }
-}
-
-class Server extends EventEmitter {
- _server;
- options;
- clients;
- _shouldEmitClose;
- _state;
- _removeListeners;
-
- /**
- * Create a `WebSocketServer` instance.
- *
- * @param {Object} options Configuration options
- * @param {Number} [options.backlog=511] The maximum length of the queue of
- * pending connections
- * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
- * track clients
- * @param {Function} [options.handleProtocols] A hook to handle protocols
- * @param {String} [options.host] The hostname where to bind the server
- * size
- * @param {Boolean} [options.noServer=false] Enable no server mode
- * @param {String} [options.path] Accept only connections matching this path
- * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
- * permessage-deflate
- * @param {Number} [options.port] The port where to bind the server
- * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
- * @param {Function} [options.verifyClient] A hook to reject connections
- * class to use. It must be the `WebSocket` class or class that extends it
- * @param {Function} [callback] A listener for the `listening` event
- */
- constructor(options, callback) {
- super();
-
- options = {
- maxPayload: 100 * 1024 * 1024,
- skipUTF8Validation: false,
- perMessageDeflate: false,
- handleProtocols: null,
- clientTracking: true,
- verifyClient: null,
- noServer: false,
- backlog: null, // use default (511 as implemented in net.js)
- server: null,
- host: null,
- path: null,
- port: null,
- ...options,
- };
-
- if (
- (options.port == null && !options.server && !options.noServer) ||
- (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");
- const emitListening = this.emit.bind(this, "listening");
- const emitError = this.emit.bind(this, "error");
- const doUpgrade = (req, socket, head) => {
- this.handleUpgrade(req, socket, head, emitConnection);
- };
-
- this._server.on("listening", emitListening);
- this._server.on("error", emitError);
- this._server.on("upgrade", doUpgrade);
-
- this._removeListeners = () => {
- this._server.removeListener("upgrade", doUpgrade);
- this._server.removeListener("listening", emitListening);
- this._server.removeListener("error", emitError);
- };
- }
-
- if (options.perMessageDeflate === true) options.perMessageDeflate = {};
- if (options.clientTracking) {
- this.clients = new Set();
- this._shouldEmitClose = false;
- }
-
- this.options = options;
- this._state = RUNNING;
- }
-
- /**
- * Returns the bound address, the address family name, and port of the server
- * as reported by the operating system if listening on an IP socket.
- * If the server is listening on a pipe or UNIX domain socket, the name is
- * returned as a string.
- *
- * @return {(Object|String|null)} The address of the server
- * @public
- */
- address() {
- if (this.options.noServer) {
- throw new Error('The server is operating in "noServer" mode');
- }
-
- if (!this._server) return null;
- return this._server.address();
- }
-
- /**
- * Stop the server from accepting new connections and emit the `'close'` event
- * when all existing connections are closed.
- *
- * @param {Function} [cb] A one-time listener for the `'close'` event
- * @public
- */
- close(cb) {
- if (this._state === CLOSED) {
- if (cb) {
- this.once("close", () => {
- cb(new Error("The server is not running"));
- });
- }
-
- process.nextTick(server => {
- server._state = CLOSED;
- server.emit("close");
- }, 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(server => {
- server._state = CLOSED;
- server.emit("close");
- }, this);
- } else {
- this._shouldEmitClose = true;
- }
- } else {
- process.nextTick(server => {
- server._state = CLOSED;
- server.emit("close");
- }, this);
- }
- } else {
- const server = this._server;
-
- this._removeListeners();
- this._removeListeners = this._server = null;
-
- //
- // The HTTP/S server was created internally. Close it, and rely on its
- // `'close'` event.
- //
- server.close(() => {
- this._state = CLOSED;
- this.emit("close");
- });
- }
- }
-
- /**
- * See if a given request should be handled by this server instance.
- *
- * @param {http.IncomingMessage} req Request object to inspect
- * @return {Boolean} `true` if the request is valid, else `false`
- * @public
- */
- shouldHandle(req) {
- if (this.options.path) {
- 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;
- }
-
- /**
- * Upgrade the connection to WebSocket.
- *
- * @param {Object} extensions The accepted extensions
- * @param {String} key The value of the `Sec-WebSocket-Key` header
- * @param {Set} protocols The subprotocols
- * @param {http.IncomingMessage} request The request object
- * @param {(net.Socket|tls.Socket)} socket The network socket between the
- * server and client
- * @param {Buffer} head The first packet of the upgraded stream
- * @param {Function} cb Callback
- * @throws {Error} If called more than once with the same socket
- * @private
- */
- completeUpgrade(extensions, key, protocols, request, socket, head, cb) {
- const [server, response, req] = socket[kBunInternals];
- if (this._state > RUNNING) return abortHandshake(response, 503);
-
- let protocol = "";
- if (protocols.size) {
- //
- // Optionally call external protocol selection handler.
- //
- protocol = this.options.handleProtocols
- ? this.options.handleProtocols(protocols, request)
- : protocols.values().next().value;
- }
- const ws = new BunWebSocketMocked(request.url, protocol, extensions, "nodebuffer");
-
- const headers = ["HTTP/1.1 101 Switching Protocols", "Upgrade: websocket", "Connection: Upgrade"];
- this.emit("headers", headers, request);
-
- if (
- server.upgrade(req, {
- data: ws[kBunInternals],
- })
- ) {
- response._reply(undefined);
- if (this.clients) {
- this.clients.add(ws);
- ws.on("close", () => {
- this.clients.delete(ws);
-
- if (this._shouldEmitClose && !this.clients.size) {
- process.nextTick(wsEmitClose, this);
- }
- });
- }
- cb(ws, request);
- } else {
- abortHandshake(response, 500);
- }
- }
- /**
- * Handle a HTTP Upgrade request.
- *
- * @param {http.IncomingMessage} req The request object
- * @param {(net.Socket|tls.Socket)} socket The network socket between the
- * server and client
- * @param {Buffer} head The first packet of the upgraded stream
- * @param {Function} cb Callback
- * @public
- */
- handleUpgrade(req, socket, head, cb) {
- // socket is actually fake so we use internal http_res
- const [_, response] = socket[kBunInternals];
-
- // 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, response, socket, 405, message);
- return;
- }
-
- if (req.headers.upgrade.toLowerCase() !== "websocket") {
- const message = "Invalid Upgrade header";
- abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, message);
- return;
- }
-
- if (!key || !wsKeyRegex.test(key)) {
- const message = "Missing or invalid Sec-WebSocket-Key header";
- abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, message);
- return;
- }
-
- if (version !== 8 && version !== 13) {
- const message = "Missing or invalid Sec-WebSocket-Version header";
- abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, message);
- return;
- }
-
- if (!this.shouldHandle(req)) {
- abortHandshake(response, 400);
- return;
- }
-
- const secWebSocketProtocol = req.headers["sec-websocket-protocol"];
- let protocols = new Set();
-
- if (secWebSocketProtocol !== undefined) {
- try {
- protocols = subprotocolParse(secWebSocketProtocol);
- } catch (err) {
- const message = "Invalid Sec-WebSocket-Protocol header";
- abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, message);
- return;
- }
- }
-
- // TODO: add perMessageDeflate options
-
- // const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
- const extensions = {};
-
- // if (secWebSocketExtensions !== undefined) {
- // console.log(secWebSocketExtensions);
- // 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, response, socket, 400, message);
- // return;
- // }
- // }
-
- //
- // Optionally call external client verification handler.
- //
- 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(response, code || 401, message, headers);
- }
-
- this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
- });
- return;
- }
-
- if (!this.options.verifyClient(info)) return abortHandshake(response, 401);
- }
-
- this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
- }
-}
-
-BunWebSocket.WebSocketServer = Server;
-BunWebSocket.Server = Server;
-
-Object.defineProperty(BunWebSocket, "CONNECTING", {
- enumerable: true,
- value: readyStates.indexOf("CONNECTING"),
-});
-
-Object.defineProperty(BunWebSocket.prototype, "CONNECTING", {
- enumerable: true,
- value: readyStates.indexOf("CONNECTING"),
-});
-
-Object.defineProperty(BunWebSocket, "OPEN", {
- enumerable: true,
- value: readyStates.indexOf("OPEN"),
-});
-
-Object.defineProperty(BunWebSocket.prototype, "OPEN", {
- enumerable: true,
- value: readyStates.indexOf("OPEN"),
-});
-
-Object.defineProperty(BunWebSocket, "CLOSING", {
- enumerable: true,
- value: readyStates.indexOf("CLOSING"),
-});
-
-Object.defineProperty(BunWebSocket.prototype, "CLOSING", {
- enumerable: true,
- value: readyStates.indexOf("CLOSING"),
-});
-
-Object.defineProperty(BunWebSocket, "CLOSED", {
- enumerable: true,
- value: readyStates.indexOf("CLOSED"),
-});
-
-Object.defineProperty(BunWebSocket.prototype, "CLOSED", {
- enumerable: true,
- value: readyStates.indexOf("CLOSED"),
-});
-
-class Sender {
- constructor() {
- throw new Error("Not supported yet in Bun");
- }
-}
-
-BunWebSocket.Sender = Sender;
-
-class Receiver {
- constructor() {
- throw new Error("Not supported yet in Bun");
- }
-}
-
-BunWebSocket.Receiver = Receiver;
-
-var createWebSocketStream = ws => {
- throw new Error("Not supported yet in Bun");
-};
-
-BunWebSocket.createWebSocketStream = createWebSocketStream;
-
-BunWebSocket[Symbol.for("CommonJS")] = 0;
-
-export default BunWebSocket;
-export { createWebSocketStream, Server, Receiver, Sender, BunWebSocket as WebSocket, Server as WebSocketServer };