/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
ext/websocket/01_websocket.js
1 049 строк
30 KB
Kenta Moriuchi
chore: make prefer-primordials lint an internal plugin (#35978)
23 июл 2026, 11:53
Не верифицирован
23 июл 2026, 11:53
5b55d08
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. /// <reference path="../../core/internal.d.ts" /> import { core, internals, primordials } from "ext:core/mod.js"; const { isAnyArrayBuffer, isArrayBuffer, internalRidSymbol, } = core; import { op_ws_check_permission_and_cancel_handle, op_ws_close, op_ws_create, op_ws_get_buffer, op_ws_get_buffer_as_string, op_ws_get_buffered_amount, op_ws_get_error, op_ws_next_event, op_ws_send_binary, op_ws_send_binary_ab, op_ws_send_ping, op_ws_send_text, } from "ext:core/ops"; const { ArrayBufferIsView, ArrayIsArray, ArrayPrototypeJoin, ArrayPrototypeMap, ArrayPrototypePush, ArrayPrototypeShift, ArrayPrototypeSome, DateNow, decodeURIComponent, Error, ErrorPrototypeToString, ObjectDefineProperties, ObjectPrototypeIsPrototypeOf, PromisePrototypeCatch, PromisePrototypeThen, RegExpPrototypeExec, SafeSet, SetPrototypeGetSize, String, StringPrototypeEndsWith, StringPrototypeToLowerCase, Symbol, SymbolFor, SymbolIterator, TypedArrayPrototypeGetByteLength, TypeError, } = primordials; const { URL } = core.loadExtScript("ext:deno_web/00_url.js"); const webidl = core.loadExtScript("ext:deno_webidl/00_webidl.js"); const { createFilteredInspectProxy } = core.loadExtScript( "ext:deno_web/01_console.js", ); const { HTTP_TOKEN_CODE_POINT_RE, byteLowerCase, forgivingBase64Encode } = core .loadExtScript( "ext:deno_web/00_infra.js", ); const { DOMException } = core.loadExtScript("ext:deno_web/01_dom_exception.js"); const { CloseEvent, defineEventHandler, dispatch, ErrorEvent, Event, EventTarget, MessageEvent, setIsTrusted, } = core.loadExtScript("ext:deno_web/02_event.js"); const { Blob, BlobPrototype } = core.loadExtScript("ext:deno_web/09_file.js"); const { getLocationHref } = core.loadExtScript("ext:deno_web/12_location.js"); const { fillHeaders, headerListFromHeaders, headersFromHeaderList, } = core.loadExtScript("ext:deno_fetch/20_headers.js"); const { HttpClientPrototype } = core.loadExtScript( "ext:deno_fetch/22_http_client.js", ); const kNodeUndiciDispatcherOptions = SymbolFor( "Deno.internal.node.undici.dispatcherOptions", ); const kNodeUndiciGlobalDispatcher = SymbolFor( "Deno.internal.node.undici.globalDispatcher", ); webidl.converters["WebSocketInit"] = webidl.createDictionaryConverter( "WebSocketInit", [ { key: "headers", converter: webidl.converters["HeadersInit"], }, { key: "protocols", converter: webidl.converters["sequence<DOMString>"], }, { key: "client", converter: webidl.converters.any }, { key: "dispatcher", converter: webidl.converters.any }, ], ); webidl.converters["WebSocketInit or sequence<DOMString> or DOMString"] = ( V, prefix, context, opts, ) => { // Union for (WebSocketInit or sequence<DOMString> or DOMString) if (V === null || V === undefined) { return webidl.converters["WebSocketInit"](V, prefix, context, opts); } if (webidl.type(V) === "Object" && V !== null) { if (V[SymbolIterator] !== undefined) { return webidl.converters["sequence<DOMString>"](V, prefix, context, opts); } return webidl.converters["WebSocketInit"](V, prefix, context, opts); } return webidl.converters.DOMString(V, prefix, context, opts); }; webidl.converters["WebSocketSend"] = (V, prefix, context, opts) => { // Union for (Blob or ArrayBufferView or ArrayBuffer or USVString) if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { return webidl.converters["Blob"](V, prefix, context, opts); } if (typeof V === "object") { if (isAnyArrayBuffer(V)) { return webidl.converters["ArrayBuffer"](V, prefix, context, opts); } if (ArrayBufferIsView(V)) { return webidl.converters["ArrayBufferView"](V, prefix, context, opts); } } return webidl.converters["USVString"](V, prefix, context, opts); }; /** role */ const SERVER = 0; const CLIENT = 1; /** state */ const CONNECTING = 0; const OPEN = 1; const CLOSING = 2; const CLOSED = 3; const _readyState = Symbol("[[readyState]]"); const _url = Symbol("[[url]]"); const _rid = Symbol("[[rid]]"); const _role = Symbol("[[role]]"); const _extensions = Symbol("[[extensions]]"); const _protocol = Symbol("[[protocol]]"); const _binaryType = Symbol("[[binaryType]]"); const _eventLoop = Symbol("[[eventLoop]]"); const _sendQueue = Symbol("[[sendQueue]]"); const _queueSend = Symbol("[[queueSend]]"); const _cancelHandle = Symbol("[[cancelHandle]]"); const _idleTimeoutDuration = Symbol("[[idleTimeout]]"); const _idleTimeoutTimeout = Symbol("[[idleTimeoutTimeout]]"); const _serverHandleIdleTimeout = Symbol("[[serverHandleIdleTimeout]]"); // Inspector Network domain instrumentation. The bridge is installed by // `ext/node/polyfills/inspector.js` on `internals.__inspectorNetwork` when // `node:inspector` is loaded; it stays null in normal runs so the cost is // one method call per WebSocket lifecycle. const _inspectorRequestId = Symbol("[[inspectorRequestId]]"); function getInspectorNetwork() { const ins = internals.__inspectorNetwork; if (ins && ins.isEnabled()) return ins; return null; } function emitWebSocketClosed(ws) { const ins = getInspectorNetwork(); const requestId = ws[_inspectorRequestId]; if (ins === null || requestId === undefined) return; try { ins.webSocketClosed({ requestId, timestamp: DateNow() / 1000, }); } catch { // never let inspector instrumentation break a real WebSocket } ws[_inspectorRequestId] = undefined; } // Opcodes per RFC 6455 / CDP `WebSocketFrame.opcode`: // 1 = text, 2 = binary. Per RFC 6455 client-to-server frames are masked, // server-to-client are not - so the `mask` flag depends on direction and // role: a CLIENT socket masks what it sends, a SERVER socket sees masked // frames coming in. function emitWebSocketFrame(ws, eventName, opcode, payloadData) { const ins = getInspectorNetwork(); const requestId = ws[_inspectorRequestId]; if (ins === null || requestId === undefined) return; const sent = eventName === "frameSent"; const mask = ws[_role] === SERVER ? !sent : sent; try { const params = { requestId, timestamp: DateNow() / 1000, response: { opcode, mask, payloadData }, }; if (sent) ins.webSocketFrameSent(params); else ins.webSocketFrameReceived(params); } catch { // never let inspector instrumentation break a real WebSocket } } // Called by ext/http's `upgradeWebSocket` after a successful handshake, so // server-accepted sockets show up in the inspector's Network panel and // the frame emitters in `_eventLoop` / `send` start firing for them. // Handshake events (`willSendHandshakeRequest`, `handshakeResponseReceived`) // are intentionally skipped here - those are client-side concepts. function installServerInspector(ws, url) { const ins = getInspectorNetwork(); if (ins === null) return; const requestId = ins.nextRequestId(); ws[_inspectorRequestId] = requestId; try { ins.webSocketCreated({ requestId, url }); } catch { // never let inspector instrumentation break a real WebSocket } } function emitWebSocketFrameError(ws, errorMessage) { const ins = getInspectorNetwork(); const requestId = ws[_inspectorRequestId]; if (ins === null || requestId === undefined) return; try { ins.webSocketFrameError({ requestId, timestamp: DateNow() / 1000, errorMessage, }); } catch { // never let inspector instrumentation break a real WebSocket } } class WebSocket extends EventTarget { constructor(url, initOrProtocols) { super(); this[webidl.brand] = webidl.brand; this[_rid] = undefined; this[_role] = undefined; this[_readyState] = CONNECTING; this[_extensions] = ""; this[_protocol] = ""; this[_url] = ""; this[_binaryType] = "blob"; this[_idleTimeoutDuration] = 0; this[_idleTimeoutTimeout] = undefined; this[_sendQueue] = []; this[_cancelHandle] = undefined; const prefix = "Failed to construct 'WebSocket'"; webidl.requiredArguments(arguments.length, 1, prefix); url = webidl.converters.USVString(url, prefix, "Argument 1"); initOrProtocols = webidl.converters ["WebSocketInit or sequence<DOMString> or DOMString"]( initOrProtocols, prefix, "Argument 2", ); let wsURL; try { wsURL = new URL(url, getLocationHref()); } catch (e) { throw new DOMException(e.message, "SyntaxError"); } if (wsURL.protocol === "http:") { wsURL.protocol = "ws:"; } else if (wsURL.protocol === "https:") { wsURL.protocol = "wss:"; } if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") { throw new DOMException( `Only ws & wss schemes are allowed in a WebSocket URL: received ${wsURL.protocol}`, "SyntaxError", ); } if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) { throw new DOMException( "Fragments are not allowed in a WebSocket URL", "SyntaxError", ); } // WHATWG WebSocket: credentials in the URL userinfo are sent as an // `Authorization: Basic` header during the handshake and then stripped // from the URL exposed via `url`. This matches browser behavior. let urlCredentials = null; if (wsURL.username !== "" || wsURL.password !== "") { urlCredentials = forgivingBase64Encode( core.encode( `${decodeURIComponent(wsURL.username)}:${ decodeURIComponent(wsURL.password) }`, ), ); wsURL.username = ""; wsURL.password = ""; } this[_url] = wsURL.href; this[_role] = CLIENT; let protocols; let headers = null; let clientRid = null; let caCerts = null; let unsafelyIgnoreCertificateErrors = false; if (typeof initOrProtocols === "string") { protocols = [initOrProtocols]; } else if (ArrayIsArray(initOrProtocols)) { protocols = initOrProtocols; } else { protocols = initOrProtocols.protocols || []; if (initOrProtocols.headers !== undefined) { headers = headersFromHeaderList([], "request"); fillHeaders(headers, initOrProtocols.headers); } // NOTE: non standard extension. This handles Deno.HttpClient parameter if (initOrProtocols.client !== undefined) { if ( initOrProtocols.client !== null && !ObjectPrototypeIsPrototypeOf( HttpClientPrototype, initOrProtocols.client, ) ) { throw webidl.makeException( TypeError, "`client` must be a Deno.HttpClient", prefix, "Argument 2", ); } clientRid = initOrProtocols.client?.[internalRidSymbol] ?? null; } let dispatcher = initOrProtocols.dispatcher; if ( dispatcher === undefined && internals[kNodeUndiciGlobalDispatcher] !== undefined ) { dispatcher = internals[kNodeUndiciGlobalDispatcher]; } if (clientRid === null && dispatcher !== undefined) { clientRid = dispatcher?.client?.[internalRidSymbol] ?? null; const dispatcherOptions = dispatcher?.[kNodeUndiciDispatcherOptions]; if (dispatcherOptions !== undefined) { caCerts = dispatcherOptions.caCerts ?? null; unsafelyIgnoreCertificateErrors = dispatcherOptions.unsafelyIgnoreCertificateErrors === true; } } } // Apply URL-derived Basic credentials. An explicit `Authorization` header // in `init.headers` takes precedence over the URL userinfo. if (urlCredentials !== null) { if (headers === null) { headers = headersFromHeaderList([], "request"); } if (headers.get("Authorization") === null) { headers.set("Authorization", `Basic ${urlCredentials}`); } } if ( protocols.length !== SetPrototypeGetSize( new SafeSet( ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)), ), ) ) { throw new DOMException( "Cannot supply the same protocol multiple times", "SyntaxError", ); } if ( ArrayPrototypeSome( protocols, (protocol) => RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, protocol) === null, ) ) { throw new DOMException( "Invalid protocol value", "SyntaxError", ); } const cancelRid = op_ws_check_permission_and_cancel_handle( "WebSocket.abort()", this[_url], true, ); this[_cancelHandle] = cancelRid; // Inspector: emit `Network.webSocketCreated` before initiating the // handshake. The op call itself reaches deep into Rust async work, so // we want the "we're attempting this URL" notification to fire even if // the handshake later fails. const inspectorNetwork = getInspectorNetwork(); if (inspectorNetwork !== null) { const requestId = inspectorNetwork.nextRequestId(); this[_inspectorRequestId] = requestId; try { inspectorNetwork.webSocketCreated({ requestId, url: this[_url], // initiator is filled in by the inspector op using V8's stack. }); } catch { // ignore } // `Network.webSocketWillSendHandshakeRequest` populates DevTools' // "Headers" panel for the request side. Tungstenite-generated headers // (Sec-WebSocket-Key, Sec-WebSocket-Version, Upgrade, Connection) are // produced in Rust and not visible here; we surface what JS knows - // user-supplied headers via `init.headers` plus the negotiated // Sec-WebSocket-Protocol. That's enough for the panel to show the // intent of the request; the response panel still gets the real // server-sent headers via `webSocketHandshakeResponseReceived`. const requestHeaders = { __proto__: null }; if (headers !== null) { const list = headerListFromHeaders(headers); for (let i = 0; i < list.length; i++) { const name = byteLowerCase(list[i][0]); const value = list[i][1]; if (requestHeaders[name] === undefined) { requestHeaders[name] = value; } else { requestHeaders[name] = requestHeaders[name] + ", " + value; } } } if (protocols.length > 0) { requestHeaders["sec-websocket-protocol"] = ArrayPrototypeJoin( protocols, ", ", ); } try { inspectorNetwork.webSocketWillSendHandshakeRequest({ requestId, timestamp: DateNow() / 1000, wallTime: DateNow() / 1000, request: { headers: requestHeaders, }, }); } catch { // ignore } } PromisePrototypeThen( op_ws_create( "new WebSocket()", wsURL.href, ArrayPrototypeJoin(protocols, ", "), cancelRid, headers ? headerListFromHeaders(headers) : null, caCerts, unsafelyIgnoreCertificateErrors, clientRid, ), (create) => { this[_rid] = create.rid; this[_extensions] = create.extensions; this[_protocol] = create.protocol; // Inspector: emit `Network.webSocketHandshakeResponseReceived` with // the real upgrade response (status, statusText, headers) returned // by the Rust op. const reqId = this[_inspectorRequestId]; if (reqId !== undefined) { const ins = getInspectorNetwork(); if (ins !== null) { const responseHeaders = { __proto__: null }; for (let i = 0; i < create.headers.length; i++) { const name = byteLowerCase(create.headers[i][0]); const value = create.headers[i][1]; if (responseHeaders[name] === undefined) { responseHeaders[name] = value; } else { // Connection, Upgrade etc. shouldn't repeat, but be defensive. responseHeaders[name] = responseHeaders[name] + ", " + value; } } try { ins.webSocketHandshakeResponseReceived({ requestId: reqId, timestamp: DateNow() / 1000, response: { status: create.status, statusText: create.statusText, headers: responseHeaders, }, }); } catch { // ignore } } } if (this[_readyState] === CLOSING) { PromisePrototypeThen( op_ws_close(this[_rid]), () => { this[_readyState] = CLOSED; const errEvent = new ErrorEvent("error"); this.dispatchEvent(errEvent); emitWebSocketClosed(this); const event = new CloseEvent("close"); this.dispatchEvent(event); core.tryClose(this[_rid]); }, ); } else { this[_readyState] = OPEN; const event = new Event("open"); this.dispatchEvent(event); this[_eventLoop](); } }, (err) => { this[_readyState] = CLOSED; const errorEv = new ErrorEvent( "error", { error: err, message: ErrorPrototypeToString(err) }, ); this.dispatchEvent(errorEv); if (this[_cancelHandle]) { core.tryClose(this[_cancelHandle]); this[_cancelHandle] = undefined; } emitWebSocketClosed(this); const closeEv = new CloseEvent("close"); this.dispatchEvent(closeEv); }, ); } get readyState() { webidl.assertBranded(this, WebSocketPrototype); return this[_readyState]; } get CONNECTING() { webidl.assertBranded(this, WebSocketPrototype); return CONNECTING; } get OPEN() { webidl.assertBranded(this, WebSocketPrototype); return OPEN; } get CLOSING() { webidl.assertBranded(this, WebSocketPrototype); return CLOSING; } get CLOSED() { webidl.assertBranded(this, WebSocketPrototype); return CLOSED; } get extensions() { webidl.assertBranded(this, WebSocketPrototype); return this[_extensions]; } get protocol() { webidl.assertBranded(this, WebSocketPrototype); return this[_protocol]; } get url() { webidl.assertBranded(this, WebSocketPrototype); return this[_url]; } get binaryType() { webidl.assertBranded(this, WebSocketPrototype); return this[_binaryType]; } set binaryType(value) { webidl.assertBranded(this, WebSocketPrototype); value = webidl.converters.DOMString( value, "Failed to set 'binaryType' on 'WebSocket'", ); if (value === "blob" || value === "arraybuffer") { this[_binaryType] = value; } } get bufferedAmount() { webidl.assertBranded(this, WebSocketPrototype); if (this[_readyState] === OPEN) { return op_ws_get_buffered_amount(this[_rid]); } else { return 0; } } send(data) { webidl.assertBranded(this, WebSocketPrototype); const prefix = "Failed to execute 'send' on 'WebSocket'"; webidl.requiredArguments(arguments.length, 1, prefix); data = webidl.converters.WebSocketSend(data, prefix, "Argument 1"); if (this[_readyState] === CONNECTING) { throw new DOMException("'readyState' not OPEN", "InvalidStateError"); } if (this[_readyState] !== OPEN) { return; } if (this[_sendQueue].length === 0) { // Fast path if the send queue is empty, for example when only synchronous // data is being sent. if (ArrayBufferIsView(data)) { op_ws_send_binary(this[_rid], data); emitWebSocketFrame(this, "frameSent", 2, data); } else if (isArrayBuffer(data)) { op_ws_send_binary_ab(this[_rid], data); emitWebSocketFrame(this, "frameSent", 2, data); } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, data)) { this[_queueSend](data); } else { const string = String(data); op_ws_send_text( this[_rid], string, ); emitWebSocketFrame(this, "frameSent", 1, string); } } else { // Slower path if the send queue is not empty, for example when sending // asynchronous data like a Blob. this[_queueSend](data); } } close(code = undefined, reason = undefined) { webidl.assertBranded(this, WebSocketPrototype); const prefix = "Failed to execute 'close' on 'WebSocket'"; if (code !== undefined) { code = webidl.converters["unsigned short"](code, prefix, "Argument 1", { clamp: true, }); } if (reason !== undefined) { reason = webidl.converters.USVString(reason, prefix, "Argument 2"); } if (this[_role] === CLIENT) { if ( code !== undefined && !(code === 1000 || (3000 <= code && code < 5000)) ) { throw new DOMException( `The close code must be either 1000 or in the range of 3000 to 4999: received ${code}`, "InvalidAccessError", ); } } if ( reason !== undefined && TypedArrayPrototypeGetByteLength(core.encode(reason)) > 123 ) { throw new DOMException( "The close reason may not be longer than 123 bytes", "SyntaxError", ); } if (this[_cancelHandle]) { // Cancel ongoing handshake. core.tryClose(this[_cancelHandle]); this[_cancelHandle] = undefined; } if (this[_readyState] === CONNECTING) { this[_readyState] = CLOSING; } else if (this[_readyState] === OPEN) { this[_readyState] = CLOSING; PromisePrototypeCatch( op_ws_close( this[_rid], code, reason, ), (err) => { this[_readyState] = CLOSED; const errorEv = new ErrorEvent("error", { error: err, message: ErrorPrototypeToString(err), }); this.dispatchEvent(errorEv); emitWebSocketClosed(this); const closeEv = new CloseEvent("close"); this.dispatchEvent(closeEv); core.tryClose(this[_rid]); }, ); } } async [_eventLoop]() { const rid = this[_rid]; while (this[_readyState] !== CLOSED) { const kind = await op_ws_next_event(rid); /* close the connection if read was cancelled, and we didn't get a close frame */ if ( (this[_readyState] == CLOSING) && kind <= 3 && this[_role] !== CLIENT ) { this[_readyState] = CLOSED; emitWebSocketClosed(this); const event = new CloseEvent("close"); this.dispatchEvent(event); core.tryClose(rid); break; } switch (kind) { case 0: { /* string */ const data = op_ws_get_buffer_as_string(rid); if (data === undefined) { break; } this[_serverHandleIdleTimeout](); emitWebSocketFrame(this, "frameReceived", 1, data); const event = new MessageEvent("message", { data, origin: this[_url], }); setIsTrusted(event, true); dispatch(this, event); break; } case 1: { /* binary */ const d = op_ws_get_buffer(rid); if (d == undefined) { break; } this[_serverHandleIdleTimeout](); // deno-lint-ignore deno-internal/prefer-primordials const buffer = d.buffer; emitWebSocketFrame(this, "frameReceived", 2, buffer); let data; if (this.binaryType === "blob") { data = new Blob([buffer]); } else { data = buffer; } const event = new MessageEvent("message", { data, origin: this[_url], }); setIsTrusted(event, true); dispatch(this, event); break; } case 2: { /* pong */ this[_serverHandleIdleTimeout](); break; } case 3: { /* error */ this[_readyState] = CLOSED; const message = op_ws_get_error(rid); emitWebSocketFrameError(this, message); const error = new Error(message); const errorEv = new ErrorEvent("error", { error, message, }); this.dispatchEvent(errorEv); emitWebSocketClosed(this); const closeEv = new CloseEvent("close"); this.dispatchEvent(closeEv); core.tryClose(rid); break; } default: { /* close */ const code = kind; const reason = code == 1005 ? "" : op_ws_get_error(rid); const prevState = this[_readyState]; this[_readyState] = CLOSED; if (this[_idleTimeoutTimeout]) { core.cancelTimer(this[_idleTimeoutTimeout]); } if (prevState === OPEN) { try { await op_ws_close( rid, code, reason, ); } catch { // ignore failures } } emitWebSocketClosed(this); const event = new CloseEvent("close", { wasClean: true, code: code, reason, }); this.dispatchEvent(event); core.tryClose(rid); break; } } } } async [_queueSend](data) { const queue = this[_sendQueue]; ArrayPrototypePush(queue, data); if (queue.length > 1) { // There is already a send in progress, so we just push to the queue // and let that task handle sending of this data. return; } while (queue.length > 0) { const data = queue[0]; if (ArrayBufferIsView(data)) { op_ws_send_binary(this[_rid], data); emitWebSocketFrame(this, "frameSent", 2, data); } else if (isArrayBuffer(data)) { op_ws_send_binary_ab(this[_rid], data); emitWebSocketFrame(this, "frameSent", 2, data); } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, data)) { // deno-lint-ignore deno-internal/prefer-primordials const ab = await data.slice().arrayBuffer(); op_ws_send_binary_ab(this[_rid], ab); emitWebSocketFrame(this, "frameSent", 2, ab); } else { const string = String(data); op_ws_send_text( this[_rid], string, ); emitWebSocketFrame(this, "frameSent", 1, string); } ArrayPrototypeShift(queue); } } [_serverHandleIdleTimeout]() { if (this[_idleTimeoutDuration]) { if (this[_idleTimeoutTimeout]) { core.cancelTimer(this[_idleTimeoutTimeout]); } this[_idleTimeoutTimeout] = core.createSystemTimer( async () => { if (this[_readyState] === OPEN) { await PromisePrototypeCatch(op_ws_send_ping(this[_rid]), () => {}); this[_idleTimeoutTimeout] = core.createSystemTimer( async () => { if (this[_readyState] === OPEN) { this[_readyState] = CLOSING; const reason = "No response from ping frame."; await PromisePrototypeCatch( op_ws_close(this[_rid], 1001, reason), () => {}, ); this[_readyState] = CLOSED; const errEvent = new ErrorEvent("error", { message: reason, }); this.dispatchEvent(errEvent); const event = new CloseEvent("close", { wasClean: false, code: 1001, reason, }); this.dispatchEvent(event); core.tryClose(this[_rid]); } else { if (this[_idleTimeoutTimeout]) { core.cancelTimer(this[_idleTimeoutTimeout]); } } }, (this[_idleTimeoutDuration] / 2) * 1000, true, ); } else { if (this[_idleTimeoutTimeout]) { core.cancelTimer(this[_idleTimeoutTimeout]); } } }, (this[_idleTimeoutDuration] / 2) * 1000, true, ); } } [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { return inspect( createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(WebSocketPrototype, this), keys: [ "url", "readyState", "extensions", "protocol", "binaryType", "bufferedAmount", "onmessage", "onerror", "onclose", "onopen", ], }), inspectOptions, ); } } ObjectDefineProperties(WebSocket, { CONNECTING: { __proto__: null, value: 0, }, OPEN: { __proto__: null, value: 1, }, CLOSING: { __proto__: null, value: 2, }, CLOSED: { __proto__: null, value: 3, }, }); defineEventHandler(WebSocket.prototype, "message"); defineEventHandler(WebSocket.prototype, "error"); defineEventHandler(WebSocket.prototype, "close"); defineEventHandler(WebSocket.prototype, "open"); webidl.configureInterface(WebSocket); const WebSocketPrototype = WebSocket.prototype; function createWebSocketBranded() { const socket = webidl.createBranded(WebSocket); socket[_rid] = undefined; socket[_role] = undefined; socket[_readyState] = CONNECTING; socket[_extensions] = ""; socket[_protocol] = ""; socket[_url] = ""; // We use ArrayBuffer for server websockets for backwards compatibility // and performance reasons. // // https://github.com/denoland/deno/issues/15340#issuecomment-1872353134 socket[_binaryType] = "arraybuffer"; socket[_idleTimeoutDuration] = 0; socket[_idleTimeoutTimeout] = undefined; socket[_sendQueue] = []; return socket; } export { _eventLoop, _idleTimeoutDuration, _idleTimeoutTimeout, _protocol, _readyState, _rid, _role, _serverHandleIdleTimeout, CLIENT, createWebSocketBranded, emitWebSocketClosed, installServerInspector, SERVER, WebSocket, };