summaryrefslogtreecommitdiffstats
path: root/g4f/Provider/npm/node_modules/undici/lib/websocket
diff options
context:
space:
mode:
authorHeiner Lohaus <hlohaus@users.noreply.github.com>2023-11-18 04:38:31 +0100
committerHeiner Lohaus <hlohaus@users.noreply.github.com>2023-11-18 04:38:31 +0100
commitcadc507fad2fee59b23d1d8e73c472c077f468fc (patch)
tree42b1c0c0ccf5e3aa7a843a3766d4d19b6a7ade8e /g4f/Provider/npm/node_modules/undici/lib/websocket
parentImprove providers (diff)
downloadgpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.tar
gpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.tar.gz
gpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.tar.bz2
gpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.tar.lz
gpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.tar.xz
gpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.tar.zst
gpt4free-cadc507fad2fee59b23d1d8e73c472c077f468fc.zip
Diffstat (limited to 'g4f/Provider/npm/node_modules/undici/lib/websocket')
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/connection.js291
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/constants.js51
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/events.js303
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/frame.js73
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/receiver.js344
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/symbols.js12
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/util.js200
-rw-r--r--g4f/Provider/npm/node_modules/undici/lib/websocket/websocket.js641
8 files changed, 0 insertions, 1915 deletions
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/connection.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/connection.js
deleted file mode 100644
index e0fa6972..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/connection.js
+++ /dev/null
@@ -1,291 +0,0 @@
-'use strict'
-
-const diagnosticsChannel = require('diagnostics_channel')
-const { uid, states } = require('./constants')
-const {
- kReadyState,
- kSentClose,
- kByteParser,
- kReceivedClose
-} = require('./symbols')
-const { fireEvent, failWebsocketConnection } = require('./util')
-const { CloseEvent } = require('./events')
-const { makeRequest } = require('../fetch/request')
-const { fetching } = require('../fetch/index')
-const { Headers } = require('../fetch/headers')
-const { getGlobalDispatcher } = require('../global')
-const { kHeadersList } = require('../core/symbols')
-
-const channels = {}
-channels.open = diagnosticsChannel.channel('undici:websocket:open')
-channels.close = diagnosticsChannel.channel('undici:websocket:close')
-channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error')
-
-/** @type {import('crypto')} */
-let crypto
-try {
- crypto = require('crypto')
-} catch {
-
-}
-
-/**
- * @see https://websockets.spec.whatwg.org/#concept-websocket-establish
- * @param {URL} url
- * @param {string|string[]} protocols
- * @param {import('./websocket').WebSocket} ws
- * @param {(response: any) => void} onEstablish
- * @param {Partial<import('../../types/websocket').WebSocketInit>} options
- */
-function establishWebSocketConnection (url, protocols, ws, onEstablish, options) {
- // 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s
- // scheme is "ws", and to "https" otherwise.
- const requestURL = url
-
- requestURL.protocol = url.protocol === 'ws:' ? 'http:' : 'https:'
-
- // 2. Let request be a new request, whose URL is requestURL, client is client,
- // service-workers mode is "none", referrer is "no-referrer", mode is
- // "websocket", credentials mode is "include", cache mode is "no-store" ,
- // and redirect mode is "error".
- const request = makeRequest({
- urlList: [requestURL],
- serviceWorkers: 'none',
- referrer: 'no-referrer',
- mode: 'websocket',
- credentials: 'include',
- cache: 'no-store',
- redirect: 'error'
- })
-
- // Note: undici extension, allow setting custom headers.
- if (options.headers) {
- const headersList = new Headers(options.headers)[kHeadersList]
-
- request.headersList = headersList
- }
-
- // 3. Append (`Upgrade`, `websocket`) to request’s header list.
- // 4. Append (`Connection`, `Upgrade`) to request’s header list.
- // Note: both of these are handled by undici currently.
- // https://github.com/nodejs/undici/blob/68c269c4144c446f3f1220951338daef4a6b5ec4/lib/client.js#L1397
-
- // 5. Let keyValue be a nonce consisting of a randomly selected
- // 16-byte value that has been forgiving-base64-encoded and
- // isomorphic encoded.
- const keyValue = crypto.randomBytes(16).toString('base64')
-
- // 6. Append (`Sec-WebSocket-Key`, keyValue) to request’s
- // header list.
- request.headersList.append('sec-websocket-key', keyValue)
-
- // 7. Append (`Sec-WebSocket-Version`, `13`) to request’s
- // header list.
- request.headersList.append('sec-websocket-version', '13')
-
- // 8. For each protocol in protocols, combine
- // (`Sec-WebSocket-Protocol`, protocol) in request’s header
- // list.
- for (const protocol of protocols) {
- request.headersList.append('sec-websocket-protocol', protocol)
- }
-
- // 9. Let permessageDeflate be a user-agent defined
- // "permessage-deflate" extension header value.
- // https://github.com/mozilla/gecko-dev/blob/ce78234f5e653a5d3916813ff990f053510227bc/netwerk/protocol/websocket/WebSocketChannel.cpp#L2673
- // TODO: enable once permessage-deflate is supported
- const permessageDeflate = '' // 'permessage-deflate; 15'
-
- // 10. Append (`Sec-WebSocket-Extensions`, permessageDeflate) to
- // request’s header list.
- // request.headersList.append('sec-websocket-extensions', permessageDeflate)
-
- // 11. Fetch request with useParallelQueue set to true, and
- // processResponse given response being these steps:
- const controller = fetching({
- request,
- useParallelQueue: true,
- dispatcher: options.dispatcher ?? getGlobalDispatcher(),
- processResponse (response) {
- // 1. If response is a network error or its status is not 101,
- // fail the WebSocket connection.
- if (response.type === 'error' || response.status !== 101) {
- failWebsocketConnection(ws, 'Received network error or non-101 status code.')
- return
- }
-
- // 2. If protocols is not the empty list and extracting header
- // list values given `Sec-WebSocket-Protocol` and response’s
- // header list results in null, failure, or the empty byte
- // sequence, then fail the WebSocket connection.
- if (protocols.length !== 0 && !response.headersList.get('Sec-WebSocket-Protocol')) {
- failWebsocketConnection(ws, 'Server did not respond with sent protocols.')
- return
- }
-
- // 3. Follow the requirements stated step 2 to step 6, inclusive,
- // of the last set of steps in section 4.1 of The WebSocket
- // Protocol to validate response. This either results in fail
- // the WebSocket connection or the WebSocket connection is
- // established.
-
- // 2. If the response lacks an |Upgrade| header field or the |Upgrade|
- // header field contains a value that is not an ASCII case-
- // insensitive match for the value "websocket", the client MUST
- // _Fail the WebSocket Connection_.
- if (response.headersList.get('Upgrade')?.toLowerCase() !== 'websocket') {
- failWebsocketConnection(ws, 'Server did not set Upgrade header to "websocket".')
- return
- }
-
- // 3. If the response lacks a |Connection| header field or the
- // |Connection| header field doesn't contain a token that is an
- // ASCII case-insensitive match for the value "Upgrade", the client
- // MUST _Fail the WebSocket Connection_.
- if (response.headersList.get('Connection')?.toLowerCase() !== 'upgrade') {
- failWebsocketConnection(ws, 'Server did not set Connection header to "upgrade".')
- return
- }
-
- // 4. If the response lacks a |Sec-WebSocket-Accept| header field or
- // the |Sec-WebSocket-Accept| contains a value other than the
- // base64-encoded SHA-1 of the concatenation of the |Sec-WebSocket-
- // Key| (as a string, not base64-decoded) with the string "258EAFA5-
- // E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and
- // trailing whitespace, the client MUST _Fail the WebSocket
- // Connection_.
- const secWSAccept = response.headersList.get('Sec-WebSocket-Accept')
- const digest = crypto.createHash('sha1').update(keyValue + uid).digest('base64')
- if (secWSAccept !== digest) {
- failWebsocketConnection(ws, 'Incorrect hash received in Sec-WebSocket-Accept header.')
- return
- }
-
- // 5. If the response includes a |Sec-WebSocket-Extensions| header
- // field and this header field indicates the use of an extension
- // that was not present in the client's handshake (the server has
- // indicated an extension not requested by the client), the client
- // MUST _Fail the WebSocket Connection_. (The parsing of this
- // header field to determine which extensions are requested is
- // discussed in Section 9.1.)
- const secExtension = response.headersList.get('Sec-WebSocket-Extensions')
-
- if (secExtension !== null && secExtension !== permessageDeflate) {
- failWebsocketConnection(ws, 'Received different permessage-deflate than the one set.')
- return
- }
-
- // 6. If the response includes a |Sec-WebSocket-Protocol| header field
- // and this header field indicates the use of a subprotocol that was
- // not present in the client's handshake (the server has indicated a
- // subprotocol not requested by the client), the client MUST _Fail
- // the WebSocket Connection_.
- const secProtocol = response.headersList.get('Sec-WebSocket-Protocol')
-
- if (secProtocol !== null && secProtocol !== request.headersList.get('Sec-WebSocket-Protocol')) {
- failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
- return
- }
-
- response.socket.on('data', onSocketData)
- response.socket.on('close', onSocketClose)
- response.socket.on('error', onSocketError)
-
- if (channels.open.hasSubscribers) {
- channels.open.publish({
- address: response.socket.address(),
- protocol: secProtocol,
- extensions: secExtension
- })
- }
-
- onEstablish(response)
- }
- })
-
- return controller
-}
-
-/**
- * @param {Buffer} chunk
- */
-function onSocketData (chunk) {
- if (!this.ws[kByteParser].write(chunk)) {
- this.pause()
- }
-}
-
-/**
- * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
- * @see https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.4
- */
-function onSocketClose () {
- const { ws } = this
-
- // If the TCP connection was closed after the
- // WebSocket closing handshake was completed, the WebSocket connection
- // is said to have been closed _cleanly_.
- const wasClean = ws[kSentClose] && ws[kReceivedClose]
-
- let code = 1005
- let reason = ''
-
- const result = ws[kByteParser].closingInfo
-
- if (result) {
- code = result.code ?? 1005
- reason = result.reason
- } else if (!ws[kSentClose]) {
- // If _The WebSocket
- // Connection is Closed_ and no Close control frame was received by the
- // endpoint (such as could occur if the underlying transport connection
- // is lost), _The WebSocket Connection Close Code_ is considered to be
- // 1006.
- code = 1006
- }
-
- // 1. Change the ready state to CLOSED (3).
- ws[kReadyState] = states.CLOSED
-
- // 2. If the user agent was required to fail the WebSocket
- // connection, or if the WebSocket connection was closed
- // after being flagged as full, fire an event named error
- // at the WebSocket object.
- // TODO
-
- // 3. Fire an event named close at the WebSocket object,
- // using CloseEvent, with the wasClean attribute
- // initialized to true if the connection closed cleanly
- // and false otherwise, the code attribute initialized to
- // the WebSocket connection close code, and the reason
- // attribute initialized to the result of applying UTF-8
- // decode without BOM to the WebSocket connection close
- // reason.
- fireEvent('close', ws, CloseEvent, {
- wasClean, code, reason
- })
-
- if (channels.close.hasSubscribers) {
- channels.close.publish({
- websocket: ws,
- code,
- reason
- })
- }
-}
-
-function onSocketError (error) {
- const { ws } = this
-
- ws[kReadyState] = states.CLOSING
-
- if (channels.socketError.hasSubscribers) {
- channels.socketError.publish(error)
- }
-
- this.destroy()
-}
-
-module.exports = {
- establishWebSocketConnection
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/constants.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/constants.js
deleted file mode 100644
index 406b8e3e..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/constants.js
+++ /dev/null
@@ -1,51 +0,0 @@
-'use strict'
-
-// This is a Globally Unique Identifier unique used
-// to validate that the endpoint accepts websocket
-// connections.
-// See https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3
-const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
-
-/** @type {PropertyDescriptor} */
-const staticPropertyDescriptors = {
- enumerable: true,
- writable: false,
- configurable: false
-}
-
-const states = {
- CONNECTING: 0,
- OPEN: 1,
- CLOSING: 2,
- CLOSED: 3
-}
-
-const opcodes = {
- CONTINUATION: 0x0,
- TEXT: 0x1,
- BINARY: 0x2,
- CLOSE: 0x8,
- PING: 0x9,
- PONG: 0xA
-}
-
-const maxUnsigned16Bit = 2 ** 16 - 1 // 65535
-
-const parserStates = {
- INFO: 0,
- PAYLOADLENGTH_16: 2,
- PAYLOADLENGTH_64: 3,
- READ_DATA: 4
-}
-
-const emptyBuffer = Buffer.allocUnsafe(0)
-
-module.exports = {
- uid,
- staticPropertyDescriptors,
- states,
- opcodes,
- maxUnsigned16Bit,
- parserStates,
- emptyBuffer
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/events.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/events.js
deleted file mode 100644
index 621a2263..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/events.js
+++ /dev/null
@@ -1,303 +0,0 @@
-'use strict'
-
-const { webidl } = require('../fetch/webidl')
-const { kEnumerableProperty } = require('../core/util')
-const { MessagePort } = require('worker_threads')
-
-/**
- * @see https://html.spec.whatwg.org/multipage/comms.html#messageevent
- */
-class MessageEvent extends Event {
- #eventInit
-
- constructor (type, eventInitDict = {}) {
- webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent constructor' })
-
- type = webidl.converters.DOMString(type)
- eventInitDict = webidl.converters.MessageEventInit(eventInitDict)
-
- super(type, eventInitDict)
-
- this.#eventInit = eventInitDict
- }
-
- get data () {
- webidl.brandCheck(this, MessageEvent)
-
- return this.#eventInit.data
- }
-
- get origin () {
- webidl.brandCheck(this, MessageEvent)
-
- return this.#eventInit.origin
- }
-
- get lastEventId () {
- webidl.brandCheck(this, MessageEvent)
-
- return this.#eventInit.lastEventId
- }
-
- get source () {
- webidl.brandCheck(this, MessageEvent)
-
- return this.#eventInit.source
- }
-
- get ports () {
- webidl.brandCheck(this, MessageEvent)
-
- if (!Object.isFrozen(this.#eventInit.ports)) {
- Object.freeze(this.#eventInit.ports)
- }
-
- return this.#eventInit.ports
- }
-
- initMessageEvent (
- type,
- bubbles = false,
- cancelable = false,
- data = null,
- origin = '',
- lastEventId = '',
- source = null,
- ports = []
- ) {
- webidl.brandCheck(this, MessageEvent)
-
- webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent.initMessageEvent' })
-
- return new MessageEvent(type, {
- bubbles, cancelable, data, origin, lastEventId, source, ports
- })
- }
-}
-
-/**
- * @see https://websockets.spec.whatwg.org/#the-closeevent-interface
- */
-class CloseEvent extends Event {
- #eventInit
-
- constructor (type, eventInitDict = {}) {
- webidl.argumentLengthCheck(arguments, 1, { header: 'CloseEvent constructor' })
-
- type = webidl.converters.DOMString(type)
- eventInitDict = webidl.converters.CloseEventInit(eventInitDict)
-
- super(type, eventInitDict)
-
- this.#eventInit = eventInitDict
- }
-
- get wasClean () {
- webidl.brandCheck(this, CloseEvent)
-
- return this.#eventInit.wasClean
- }
-
- get code () {
- webidl.brandCheck(this, CloseEvent)
-
- return this.#eventInit.code
- }
-
- get reason () {
- webidl.brandCheck(this, CloseEvent)
-
- return this.#eventInit.reason
- }
-}
-
-// https://html.spec.whatwg.org/multipage/webappapis.html#the-errorevent-interface
-class ErrorEvent extends Event {
- #eventInit
-
- constructor (type, eventInitDict) {
- webidl.argumentLengthCheck(arguments, 1, { header: 'ErrorEvent constructor' })
-
- super(type, eventInitDict)
-
- type = webidl.converters.DOMString(type)
- eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {})
-
- this.#eventInit = eventInitDict
- }
-
- get message () {
- webidl.brandCheck(this, ErrorEvent)
-
- return this.#eventInit.message
- }
-
- get filename () {
- webidl.brandCheck(this, ErrorEvent)
-
- return this.#eventInit.filename
- }
-
- get lineno () {
- webidl.brandCheck(this, ErrorEvent)
-
- return this.#eventInit.lineno
- }
-
- get colno () {
- webidl.brandCheck(this, ErrorEvent)
-
- return this.#eventInit.colno
- }
-
- get error () {
- webidl.brandCheck(this, ErrorEvent)
-
- return this.#eventInit.error
- }
-}
-
-Object.defineProperties(MessageEvent.prototype, {
- [Symbol.toStringTag]: {
- value: 'MessageEvent',
- configurable: true
- },
- data: kEnumerableProperty,
- origin: kEnumerableProperty,
- lastEventId: kEnumerableProperty,
- source: kEnumerableProperty,
- ports: kEnumerableProperty,
- initMessageEvent: kEnumerableProperty
-})
-
-Object.defineProperties(CloseEvent.prototype, {
- [Symbol.toStringTag]: {
- value: 'CloseEvent',
- configurable: true
- },
- reason: kEnumerableProperty,
- code: kEnumerableProperty,
- wasClean: kEnumerableProperty
-})
-
-Object.defineProperties(ErrorEvent.prototype, {
- [Symbol.toStringTag]: {
- value: 'ErrorEvent',
- configurable: true
- },
- message: kEnumerableProperty,
- filename: kEnumerableProperty,
- lineno: kEnumerableProperty,
- colno: kEnumerableProperty,
- error: kEnumerableProperty
-})
-
-webidl.converters.MessagePort = webidl.interfaceConverter(MessagePort)
-
-webidl.converters['sequence<MessagePort>'] = webidl.sequenceConverter(
- webidl.converters.MessagePort
-)
-
-const eventInit = [
- {
- key: 'bubbles',
- converter: webidl.converters.boolean,
- defaultValue: false
- },
- {
- key: 'cancelable',
- converter: webidl.converters.boolean,
- defaultValue: false
- },
- {
- key: 'composed',
- converter: webidl.converters.boolean,
- defaultValue: false
- }
-]
-
-webidl.converters.MessageEventInit = webidl.dictionaryConverter([
- ...eventInit,
- {
- key: 'data',
- converter: webidl.converters.any,
- defaultValue: null
- },
- {
- key: 'origin',
- converter: webidl.converters.USVString,
- defaultValue: ''
- },
- {
- key: 'lastEventId',
- converter: webidl.converters.DOMString,
- defaultValue: ''
- },
- {
- key: 'source',
- // Node doesn't implement WindowProxy or ServiceWorker, so the only
- // valid value for source is a MessagePort.
- converter: webidl.nullableConverter(webidl.converters.MessagePort),
- defaultValue: null
- },
- {
- key: 'ports',
- converter: webidl.converters['sequence<MessagePort>'],
- get defaultValue () {
- return []
- }
- }
-])
-
-webidl.converters.CloseEventInit = webidl.dictionaryConverter([
- ...eventInit,
- {
- key: 'wasClean',
- converter: webidl.converters.boolean,
- defaultValue: false
- },
- {
- key: 'code',
- converter: webidl.converters['unsigned short'],
- defaultValue: 0
- },
- {
- key: 'reason',
- converter: webidl.converters.USVString,
- defaultValue: ''
- }
-])
-
-webidl.converters.ErrorEventInit = webidl.dictionaryConverter([
- ...eventInit,
- {
- key: 'message',
- converter: webidl.converters.DOMString,
- defaultValue: ''
- },
- {
- key: 'filename',
- converter: webidl.converters.USVString,
- defaultValue: ''
- },
- {
- key: 'lineno',
- converter: webidl.converters['unsigned long'],
- defaultValue: 0
- },
- {
- key: 'colno',
- converter: webidl.converters['unsigned long'],
- defaultValue: 0
- },
- {
- key: 'error',
- converter: webidl.converters.any
- }
-])
-
-module.exports = {
- MessageEvent,
- CloseEvent,
- ErrorEvent
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/frame.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/frame.js
deleted file mode 100644
index d867ad11..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/frame.js
+++ /dev/null
@@ -1,73 +0,0 @@
-'use strict'
-
-const { maxUnsigned16Bit } = require('./constants')
-
-/** @type {import('crypto')} */
-let crypto
-try {
- crypto = require('crypto')
-} catch {
-
-}
-
-class WebsocketFrameSend {
- /**
- * @param {Buffer|undefined} data
- */
- constructor (data) {
- this.frameData = data
- this.maskKey = crypto.randomBytes(4)
- }
-
- createFrame (opcode) {
- const bodyLength = this.frameData?.byteLength ?? 0
-
- /** @type {number} */
- let payloadLength = bodyLength // 0-125
- let offset = 6
-
- if (bodyLength > maxUnsigned16Bit) {
- offset += 8 // payload length is next 8 bytes
- payloadLength = 127
- } else if (bodyLength > 125) {
- offset += 2 // payload length is next 2 bytes
- payloadLength = 126
- }
-
- const buffer = Buffer.allocUnsafe(bodyLength + offset)
-
- // Clear first 2 bytes, everything else is overwritten
- buffer[0] = buffer[1] = 0
- buffer[0] |= 0x80 // FIN
- buffer[0] = (buffer[0] & 0xF0) + opcode // opcode
-
- /*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */
- buffer[offset - 4] = this.maskKey[0]
- buffer[offset - 3] = this.maskKey[1]
- buffer[offset - 2] = this.maskKey[2]
- buffer[offset - 1] = this.maskKey[3]
-
- buffer[1] = payloadLength
-
- if (payloadLength === 126) {
- buffer.writeUInt16BE(bodyLength, 2)
- } else if (payloadLength === 127) {
- // Clear extended payload length
- buffer[2] = buffer[3] = 0
- buffer.writeUIntBE(bodyLength, 4, 6)
- }
-
- buffer[1] |= 0x80 // MASK
-
- // mask body
- for (let i = 0; i < bodyLength; i++) {
- buffer[offset + i] = this.frameData[i] ^ this.maskKey[i % 4]
- }
-
- return buffer
- }
-}
-
-module.exports = {
- WebsocketFrameSend
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/receiver.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/receiver.js
deleted file mode 100644
index bdd2031b..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/receiver.js
+++ /dev/null
@@ -1,344 +0,0 @@
-'use strict'
-
-const { Writable } = require('stream')
-const diagnosticsChannel = require('diagnostics_channel')
-const { parserStates, opcodes, states, emptyBuffer } = require('./constants')
-const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols')
-const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = require('./util')
-const { WebsocketFrameSend } = require('./frame')
-
-// This code was influenced by ws released under the MIT license.
-// Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
-// Copyright (c) 2013 Arnout Kazemier and contributors
-// Copyright (c) 2016 Luigi Pinca and contributors
-
-const channels = {}
-channels.ping = diagnosticsChannel.channel('undici:websocket:ping')
-channels.pong = diagnosticsChannel.channel('undici:websocket:pong')
-
-class ByteParser extends Writable {
- #buffers = []
- #byteOffset = 0
-
- #state = parserStates.INFO
-
- #info = {}
- #fragments = []
-
- constructor (ws) {
- super()
-
- this.ws = ws
- }
-
- /**
- * @param {Buffer} chunk
- * @param {() => void} callback
- */
- _write (chunk, _, callback) {
- this.#buffers.push(chunk)
- this.#byteOffset += chunk.length
-
- this.run(callback)
- }
-
- /**
- * Runs whenever a new chunk is received.
- * Callback is called whenever there are no more chunks buffering,
- * or not enough bytes are buffered to parse.
- */
- run (callback) {
- while (true) {
- if (this.#state === parserStates.INFO) {
- // If there aren't enough bytes to parse the payload length, etc.
- if (this.#byteOffset < 2) {
- return callback()
- }
-
- const buffer = this.consume(2)
-
- this.#info.fin = (buffer[0] & 0x80) !== 0
- this.#info.opcode = buffer[0] & 0x0F
-
- // If we receive a fragmented message, we use the type of the first
- // frame to parse the full message as binary/text, when it's terminated
- this.#info.originalOpcode ??= this.#info.opcode
-
- this.#info.fragmented = !this.#info.fin && this.#info.opcode !== opcodes.CONTINUATION
-
- if (this.#info.fragmented && this.#info.opcode !== opcodes.BINARY && this.#info.opcode !== opcodes.TEXT) {
- // Only text and binary frames can be fragmented
- failWebsocketConnection(this.ws, 'Invalid frame type was fragmented.')
- return
- }
-
- const payloadLength = buffer[1] & 0x7F
-
- if (payloadLength <= 125) {
- this.#info.payloadLength = payloadLength
- this.#state = parserStates.READ_DATA
- } else if (payloadLength === 126) {
- this.#state = parserStates.PAYLOADLENGTH_16
- } else if (payloadLength === 127) {
- this.#state = parserStates.PAYLOADLENGTH_64
- }
-
- if (this.#info.fragmented && payloadLength > 125) {
- // A fragmented frame can't be fragmented itself
- failWebsocketConnection(this.ws, 'Fragmented frame exceeded 125 bytes.')
- return
- } else if (
- (this.#info.opcode === opcodes.PING ||
- this.#info.opcode === opcodes.PONG ||
- this.#info.opcode === opcodes.CLOSE) &&
- payloadLength > 125
- ) {
- // Control frames can have a payload length of 125 bytes MAX
- failWebsocketConnection(this.ws, 'Payload length for control frame exceeded 125 bytes.')
- return
- } else if (this.#info.opcode === opcodes.CLOSE) {
- if (payloadLength === 1) {
- failWebsocketConnection(this.ws, 'Received close frame with a 1-byte body.')
- return
- }
-
- const body = this.consume(payloadLength)
-
- this.#info.closeInfo = this.parseCloseBody(false, body)
-
- if (!this.ws[kSentClose]) {
- // If an endpoint receives a Close frame and did not previously send a
- // Close frame, the endpoint MUST send a Close frame in response. (When
- // sending a Close frame in response, the endpoint typically echos the
- // status code it received.)
- const body = Buffer.allocUnsafe(2)
- body.writeUInt16BE(this.#info.closeInfo.code, 0)
- const closeFrame = new WebsocketFrameSend(body)
-
- this.ws[kResponse].socket.write(
- closeFrame.createFrame(opcodes.CLOSE),
- (err) => {
- if (!err) {
- this.ws[kSentClose] = true
- }
- }
- )
- }
-
- // Upon either sending or receiving a Close control frame, it is said
- // that _The WebSocket Closing Handshake is Started_ and that the
- // WebSocket connection is in the CLOSING state.
- this.ws[kReadyState] = states.CLOSING
- this.ws[kReceivedClose] = true
-
- this.end()
-
- return
- } else if (this.#info.opcode === opcodes.PING) {
- // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
- // response, unless it already received a Close frame.
- // A Pong frame sent in response to a Ping frame must have identical
- // "Application data"
-
- const body = this.consume(payloadLength)
-
- if (!this.ws[kReceivedClose]) {
- const frame = new WebsocketFrameSend(body)
-
- this.ws[kResponse].socket.write(frame.createFrame(opcodes.PONG))
-
- if (channels.ping.hasSubscribers) {
- channels.ping.publish({
- payload: body
- })
- }
- }
-
- this.#state = parserStates.INFO
-
- if (this.#byteOffset > 0) {
- continue
- } else {
- callback()
- return
- }
- } else if (this.#info.opcode === opcodes.PONG) {
- // A Pong frame MAY be sent unsolicited. This serves as a
- // unidirectional heartbeat. A response to an unsolicited Pong frame is
- // not expected.
-
- const body = this.consume(payloadLength)
-
- if (channels.pong.hasSubscribers) {
- channels.pong.publish({
- payload: body
- })
- }
-
- if (this.#byteOffset > 0) {
- continue
- } else {
- callback()
- return
- }
- }
- } else if (this.#state === parserStates.PAYLOADLENGTH_16) {
- if (this.#byteOffset < 2) {
- return callback()
- }
-
- const buffer = this.consume(2)
-
- this.#info.payloadLength = buffer.readUInt16BE(0)
- this.#state = parserStates.READ_DATA
- } else if (this.#state === parserStates.PAYLOADLENGTH_64) {
- if (this.#byteOffset < 8) {
- return callback()
- }
-
- const buffer = this.consume(8)
- const upper = buffer.readUInt32BE(0)
-
- // 2^31 is the maxinimum bytes an arraybuffer can contain
- // on 32-bit systems. Although, on 64-bit systems, this is
- // 2^53-1 bytes.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length
- // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275
- // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e
- if (upper > 2 ** 31 - 1) {
- failWebsocketConnection(this.ws, 'Received payload length > 2^31 bytes.')
- return
- }
-
- const lower = buffer.readUInt32BE(4)
-
- this.#info.payloadLength = (upper << 8) + lower
- this.#state = parserStates.READ_DATA
- } else if (this.#state === parserStates.READ_DATA) {
- if (this.#byteOffset < this.#info.payloadLength) {
- // If there is still more data in this chunk that needs to be read
- return callback()
- } else if (this.#byteOffset >= this.#info.payloadLength) {
- // If the server sent multiple frames in a single chunk
-
- const body = this.consume(this.#info.payloadLength)
-
- this.#fragments.push(body)
-
- // If the frame is unfragmented, or a fragmented frame was terminated,
- // a message was received
- if (!this.#info.fragmented || (this.#info.fin && this.#info.opcode === opcodes.CONTINUATION)) {
- const fullMessage = Buffer.concat(this.#fragments)
-
- websocketMessageReceived(this.ws, this.#info.originalOpcode, fullMessage)
-
- this.#info = {}
- this.#fragments.length = 0
- }
-
- this.#state = parserStates.INFO
- }
- }
-
- if (this.#byteOffset > 0) {
- continue
- } else {
- callback()
- break
- }
- }
- }
-
- /**
- * Take n bytes from the buffered Buffers
- * @param {number} n
- * @returns {Buffer|null}
- */
- consume (n) {
- if (n > this.#byteOffset) {
- return null
- } else if (n === 0) {
- return emptyBuffer
- }
-
- if (this.#buffers[0].length === n) {
- this.#byteOffset -= this.#buffers[0].length
- return this.#buffers.shift()
- }
-
- const buffer = Buffer.allocUnsafe(n)
- let offset = 0
-
- while (offset !== n) {
- const next = this.#buffers[0]
- const { length } = next
-
- if (length + offset === n) {
- buffer.set(this.#buffers.shift(), offset)
- break
- } else if (length + offset > n) {
- buffer.set(next.subarray(0, n - offset), offset)
- this.#buffers[0] = next.subarray(n - offset)
- break
- } else {
- buffer.set(this.#buffers.shift(), offset)
- offset += next.length
- }
- }
-
- this.#byteOffset -= n
-
- return buffer
- }
-
- parseCloseBody (onlyCode, data) {
- // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
- /** @type {number|undefined} */
- let code
-
- if (data.length >= 2) {
- // _The WebSocket Connection Close Code_ is
- // defined as the status code (Section 7.4) contained in the first Close
- // control frame received by the application
- code = data.readUInt16BE(0)
- }
-
- if (onlyCode) {
- if (!isValidStatusCode(code)) {
- return null
- }
-
- return { code }
- }
-
- // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6
- /** @type {Buffer} */
- let reason = data.subarray(2)
-
- // Remove BOM
- if (reason[0] === 0xEF && reason[1] === 0xBB && reason[2] === 0xBF) {
- reason = reason.subarray(3)
- }
-
- if (code !== undefined && !isValidStatusCode(code)) {
- return null
- }
-
- try {
- // TODO: optimize this
- reason = new TextDecoder('utf-8', { fatal: true }).decode(reason)
- } catch {
- return null
- }
-
- return { code, reason }
- }
-
- get closingInfo () {
- return this.#info.closeInfo
- }
-}
-
-module.exports = {
- ByteParser
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/symbols.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/symbols.js
deleted file mode 100644
index 11d03e38..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/symbols.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict'
-
-module.exports = {
- kWebSocketURL: Symbol('url'),
- kReadyState: Symbol('ready state'),
- kController: Symbol('controller'),
- kResponse: Symbol('response'),
- kBinaryType: Symbol('binary type'),
- kSentClose: Symbol('sent close'),
- kReceivedClose: Symbol('received close'),
- kByteParser: Symbol('byte parser')
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/util.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/util.js
deleted file mode 100644
index 6c59b2c2..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/util.js
+++ /dev/null
@@ -1,200 +0,0 @@
-'use strict'
-
-const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require('./symbols')
-const { states, opcodes } = require('./constants')
-const { MessageEvent, ErrorEvent } = require('./events')
-
-/* globals Blob */
-
-/**
- * @param {import('./websocket').WebSocket} ws
- */
-function isEstablished (ws) {
- // If the server's response is validated as provided for above, it is
- // said that _The WebSocket Connection is Established_ and that the
- // WebSocket Connection is in the OPEN state.
- return ws[kReadyState] === states.OPEN
-}
-
-/**
- * @param {import('./websocket').WebSocket} ws
- */
-function isClosing (ws) {
- // Upon either sending or receiving a Close control frame, it is said
- // that _The WebSocket Closing Handshake is Started_ and that the
- // WebSocket connection is in the CLOSING state.
- return ws[kReadyState] === states.CLOSING
-}
-
-/**
- * @param {import('./websocket').WebSocket} ws
- */
-function isClosed (ws) {
- return ws[kReadyState] === states.CLOSED
-}
-
-/**
- * @see https://dom.spec.whatwg.org/#concept-event-fire
- * @param {string} e
- * @param {EventTarget} target
- * @param {EventInit | undefined} eventInitDict
- */
-function fireEvent (e, target, eventConstructor = Event, eventInitDict) {
- // 1. If eventConstructor is not given, then let eventConstructor be Event.
-
- // 2. Let event be the result of creating an event given eventConstructor,
- // in the relevant realm of target.
- // 3. Initialize event’s type attribute to e.
- const event = new eventConstructor(e, eventInitDict) // eslint-disable-line new-cap
-
- // 4. Initialize any other IDL attributes of event as described in the
- // invocation of this algorithm.
-
- // 5. Return the result of dispatching event at target, with legacy target
- // override flag set if set.
- target.dispatchEvent(event)
-}
-
-/**
- * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
- * @param {import('./websocket').WebSocket} ws
- * @param {number} type Opcode
- * @param {Buffer} data application data
- */
-function websocketMessageReceived (ws, type, data) {
- // 1. If ready state is not OPEN (1), then return.
- if (ws[kReadyState] !== states.OPEN) {
- return
- }
-
- // 2. Let dataForEvent be determined by switching on type and binary type:
- let dataForEvent
-
- if (type === opcodes.TEXT) {
- // -> type indicates that the data is Text
- // a new DOMString containing data
- try {
- dataForEvent = new TextDecoder('utf-8', { fatal: true }).decode(data)
- } catch {
- failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.')
- return
- }
- } else if (type === opcodes.BINARY) {
- if (ws[kBinaryType] === 'blob') {
- // -> type indicates that the data is Binary and binary type is "blob"
- // a new Blob object, created in the relevant Realm of the WebSocket
- // object, that represents data as its raw data
- dataForEvent = new Blob([data])
- } else {
- // -> type indicates that the data is Binary and binary type is "arraybuffer"
- // a new ArrayBuffer object, created in the relevant Realm of the
- // WebSocket object, whose contents are data
- dataForEvent = new Uint8Array(data).buffer
- }
- }
-
- // 3. Fire an event named message at the WebSocket object, using MessageEvent,
- // with the origin attribute initialized to the serialization of the WebSocket
- // object’s url's origin, and the data attribute initialized to dataForEvent.
- fireEvent('message', ws, MessageEvent, {
- origin: ws[kWebSocketURL].origin,
- data: dataForEvent
- })
-}
-
-/**
- * @see https://datatracker.ietf.org/doc/html/rfc6455
- * @see https://datatracker.ietf.org/doc/html/rfc2616
- * @see https://bugs.chromium.org/p/chromium/issues/detail?id=398407
- * @param {string} protocol
- */
-function isValidSubprotocol (protocol) {
- // If present, this value indicates one
- // or more comma-separated subprotocol the client wishes to speak,
- // ordered by preference. The elements that comprise this value
- // MUST be non-empty strings with characters in the range U+0021 to
- // U+007E not including separator characters as defined in
- // [RFC2616] and MUST all be unique strings.
- if (protocol.length === 0) {
- return false
- }
-
- for (const char of protocol) {
- const code = char.charCodeAt(0)
-
- if (
- code < 0x21 ||
- code > 0x7E ||
- char === '(' ||
- char === ')' ||
- char === '<' ||
- char === '>' ||
- char === '@' ||
- char === ',' ||
- char === ';' ||
- char === ':' ||
- char === '\\' ||
- char === '"' ||
- char === '/' ||
- char === '[' ||
- char === ']' ||
- char === '?' ||
- char === '=' ||
- char === '{' ||
- char === '}' ||
- code === 32 || // SP
- code === 9 // HT
- ) {
- return false
- }
- }
-
- return true
-}
-
-/**
- * @see https://datatracker.ietf.org/doc/html/rfc6455#section-7-4
- * @param {number} code
- */
-function isValidStatusCode (code) {
- if (code >= 1000 && code < 1015) {
- return (
- code !== 1004 && // reserved
- code !== 1005 && // "MUST NOT be set as a status code"
- code !== 1006 // "MUST NOT be set as a status code"
- )
- }
-
- return code >= 3000 && code <= 4999
-}
-
-/**
- * @param {import('./websocket').WebSocket} ws
- * @param {string|undefined} reason
- */
-function failWebsocketConnection (ws, reason) {
- const { [kController]: controller, [kResponse]: response } = ws
-
- controller.abort()
-
- if (response?.socket && !response.socket.destroyed) {
- response.socket.destroy()
- }
-
- if (reason) {
- fireEvent('error', ws, ErrorEvent, {
- error: new Error(reason)
- })
- }
-}
-
-module.exports = {
- isEstablished,
- isClosing,
- isClosed,
- fireEvent,
- isValidSubprotocol,
- isValidStatusCode,
- failWebsocketConnection,
- websocketMessageReceived
-}
diff --git a/g4f/Provider/npm/node_modules/undici/lib/websocket/websocket.js b/g4f/Provider/npm/node_modules/undici/lib/websocket/websocket.js
deleted file mode 100644
index e4aa58f5..00000000
--- a/g4f/Provider/npm/node_modules/undici/lib/websocket/websocket.js
+++ /dev/null
@@ -1,641 +0,0 @@
-'use strict'
-
-const { webidl } = require('../fetch/webidl')
-const { DOMException } = require('../fetch/constants')
-const { URLSerializer } = require('../fetch/dataURL')
-const { getGlobalOrigin } = require('../fetch/global')
-const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = require('./constants')
-const {
- kWebSocketURL,
- kReadyState,
- kController,
- kBinaryType,
- kResponse,
- kSentClose,
- kByteParser
-} = require('./symbols')
-const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent } = require('./util')
-const { establishWebSocketConnection } = require('./connection')
-const { WebsocketFrameSend } = require('./frame')
-const { ByteParser } = require('./receiver')
-const { kEnumerableProperty, isBlobLike } = require('../core/util')
-const { getGlobalDispatcher } = require('../global')
-const { types } = require('util')
-
-let experimentalWarned = false
-
-// https://websockets.spec.whatwg.org/#interface-definition
-class WebSocket extends EventTarget {
- #events = {
- open: null,
- error: null,
- close: null,
- message: null
- }
-
- #bufferedAmount = 0
- #protocol = ''
- #extensions = ''
-
- /**
- * @param {string} url
- * @param {string|string[]} protocols
- */
- constructor (url, protocols = []) {
- super()
-
- webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket constructor' })
-
- if (!experimentalWarned) {
- experimentalWarned = true
- process.emitWarning('WebSockets are experimental, expect them to change at any time.', {
- code: 'UNDICI-WS'
- })
- }
-
- const options = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols)
-
- url = webidl.converters.USVString(url)
- protocols = options.protocols
-
- // 1. Let baseURL be this's relevant settings object's API base URL.
- const baseURL = getGlobalOrigin()
-
- // 1. Let urlRecord be the result of applying the URL parser to url with baseURL.
- let urlRecord
-
- try {
- urlRecord = new URL(url, baseURL)
- } catch (e) {
- // 3. If urlRecord is failure, then throw a "SyntaxError" DOMException.
- throw new DOMException(e, 'SyntaxError')
- }
-
- // 4. If urlRecord’s scheme is "http", then set urlRecord’s scheme to "ws".
- if (urlRecord.protocol === 'http:') {
- urlRecord.protocol = 'ws:'
- } else if (urlRecord.protocol === 'https:') {
- // 5. Otherwise, if urlRecord’s scheme is "https", set urlRecord’s scheme to "wss".
- urlRecord.protocol = 'wss:'
- }
-
- // 6. If urlRecord’s scheme is not "ws" or "wss", then throw a "SyntaxError" DOMException.
- if (urlRecord.protocol !== 'ws:' && urlRecord.protocol !== 'wss:') {
- throw new DOMException(
- `Expected a ws: or wss: protocol, got ${urlRecord.protocol}`,
- 'SyntaxError'
- )
- }
-
- // 7. If urlRecord’s fragment is non-null, then throw a "SyntaxError"
- // DOMException.
- if (urlRecord.hash || urlRecord.href.endsWith('#')) {
- throw new DOMException('Got fragment', 'SyntaxError')
- }
-
- // 8. If protocols is a string, set protocols to a sequence consisting
- // of just that string.
- if (typeof protocols === 'string') {
- protocols = [protocols]
- }
-
- // 9. If any of the values in protocols occur more than once or otherwise
- // fail to match the requirements for elements that comprise the value
- // of `Sec-WebSocket-Protocol` fields as defined by The WebSocket
- // protocol, then throw a "SyntaxError" DOMException.
- if (protocols.length !== new Set(protocols.map(p => p.toLowerCase())).size) {
- throw new DOMException('Invalid Sec-WebSocket-Protocol value', 'SyntaxError')
- }
-
- if (protocols.length > 0 && !protocols.every(p => isValidSubprotocol(p))) {
- throw new DOMException('Invalid Sec-WebSocket-Protocol value', 'SyntaxError')
- }
-
- // 10. Set this's url to urlRecord.
- this[kWebSocketURL] = new URL(urlRecord.href)
-
- // 11. Let client be this's relevant settings object.
-
- // 12. Run this step in parallel:
-
- // 1. Establish a WebSocket connection given urlRecord, protocols,
- // and client.
- this[kController] = establishWebSocketConnection(
- urlRecord,
- protocols,
- this,
- (response) => this.#onConnectionEstablished(response),
- options
- )
-
- // Each WebSocket object has an associated ready state, which is a
- // number representing the state of the connection. Initially it must
- // be CONNECTING (0).
- this[kReadyState] = WebSocket.CONNECTING
-
- // The extensions attribute must initially return the empty string.
-
- // The protocol attribute must initially return the empty string.
-
- // Each WebSocket object has an associated binary type, which is a
- // BinaryType. Initially it must be "blob".
- this[kBinaryType] = 'blob'
- }
-
- /**
- * @see https://websockets.spec.whatwg.org/#dom-websocket-close
- * @param {number|undefined} code
- * @param {string|undefined} reason
- */
- close (code = undefined, reason = undefined) {
- webidl.brandCheck(this, WebSocket)
-
- if (code !== undefined) {
- code = webidl.converters['unsigned short'](code, { clamp: true })
- }
-
- if (reason !== undefined) {
- reason = webidl.converters.USVString(reason)
- }
-
- // 1. If code is present, but is neither an integer equal to 1000 nor an
- // integer in the range 3000 to 4999, inclusive, throw an
- // "InvalidAccessError" DOMException.
- if (code !== undefined) {
- if (code !== 1000 && (code < 3000 || code > 4999)) {
- throw new DOMException('invalid code', 'InvalidAccessError')
- }
- }
-
- let reasonByteLength = 0
-
- // 2. If reason is present, then run these substeps:
- if (reason !== undefined) {
- // 1. Let reasonBytes be the result of encoding reason.
- // 2. If reasonBytes is longer than 123 bytes, then throw a
- // "SyntaxError" DOMException.
- reasonByteLength = Buffer.byteLength(reason)
-
- if (reasonByteLength > 123) {
- throw new DOMException(
- `Reason must be less than 123 bytes; received ${reasonByteLength}`,
- 'SyntaxError'
- )
- }
- }
-
- // 3. Run the first matching steps from the following list:
- if (this[kReadyState] === WebSocket.CLOSING || this[kReadyState] === WebSocket.CLOSED) {
- // If this's ready state is CLOSING (2) or CLOSED (3)
- // Do nothing.
- } else if (!isEstablished(this)) {
- // If the WebSocket connection is not yet established
- // Fail the WebSocket connection and set this's ready state
- // to CLOSING (2).
- failWebsocketConnection(this, 'Connection was closed before it was established.')
- this[kReadyState] = WebSocket.CLOSING
- } else if (!isClosing(this)) {
- // If the WebSocket closing handshake has not yet been started
- // Start the WebSocket closing handshake and set this's ready
- // state to CLOSING (2).
- // - If neither code nor reason is present, the WebSocket Close
- // message must not have a body.
- // - If code is present, then the status code to use in the
- // WebSocket Close message must be the integer given by code.
- // - If reason is also present, then reasonBytes must be
- // provided in the Close message after the status code.
-
- const frame = new WebsocketFrameSend()
-
- // If neither code nor reason is present, the WebSocket Close
- // message must not have a body.
-
- // If code is present, then the status code to use in the
- // WebSocket Close message must be the integer given by code.
- if (code !== undefined && reason === undefined) {
- frame.frameData = Buffer.allocUnsafe(2)
- frame.frameData.writeUInt16BE(code, 0)
- } else if (code !== undefined && reason !== undefined) {
- // If reason is also present, then reasonBytes must be
- // provided in the Close message after the status code.
- frame.frameData = Buffer.allocUnsafe(2 + reasonByteLength)
- frame.frameData.writeUInt16BE(code, 0)
- // the body MAY contain UTF-8-encoded data with value /reason/
- frame.frameData.write(reason, 2, 'utf-8')
- } else {
- frame.frameData = emptyBuffer
- }
-
- /** @type {import('stream').Duplex} */
- const socket = this[kResponse].socket
-
- socket.write(frame.createFrame(opcodes.CLOSE), (err) => {
- if (!err) {
- this[kSentClose] = true
- }
- })
-
- // Upon either sending or receiving a Close control frame, it is said
- // that _The WebSocket Closing Handshake is Started_ and that the
- // WebSocket connection is in the CLOSING state.
- this[kReadyState] = states.CLOSING
- } else {
- // Otherwise
- // Set this's ready state to CLOSING (2).
- this[kReadyState] = WebSocket.CLOSING
- }
- }
-
- /**
- * @see https://websockets.spec.whatwg.org/#dom-websocket-send
- * @param {NodeJS.TypedArray|ArrayBuffer|Blob|string} data
- */
- send (data) {
- webidl.brandCheck(this, WebSocket)
-
- webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket.send' })
-
- data = webidl.converters.WebSocketSendData(data)
-
- // 1. If this's ready state is CONNECTING, then throw an
- // "InvalidStateError" DOMException.
- if (this[kReadyState] === WebSocket.CONNECTING) {
- throw new DOMException('Sent before connected.', 'InvalidStateError')
- }
-
- // 2. Run the appropriate set of steps from the following list:
- // https://datatracker.ietf.org/doc/html/rfc6455#section-6.1
- // https://datatracker.ietf.org/doc/html/rfc6455#section-5.2
-
- if (!isEstablished(this) || isClosing(this)) {
- return
- }
-
- /** @type {import('stream').Duplex} */
- const socket = this[kResponse].socket
-
- // If data is a string
- if (typeof data === 'string') {
- // If the WebSocket connection is established and the WebSocket
- // closing handshake has not yet started, then the user agent
- // must send a WebSocket Message comprised of the data argument
- // using a text frame opcode; if the data cannot be sent, e.g.
- // because it would need to be buffered but the buffer is full,
- // the user agent must flag the WebSocket as full and then close
- // the WebSocket connection. Any invocation of this method with a
- // string argument that does not throw an exception must increase
- // the bufferedAmount attribute by the number of bytes needed to
- // express the argument as UTF-8.
-
- const value = Buffer.from(data)
- const frame = new WebsocketFrameSend(value)
- const buffer = frame.createFrame(opcodes.TEXT)
-
- this.#bufferedAmount += value.byteLength
- socket.write(buffer, () => {
- this.#bufferedAmount -= value.byteLength
- })
- } else if (types.isArrayBuffer(data)) {
- // If the WebSocket connection is established, and the WebSocket
- // closing handshake has not yet started, then the user agent must
- // send a WebSocket Message comprised of data using a binary frame
- // opcode; if the data cannot be sent, e.g. because it would need
- // to be buffered but the buffer is full, the user agent must flag
- // the WebSocket as full and then close the WebSocket connection.
- // The data to be sent is the data stored in the buffer described
- // by the ArrayBuffer object. Any invocation of this method with an
- // ArrayBuffer argument that does not throw an exception must
- // increase the bufferedAmount attribute by the length of the
- // ArrayBuffer in bytes.
-
- const value = Buffer.from(data)
- const frame = new WebsocketFrameSend(value)
- const buffer = frame.createFrame(opcodes.BINARY)
-
- this.#bufferedAmount += value.byteLength
- socket.write(buffer, () => {
- this.#bufferedAmount -= value.byteLength
- })
- } else if (ArrayBuffer.isView(data)) {
- // If the WebSocket connection is established, and the WebSocket
- // closing handshake has not yet started, then the user agent must
- // send a WebSocket Message comprised of data using a binary frame
- // opcode; if the data cannot be sent, e.g. because it would need to
- // be buffered but the buffer is full, the user agent must flag the
- // WebSocket as full and then close the WebSocket connection. The
- // data to be sent is the data stored in the section of the buffer
- // described by the ArrayBuffer object that data references. Any
- // invocation of this method with this kind of argument that does
- // not throw an exception must increase the bufferedAmount attribute
- // by the length of data’s buffer in bytes.
-
- const ab = Buffer.from(data, data.byteOffset, data.byteLength)
-
- const frame = new WebsocketFrameSend(ab)
- const buffer = frame.createFrame(opcodes.BINARY)
-
- this.#bufferedAmount += ab.byteLength
- socket.write(buffer, () => {
- this.#bufferedAmount -= ab.byteLength
- })
- } else if (isBlobLike(data)) {
- // If the WebSocket connection is established, and the WebSocket
- // closing handshake has not yet started, then the user agent must
- // send a WebSocket Message comprised of data using a binary frame
- // opcode; if the data cannot be sent, e.g. because it would need to
- // be buffered but the buffer is full, the user agent must flag the
- // WebSocket as full and then close the WebSocket connection. The data
- // to be sent is the raw data represented by the Blob object. Any
- // invocation of this method with a Blob argument that does not throw
- // an exception must increase the bufferedAmount attribute by the size
- // of the Blob object’s raw data, in bytes.
-
- const frame = new WebsocketFrameSend()
-
- data.arrayBuffer().then((ab) => {
- const value = Buffer.from(ab)
- frame.frameData = value
- const buffer = frame.createFrame(opcodes.BINARY)
-
- this.#bufferedAmount += value.byteLength
- socket.write(buffer, () => {
- this.#bufferedAmount -= value.byteLength
- })
- })
- }
- }
-
- get readyState () {
- webidl.brandCheck(this, WebSocket)
-
- // The readyState getter steps are to return this's ready state.
- return this[kReadyState]
- }
-
- get bufferedAmount () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#bufferedAmount
- }
-
- get url () {
- webidl.brandCheck(this, WebSocket)
-
- // The url getter steps are to return this's url, serialized.
- return URLSerializer(this[kWebSocketURL])
- }
-
- get extensions () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#extensions
- }
-
- get protocol () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#protocol
- }
-
- get onopen () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#events.open
- }
-
- set onopen (fn) {
- webidl.brandCheck(this, WebSocket)
-
- if (this.#events.open) {
- this.removeEventListener('open', this.#events.open)
- }
-
- if (typeof fn === 'function') {
- this.#events.open = fn
- this.addEventListener('open', fn)
- } else {
- this.#events.open = null
- }
- }
-
- get onerror () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#events.error
- }
-
- set onerror (fn) {
- webidl.brandCheck(this, WebSocket)
-
- if (this.#events.error) {
- this.removeEventListener('error', this.#events.error)
- }
-
- if (typeof fn === 'function') {
- this.#events.error = fn
- this.addEventListener('error', fn)
- } else {
- this.#events.error = null
- }
- }
-
- get onclose () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#events.close
- }
-
- set onclose (fn) {
- webidl.brandCheck(this, WebSocket)
-
- if (this.#events.close) {
- this.removeEventListener('close', this.#events.close)
- }
-
- if (typeof fn === 'function') {
- this.#events.close = fn
- this.addEventListener('close', fn)
- } else {
- this.#events.close = null
- }
- }
-
- get onmessage () {
- webidl.brandCheck(this, WebSocket)
-
- return this.#events.message
- }
-
- set onmessage (fn) {
- webidl.brandCheck(this, WebSocket)
-
- if (this.#events.message) {
- this.removeEventListener('message', this.#events.message)
- }
-
- if (typeof fn === 'function') {
- this.#events.message = fn
- this.addEventListener('message', fn)
- } else {
- this.#events.message = null
- }
- }
-
- get binaryType () {
- webidl.brandCheck(this, WebSocket)
-
- return this[kBinaryType]
- }
-
- set binaryType (type) {
- webidl.brandCheck(this, WebSocket)
-
- if (type !== 'blob' && type !== 'arraybuffer') {
- this[kBinaryType] = 'blob'
- } else {
- this[kBinaryType] = type
- }
- }
-
- /**
- * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
- */
- #onConnectionEstablished (response) {
- // processResponse is called when the "response’s header list has been received and initialized."
- // once this happens, the connection is open
- this[kResponse] = response
-
- const parser = new ByteParser(this)
- parser.on('drain', function onParserDrain () {
- this.ws[kResponse].socket.resume()
- })
-
- response.socket.ws = this
- this[kByteParser] = parser
-
- // 1. Change the ready state to OPEN (1).
- this[kReadyState] = states.OPEN
-
- // 2. Change the extensions attribute’s value to the extensions in use, if
- // it is not the null value.
- // https://datatracker.ietf.org/doc/html/rfc6455#section-9.1
- const extensions = response.headersList.get('sec-websocket-extensions')
-
- if (extensions !== null) {
- this.#extensions = extensions
- }
-
- // 3. Change the protocol attribute’s value to the subprotocol in use, if
- // it is not the null value.
- // https://datatracker.ietf.org/doc/html/rfc6455#section-1.9
- const protocol = response.headersList.get('sec-websocket-protocol')
-
- if (protocol !== null) {
- this.#protocol = protocol
- }
-
- // 4. Fire an event named open at the WebSocket object.
- fireEvent('open', this)
- }
-}
-
-// https://websockets.spec.whatwg.org/#dom-websocket-connecting
-WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING
-// https://websockets.spec.whatwg.org/#dom-websocket-open
-WebSocket.OPEN = WebSocket.prototype.OPEN = states.OPEN
-// https://websockets.spec.whatwg.org/#dom-websocket-closing
-WebSocket.CLOSING = WebSocket.prototype.CLOSING = states.CLOSING
-// https://websockets.spec.whatwg.org/#dom-websocket-closed
-WebSocket.CLOSED = WebSocket.prototype.CLOSED = states.CLOSED
-
-Object.defineProperties(WebSocket.prototype, {
- CONNECTING: staticPropertyDescriptors,
- OPEN: staticPropertyDescriptors,
- CLOSING: staticPropertyDescriptors,
- CLOSED: staticPropertyDescriptors,
- url: kEnumerableProperty,
- readyState: kEnumerableProperty,
- bufferedAmount: kEnumerableProperty,
- onopen: kEnumerableProperty,
- onerror: kEnumerableProperty,
- onclose: kEnumerableProperty,
- close: kEnumerableProperty,
- onmessage: kEnumerableProperty,
- binaryType: kEnumerableProperty,
- send: kEnumerableProperty,
- extensions: kEnumerableProperty,
- protocol: kEnumerableProperty,
- [Symbol.toStringTag]: {
- value: 'WebSocket',
- writable: false,
- enumerable: false,
- configurable: true
- }
-})
-
-Object.defineProperties(WebSocket, {
- CONNECTING: staticPropertyDescriptors,
- OPEN: staticPropertyDescriptors,
- CLOSING: staticPropertyDescriptors,
- CLOSED: staticPropertyDescriptors
-})
-
-webidl.converters['sequence<DOMString>'] = webidl.sequenceConverter(
- webidl.converters.DOMString
-)
-
-webidl.converters['DOMString or sequence<DOMString>'] = function (V) {
- if (webidl.util.Type(V) === 'Object' && Symbol.iterator in V) {
- return webidl.converters['sequence<DOMString>'](V)
- }
-
- return webidl.converters.DOMString(V)
-}
-
-// This implements the propsal made in https://github.com/whatwg/websockets/issues/42
-webidl.converters.WebSocketInit = webidl.dictionaryConverter([
- {
- key: 'protocols',
- converter: webidl.converters['DOMString or sequence<DOMString>'],
- get defaultValue () {
- return []
- }
- },
- {
- key: 'dispatcher',
- converter: (V) => V,
- get defaultValue () {
- return getGlobalDispatcher()
- }
- },
- {
- key: 'headers',
- converter: webidl.nullableConverter(webidl.converters.HeadersInit)
- }
-])
-
-webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'] = function (V) {
- if (webidl.util.Type(V) === 'Object' && !(Symbol.iterator in V)) {
- return webidl.converters.WebSocketInit(V)
- }
-
- return { protocols: webidl.converters['DOMString or sequence<DOMString>'](V) }
-}
-
-webidl.converters.WebSocketSendData = function (V) {
- if (webidl.util.Type(V) === 'Object') {
- if (isBlobLike(V)) {
- return webidl.converters.Blob(V, { strict: false })
- }
-
- if (ArrayBuffer.isView(V) || types.isAnyArrayBuffer(V)) {
- return webidl.converters.BufferSource(V)
- }
- }
-
- return webidl.converters.USVString(V)
-}
-
-module.exports = {
- WebSocket
-}