diff options
Diffstat (limited to 'ext/websocket/01_websocket.js')
-rw-r--r-- | ext/websocket/01_websocket.js | 1017 |
1 files changed, 507 insertions, 510 deletions
diff --git a/ext/websocket/01_websocket.js b/ext/websocket/01_websocket.js index 9b7c45e70..305cf75a7 100644 --- a/ext/websocket/01_websocket.js +++ b/ext/websocket/01_websocket.js @@ -1,579 +1,576 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -"use strict"; /// <reference path="../../core/internal.d.ts" /> -((window) => { - const core = window.Deno.core; - const ops = core.ops; - const { URL } = window.__bootstrap.url; - const webidl = window.__bootstrap.webidl; - const { HTTP_TOKEN_CODE_POINT_RE } = window.__bootstrap.infra; - const { DOMException } = window.__bootstrap.domException; - const { - Event, - ErrorEvent, - CloseEvent, - MessageEvent, - defineEventHandler, - _skipInternalInit, - } = window.__bootstrap.event; - const { EventTarget } = window.__bootstrap.eventTarget; - const { Blob, BlobPrototype } = globalThis.__bootstrap.file; - const { - ArrayBufferPrototype, - ArrayBufferIsView, - ArrayPrototypeJoin, - ArrayPrototypeMap, - ArrayPrototypeSome, - DataView, - ErrorPrototypeToString, - ObjectDefineProperties, - ObjectPrototypeIsPrototypeOf, - PromisePrototypeThen, - RegExpPrototypeTest, - Set, - // TODO(lucacasonato): add SharedArrayBuffer to primordials - // SharedArrayBufferPrototype - String, - StringPrototypeEndsWith, - StringPrototypeToLowerCase, - Symbol, - SymbolIterator, - PromisePrototypeCatch, - SymbolFor, - } = window.__bootstrap.primordials; - - webidl.converters["sequence<DOMString> or DOMString"] = (V, opts) => { - // Union for (sequence<DOMString> or DOMString) - if (webidl.type(V) === "Object" && V !== null) { - if (V[SymbolIterator] !== undefined) { - return webidl.converters["sequence<DOMString>"](V, opts); - } +const core = globalThis.Deno.core; +const ops = core.ops; +import { URL } from "internal:ext/url/00_url.js"; +import * as webidl from "internal:ext/webidl/00_webidl.js"; +import { HTTP_TOKEN_CODE_POINT_RE } from "internal:ext/web/00_infra.js"; +import DOMException from "internal:ext/web/01_dom_exception.js"; +import { + _skipInternalInit, + CloseEvent, + defineEventHandler, + ErrorEvent, + Event, + EventTarget, + MessageEvent, +} from "internal:ext/web/02_event.js"; +import { Blob, BlobPrototype } from "internal:ext/web/09_file.js"; +const primordials = globalThis.__bootstrap.primordials; +const { + ArrayBufferPrototype, + ArrayBufferIsView, + ArrayPrototypeJoin, + ArrayPrototypeMap, + ArrayPrototypeSome, + DataView, + ErrorPrototypeToString, + ObjectDefineProperties, + ObjectPrototypeIsPrototypeOf, + PromisePrototypeThen, + RegExpPrototypeTest, + Set, + // TODO(lucacasonato): add SharedArrayBuffer to primordials + // SharedArrayBufferPrototype + String, + StringPrototypeEndsWith, + StringPrototypeToLowerCase, + Symbol, + SymbolIterator, + PromisePrototypeCatch, + SymbolFor, +} = primordials; + +webidl.converters["sequence<DOMString> or DOMString"] = (V, opts) => { + // Union for (sequence<DOMString> or DOMString) + if (webidl.type(V) === "Object" && V !== null) { + if (V[SymbolIterator] !== undefined) { + return webidl.converters["sequence<DOMString>"](V, opts); } - return webidl.converters.DOMString(V, opts); - }; + } + return webidl.converters.DOMString(V, opts); +}; - webidl.converters["WebSocketSend"] = (V, opts) => { - // Union for (Blob or ArrayBufferView or ArrayBuffer or USVString) - if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { - return webidl.converters["Blob"](V, opts); - } - if (typeof V === "object") { - if ( - ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) || - // deno-lint-ignore prefer-primordials - ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V) - ) { - return webidl.converters["ArrayBuffer"](V, opts); - } - if (ArrayBufferIsView(V)) { - return webidl.converters["ArrayBufferView"](V, opts); - } +webidl.converters["WebSocketSend"] = (V, opts) => { + // Union for (Blob or ArrayBufferView or ArrayBuffer or USVString) + if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { + return webidl.converters["Blob"](V, opts); + } + if (typeof V === "object") { + if ( + ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) || + // deno-lint-ignore prefer-primordials + ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V) + ) { + return webidl.converters["ArrayBuffer"](V, opts); } - return webidl.converters["USVString"](V, opts); - }; - - 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 _extensions = Symbol("[[extensions]]"); - const _protocol = Symbol("[[protocol]]"); - const _binaryType = Symbol("[[binaryType]]"); - const _bufferedAmount = Symbol("[[bufferedAmount]]"); - const _eventLoop = Symbol("[[eventLoop]]"); - - const _server = Symbol("[[server]]"); - const _idleTimeoutDuration = Symbol("[[idleTimeout]]"); - const _idleTimeoutTimeout = Symbol("[[idleTimeoutTimeout]]"); - const _serverHandleIdleTimeout = Symbol("[[serverHandleIdleTimeout]]"); - class WebSocket extends EventTarget { - [_rid]; - - [_readyState] = CONNECTING; - get readyState() { - webidl.assertBranded(this, WebSocketPrototype); - return this[_readyState]; + if (ArrayBufferIsView(V)) { + return webidl.converters["ArrayBufferView"](V, opts); } + } + return webidl.converters["USVString"](V, opts); +}; + +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 _extensions = Symbol("[[extensions]]"); +const _protocol = Symbol("[[protocol]]"); +const _binaryType = Symbol("[[binaryType]]"); +const _bufferedAmount = Symbol("[[bufferedAmount]]"); +const _eventLoop = Symbol("[[eventLoop]]"); + +const _server = Symbol("[[server]]"); +const _idleTimeoutDuration = Symbol("[[idleTimeout]]"); +const _idleTimeoutTimeout = Symbol("[[idleTimeoutTimeout]]"); +const _serverHandleIdleTimeout = Symbol("[[serverHandleIdleTimeout]]"); +class WebSocket extends EventTarget { + [_rid]; + + [_readyState] = CONNECTING; + 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 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; + } + + [_extensions] = ""; + get extensions() { + webidl.assertBranded(this, WebSocketPrototype); + return this[_extensions]; + } - [_extensions] = ""; - get extensions() { - webidl.assertBranded(this, WebSocketPrototype); - return this[_extensions]; + [_protocol] = ""; + get protocol() { + webidl.assertBranded(this, WebSocketPrototype); + return this[_protocol]; + } + + [_url] = ""; + get url() { + webidl.assertBranded(this, WebSocketPrototype); + return this[_url]; + } + + [_binaryType] = "blob"; + get binaryType() { + webidl.assertBranded(this, WebSocketPrototype); + return this[_binaryType]; + } + set binaryType(value) { + webidl.assertBranded(this, WebSocketPrototype); + value = webidl.converters.DOMString(value, { + prefix: "Failed to set 'binaryType' on 'WebSocket'", + }); + if (value === "blob" || value === "arraybuffer") { + this[_binaryType] = value; } + } + + [_bufferedAmount] = 0; + get bufferedAmount() { + webidl.assertBranded(this, WebSocketPrototype); + return this[_bufferedAmount]; + } + + constructor(url, protocols = []) { + super(); + this[webidl.brand] = webidl.brand; + const prefix = "Failed to construct 'WebSocket'"; + webidl.requiredArguments(arguments.length, 1, { + prefix, + }); + url = webidl.converters.USVString(url, { + prefix, + context: "Argument 1", + }); + protocols = webidl.converters["sequence<DOMString> or DOMString"]( + protocols, + { + prefix, + context: "Argument 2", + }, + ); - [_protocol] = ""; - get protocol() { - webidl.assertBranded(this, WebSocketPrototype); - return this[_protocol]; + let wsURL; + + try { + wsURL = new URL(url); + } catch (e) { + throw new DOMException(e.message, "SyntaxError"); } - [_url] = ""; - get url() { - webidl.assertBranded(this, WebSocketPrototype); - return this[_url]; + if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") { + throw new DOMException( + "Only ws & wss schemes are allowed in a WebSocket URL.", + "SyntaxError", + ); } - [_binaryType] = "blob"; - get binaryType() { - webidl.assertBranded(this, WebSocketPrototype); - return this[_binaryType]; + if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) { + throw new DOMException( + "Fragments are not allowed in a WebSocket URL.", + "SyntaxError", + ); } - set binaryType(value) { - webidl.assertBranded(this, WebSocketPrototype); - value = webidl.converters.DOMString(value, { - prefix: "Failed to set 'binaryType' on 'WebSocket'", - }); - if (value === "blob" || value === "arraybuffer") { - this[_binaryType] = value; - } + + this[_url] = wsURL.href; + + ops.op_ws_check_permission_and_cancel_handle( + "WebSocket.abort()", + this[_url], + false, + ); + + if (typeof protocols === "string") { + protocols = [protocols]; } - [_bufferedAmount] = 0; - get bufferedAmount() { - webidl.assertBranded(this, WebSocketPrototype); - return this[_bufferedAmount]; + if ( + protocols.length !== + new Set( + ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)), + ).size + ) { + throw new DOMException( + "Can't supply multiple times the same protocol.", + "SyntaxError", + ); } - constructor(url, protocols = []) { - super(); - this[webidl.brand] = webidl.brand; - const prefix = "Failed to construct 'WebSocket'"; - webidl.requiredArguments(arguments.length, 1, { - prefix, - }); - url = webidl.converters.USVString(url, { - prefix, - context: "Argument 1", - }); - protocols = webidl.converters["sequence<DOMString> or DOMString"]( + if ( + ArrayPrototypeSome( protocols, - { - prefix, - context: "Argument 2", - }, + (protocol) => !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol), + ) + ) { + throw new DOMException( + "Invalid protocol value.", + "SyntaxError", ); + } - let wsURL; - - try { - wsURL = new URL(url); - } catch (e) { - throw new DOMException(e.message, "SyntaxError"); - } + PromisePrototypeThen( + core.opAsync( + "op_ws_create", + "new WebSocket()", + wsURL.href, + ArrayPrototypeJoin(protocols, ", "), + ), + (create) => { + this[_rid] = create.rid; + this[_extensions] = create.extensions; + this[_protocol] = create.protocol; + + if (this[_readyState] === CLOSING) { + PromisePrototypeThen( + core.opAsync("op_ws_close", this[_rid]), + () => { + this[_readyState] = CLOSED; + + const errEvent = new ErrorEvent("error"); + this.dispatchEvent(errEvent); + + const event = new CloseEvent("close"); + this.dispatchEvent(event); + core.tryClose(this[_rid]); + }, + ); + } else { + this[_readyState] = OPEN; + const event = new Event("open"); + this.dispatchEvent(event); - if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") { - throw new DOMException( - "Only ws & wss schemes are allowed in a WebSocket URL.", - "SyntaxError", - ); - } + this[_eventLoop](); + } + }, + (err) => { + this[_readyState] = CLOSED; - if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) { - throw new DOMException( - "Fragments are not allowed in a WebSocket URL.", - "SyntaxError", + const errorEv = new ErrorEvent( + "error", + { error: err, message: ErrorPrototypeToString(err) }, ); - } - - this[_url] = wsURL.href; + this.dispatchEvent(errorEv); - ops.op_ws_check_permission_and_cancel_handle( - "WebSocket.abort()", - this[_url], - false, - ); + const closeEv = new CloseEvent("close"); + this.dispatchEvent(closeEv); + }, + ); + } - if (typeof protocols === "string") { - protocols = [protocols]; - } + send(data) { + webidl.assertBranded(this, WebSocketPrototype); + const prefix = "Failed to execute 'send' on 'WebSocket'"; - if ( - protocols.length !== - new Set( - ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)), - ).size - ) { - throw new DOMException( - "Can't supply multiple times the same protocol.", - "SyntaxError", - ); - } + webidl.requiredArguments(arguments.length, 1, { + prefix, + }); + data = webidl.converters.WebSocketSend(data, { + prefix, + context: "Argument 1", + }); - if ( - ArrayPrototypeSome( - protocols, - (protocol) => - !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol), - ) - ) { - throw new DOMException( - "Invalid protocol value.", - "SyntaxError", - ); - } + if (this[_readyState] !== OPEN) { + throw new DOMException("readyState not OPEN", "InvalidStateError"); + } + const sendTypedArray = (ta) => { + this[_bufferedAmount] += ta.byteLength; PromisePrototypeThen( - core.opAsync( - "op_ws_create", - "new WebSocket()", - wsURL.href, - ArrayPrototypeJoin(protocols, ", "), - ), - (create) => { - this[_rid] = create.rid; - this[_extensions] = create.extensions; - this[_protocol] = create.protocol; - - if (this[_readyState] === CLOSING) { - PromisePrototypeThen( - core.opAsync("op_ws_close", this[_rid]), - () => { - this[_readyState] = CLOSED; - - const errEvent = new ErrorEvent("error"); - this.dispatchEvent(errEvent); - - 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](); - } + core.opAsync("op_ws_send", this[_rid], { + kind: "binary", + value: ta, + }), + () => { + this[_bufferedAmount] -= ta.byteLength; }, - (err) => { - this[_readyState] = CLOSED; - - const errorEv = new ErrorEvent( - "error", - { error: err, message: ErrorPrototypeToString(err) }, - ); - this.dispatchEvent(errorEv); + ); + }; - const closeEv = new CloseEvent("close"); - this.dispatchEvent(closeEv); + if (ObjectPrototypeIsPrototypeOf(BlobPrototype, data)) { + PromisePrototypeThen( + data.slice().arrayBuffer(), + (ab) => sendTypedArray(new DataView(ab)), + ); + } else if (ArrayBufferIsView(data)) { + sendTypedArray(data); + } else if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, data)) { + sendTypedArray(new DataView(data)); + } else { + const string = String(data); + const d = core.encode(string); + this[_bufferedAmount] += d.byteLength; + PromisePrototypeThen( + core.opAsync("op_ws_send", this[_rid], { + kind: "text", + value: string, + }), + () => { + this[_bufferedAmount] -= d.byteLength; }, ); } + } - send(data) { - webidl.assertBranded(this, WebSocketPrototype); - const prefix = "Failed to execute 'send' on 'WebSocket'"; + close(code = undefined, reason = undefined) { + webidl.assertBranded(this, WebSocketPrototype); + const prefix = "Failed to execute 'close' on 'WebSocket'"; - webidl.requiredArguments(arguments.length, 1, { - prefix, - }); - data = webidl.converters.WebSocketSend(data, { + if (code !== undefined) { + code = webidl.converters["unsigned short"](code, { prefix, + clamp: true, context: "Argument 1", }); + } - if (this[_readyState] !== OPEN) { - throw new DOMException("readyState not OPEN", "InvalidStateError"); - } - - const sendTypedArray = (ta) => { - this[_bufferedAmount] += ta.byteLength; - PromisePrototypeThen( - core.opAsync("op_ws_send", this[_rid], { - kind: "binary", - value: ta, - }), - () => { - this[_bufferedAmount] -= ta.byteLength; - }, - ); - }; + if (reason !== undefined) { + reason = webidl.converters.USVString(reason, { + prefix, + context: "Argument 2", + }); + } - if (ObjectPrototypeIsPrototypeOf(BlobPrototype, data)) { - PromisePrototypeThen( - data.slice().arrayBuffer(), - (ab) => sendTypedArray(new DataView(ab)), - ); - } else if (ArrayBufferIsView(data)) { - sendTypedArray(data); - } else if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, data)) { - sendTypedArray(new DataView(data)); - } else { - const string = String(data); - const d = core.encode(string); - this[_bufferedAmount] += d.byteLength; - PromisePrototypeThen( - core.opAsync("op_ws_send", this[_rid], { - kind: "text", - value: string, - }), - () => { - this[_bufferedAmount] -= d.byteLength; - }, + if (!this[_server]) { + 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.", + "InvalidAccessError", ); } } - 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, - clamp: true, - context: "Argument 1", - }); - } + if (reason !== undefined && core.encode(reason).byteLength > 123) { + throw new DOMException( + "The close reason may not be longer than 123 bytes.", + "SyntaxError", + ); + } - if (reason !== undefined) { - reason = webidl.converters.USVString(reason, { - prefix, - context: "Argument 2", - }); - } + if (this[_readyState] === CONNECTING) { + this[_readyState] = CLOSING; + } else if (this[_readyState] === OPEN) { + this[_readyState] = CLOSING; - if (!this[_server]) { - 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.", - "InvalidAccessError", - ); - } - } + PromisePrototypeCatch( + core.opAsync("op_ws_close", this[_rid], code, reason), + (err) => { + this[_readyState] = CLOSED; - if (reason !== undefined && core.encode(reason).byteLength > 123) { - throw new DOMException( - "The close reason may not be longer than 123 bytes.", - "SyntaxError", - ); - } + const errorEv = new ErrorEvent("error", { + error: err, + message: ErrorPrototypeToString(err), + }); + this.dispatchEvent(errorEv); - if (this[_readyState] === CONNECTING) { - this[_readyState] = CLOSING; - } else if (this[_readyState] === OPEN) { - this[_readyState] = CLOSING; - - PromisePrototypeCatch( - core.opAsync("op_ws_close", this[_rid], code, reason), - (err) => { - this[_readyState] = CLOSED; - - const errorEv = new ErrorEvent("error", { - error: err, - message: ErrorPrototypeToString(err), - }); - this.dispatchEvent(errorEv); - - const closeEv = new CloseEvent("close"); - this.dispatchEvent(closeEv); - core.tryClose(this[_rid]); - }, - ); - } + const closeEv = new CloseEvent("close"); + this.dispatchEvent(closeEv); + core.tryClose(this[_rid]); + }, + ); } + } - async [_eventLoop]() { - while (this[_readyState] !== CLOSED) { - const { kind, value } = await core.opAsync( - "op_ws_next_event", - this[_rid], - ); + async [_eventLoop]() { + while (this[_readyState] !== CLOSED) { + const { kind, value } = await core.opAsync( + "op_ws_next_event", + this[_rid], + ); + + switch (kind) { + case "string": { + this[_serverHandleIdleTimeout](); + const event = new MessageEvent("message", { + data: value, + origin: this[_url], + }); + this.dispatchEvent(event); + break; + } + case "binary": { + this[_serverHandleIdleTimeout](); + let data; - switch (kind) { - case "string": { - this[_serverHandleIdleTimeout](); - const event = new MessageEvent("message", { - data: value, - origin: this[_url], - }); - this.dispatchEvent(event); - break; + if (this.binaryType === "blob") { + data = new Blob([value]); + } else { + data = value.buffer; } - case "binary": { - this[_serverHandleIdleTimeout](); - let data; - if (this.binaryType === "blob") { - data = new Blob([value]); - } else { - data = value.buffer; + const event = new MessageEvent("message", { + data, + origin: this[_url], + [_skipInternalInit]: true, + }); + this.dispatchEvent(event); + break; + } + case "ping": { + core.opAsync("op_ws_send", this[_rid], { + kind: "pong", + }); + break; + } + case "pong": { + this[_serverHandleIdleTimeout](); + break; + } + case "closed": + case "close": { + const prevState = this[_readyState]; + this[_readyState] = CLOSED; + clearTimeout(this[_idleTimeoutTimeout]); + + if (prevState === OPEN) { + try { + await core.opAsync( + "op_ws_close", + this[_rid], + value.code, + value.reason, + ); + } catch { + // ignore failures } - - const event = new MessageEvent("message", { - data, - origin: this[_url], - [_skipInternalInit]: true, - }); - this.dispatchEvent(event); - break; - } - case "ping": { - core.opAsync("op_ws_send", this[_rid], { - kind: "pong", - }); - break; } - case "pong": { - this[_serverHandleIdleTimeout](); - break; - } - case "closed": - case "close": { - const prevState = this[_readyState]; - this[_readyState] = CLOSED; - clearTimeout(this[_idleTimeoutTimeout]); - - if (prevState === OPEN) { - try { - await core.opAsync( - "op_ws_close", - this[_rid], - value.code, - value.reason, - ); - } catch { - // ignore failures - } - } - const event = new CloseEvent("close", { - wasClean: true, - code: value.code, - reason: value.reason, - }); - this.dispatchEvent(event); - core.tryClose(this[_rid]); - break; - } - case "error": { - this[_readyState] = CLOSED; - - const errorEv = new ErrorEvent("error", { - message: value, - }); - this.dispatchEvent(errorEv); - - const closeEv = new CloseEvent("close"); - this.dispatchEvent(closeEv); - core.tryClose(this[_rid]); - break; - } + const event = new CloseEvent("close", { + wasClean: true, + code: value.code, + reason: value.reason, + }); + this.dispatchEvent(event); + core.tryClose(this[_rid]); + break; } - } - } + case "error": { + this[_readyState] = CLOSED; - [_serverHandleIdleTimeout]() { - if (this[_idleTimeoutDuration]) { - clearTimeout(this[_idleTimeoutTimeout]); - this[_idleTimeoutTimeout] = setTimeout(async () => { - if (this[_readyState] === OPEN) { - await core.opAsync("op_ws_send", this[_rid], { - kind: "ping", - }); - this[_idleTimeoutTimeout] = setTimeout(async () => { - if (this[_readyState] === OPEN) { - this[_readyState] = CLOSING; - const reason = "No response from ping frame."; - await core.opAsync("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 { - clearTimeout(this[_idleTimeoutTimeout]); - } - }, (this[_idleTimeoutDuration] / 2) * 1000); - } else { - clearTimeout(this[_idleTimeoutTimeout]); - } - }, (this[_idleTimeoutDuration] / 2) * 1000); + const errorEv = new ErrorEvent("error", { + message: value, + }); + this.dispatchEvent(errorEv); + + const closeEv = new CloseEvent("close"); + this.dispatchEvent(closeEv); + core.tryClose(this[_rid]); + break; + } } } + } - [SymbolFor("Deno.customInspect")](inspect) { - return `${this.constructor.name} ${ - inspect({ - url: this.url, - readyState: this.readyState, - extensions: this.extensions, - protocol: this.protocol, - binaryType: this.binaryType, - bufferedAmount: this.bufferedAmount, - }) - }`; + [_serverHandleIdleTimeout]() { + if (this[_idleTimeoutDuration]) { + clearTimeout(this[_idleTimeoutTimeout]); + this[_idleTimeoutTimeout] = setTimeout(async () => { + if (this[_readyState] === OPEN) { + await core.opAsync("op_ws_send", this[_rid], { + kind: "ping", + }); + this[_idleTimeoutTimeout] = setTimeout(async () => { + if (this[_readyState] === OPEN) { + this[_readyState] = CLOSING; + const reason = "No response from ping frame."; + await core.opAsync("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 { + clearTimeout(this[_idleTimeoutTimeout]); + } + }, (this[_idleTimeoutDuration] / 2) * 1000); + } else { + clearTimeout(this[_idleTimeoutTimeout]); + } + }, (this[_idleTimeoutDuration] / 2) * 1000); } } - ObjectDefineProperties(WebSocket, { - CONNECTING: { - value: 0, - }, - OPEN: { - value: 1, - }, - CLOSING: { - value: 2, - }, - CLOSED: { - value: 3, - }, - }); - - defineEventHandler(WebSocket.prototype, "message"); - defineEventHandler(WebSocket.prototype, "error"); - defineEventHandler(WebSocket.prototype, "close"); - defineEventHandler(WebSocket.prototype, "open"); - - webidl.configurePrototype(WebSocket); - const WebSocketPrototype = WebSocket.prototype; - - window.__bootstrap.webSocket = { - WebSocket, - _rid, - _readyState, - _eventLoop, - _protocol, - _server, - _idleTimeoutDuration, - _idleTimeoutTimeout, - _serverHandleIdleTimeout, - }; -})(this); + [SymbolFor("Deno.customInspect")](inspect) { + return `${this.constructor.name} ${ + inspect({ + url: this.url, + readyState: this.readyState, + extensions: this.extensions, + protocol: this.protocol, + binaryType: this.binaryType, + bufferedAmount: this.bufferedAmount, + }) + }`; + } +} + +ObjectDefineProperties(WebSocket, { + CONNECTING: { + value: 0, + }, + OPEN: { + value: 1, + }, + CLOSING: { + value: 2, + }, + CLOSED: { + value: 3, + }, +}); + +defineEventHandler(WebSocket.prototype, "message"); +defineEventHandler(WebSocket.prototype, "error"); +defineEventHandler(WebSocket.prototype, "close"); +defineEventHandler(WebSocket.prototype, "open"); + +webidl.configurePrototype(WebSocket); +const WebSocketPrototype = WebSocket.prototype; + +export { + _eventLoop, + _idleTimeoutDuration, + _idleTimeoutTimeout, + _protocol, + _readyState, + _rid, + _server, + _serverHandleIdleTimeout, + WebSocket, +}; |