commit
This commit is contained in:
parent
13ec9babde
commit
68f4b60012
1429 changed files with 2481 additions and 272836 deletions
85
node_modules/undici/lib/websocket/connection.js
generated
vendored
85
node_modules/undici/lib/websocket/connection.js
generated
vendored
|
@ -5,19 +5,17 @@ const diagnosticsChannel = require('diagnostics_channel')
|
|||
const { uid, states } = require('./constants')
|
||||
const {
|
||||
kReadyState,
|
||||
kResponse,
|
||||
kExtensions,
|
||||
kProtocol,
|
||||
kSentClose,
|
||||
kByteParser,
|
||||
kReceivedClose
|
||||
} = require('./symbols')
|
||||
const { fireEvent, failWebsocketConnection } = require('./util')
|
||||
const { CloseEvent } = require('./events')
|
||||
const { ByteParser } = require('./receiver')
|
||||
const { makeRequest } = require('../fetch/request')
|
||||
const { fetching } = require('../fetch/index')
|
||||
const { getGlobalDispatcher } = require('../..')
|
||||
const { Headers } = require('../fetch/headers')
|
||||
const { getGlobalDispatcher } = require('../global')
|
||||
const { kHeadersList } = require('../core/symbols')
|
||||
|
||||
const channels = {}
|
||||
channels.open = diagnosticsChannel.channel('undici:websocket:open')
|
||||
|
@ -29,8 +27,10 @@ channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error
|
|||
* @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) {
|
||||
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
|
||||
|
@ -51,6 +51,13 @@ function establishWebSocketConnection (url, protocols, ws) {
|
|||
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.
|
||||
|
@ -91,7 +98,7 @@ function establishWebSocketConnection (url, protocols, ws) {
|
|||
const controller = fetching({
|
||||
request,
|
||||
useParallelQueue: true,
|
||||
dispatcher: getGlobalDispatcher(),
|
||||
dispatcher: options.dispatcher ?? getGlobalDispatcher(),
|
||||
processResponse (response) {
|
||||
// 1. If response is a network error or its status is not 101,
|
||||
// fail the WebSocket connection.
|
||||
|
@ -173,67 +180,25 @@ function establishWebSocketConnection (url, protocols, ws) {
|
|||
return
|
||||
}
|
||||
|
||||
// processResponse is called when the "response’s header list has been received and initialized."
|
||||
// once this happens, the connection is open
|
||||
ws[kResponse] = response
|
||||
|
||||
const parser = new ByteParser(ws)
|
||||
response.socket.ws = ws // TODO: use symbol
|
||||
ws[kByteParser] = parser
|
||||
|
||||
whenConnectionEstablished(ws)
|
||||
|
||||
response.socket.on('data', onSocketData)
|
||||
response.socket.on('close', onSocketClose)
|
||||
response.socket.on('error', onSocketError)
|
||||
|
||||
parser.on('drain', onParserDrain)
|
||||
if (channels.open.hasSubscribers) {
|
||||
channels.open.publish({
|
||||
address: response.socket.address(),
|
||||
protocol: secProtocol,
|
||||
extensions: secExtension
|
||||
})
|
||||
}
|
||||
|
||||
onEstablish(response)
|
||||
}
|
||||
})
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
||||
* @param {import('./websocket').WebSocket} ws
|
||||
*/
|
||||
function whenConnectionEstablished (ws) {
|
||||
const { [kResponse]: response } = ws
|
||||
|
||||
// 1. Change the ready state to OPEN (1).
|
||||
ws[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) {
|
||||
ws[kExtensions] = 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) {
|
||||
ws[kProtocol] = protocol
|
||||
}
|
||||
|
||||
// 4. Fire an event named open at the WebSocket object.
|
||||
fireEvent('open', ws)
|
||||
|
||||
if (channels.open.hasSubscribers) {
|
||||
channels.open.publish({
|
||||
address: response.socket.address(),
|
||||
protocol,
|
||||
extensions
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} chunk
|
||||
*/
|
||||
|
@ -243,10 +208,6 @@ function onSocketData (chunk) {
|
|||
}
|
||||
}
|
||||
|
||||
function onParserDrain () {
|
||||
this.ws[kResponse].socket.resume()
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
||||
* @see https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.4
|
||||
|
|
2
node_modules/undici/lib/websocket/frame.js
generated
vendored
2
node_modules/undici/lib/websocket/frame.js
generated
vendored
|
@ -43,7 +43,7 @@ class WebsocketFrameSend {
|
|||
buffer[1] = payloadLength
|
||||
|
||||
if (payloadLength === 126) {
|
||||
new DataView(buffer.buffer).setUint16(2, bodyLength)
|
||||
buffer.writeUInt16BE(bodyLength, 2)
|
||||
} else if (payloadLength === 127) {
|
||||
// Clear extended payload length
|
||||
buffer[2] = buffer[3] = 0
|
||||
|
|
3
node_modules/undici/lib/websocket/symbols.js
generated
vendored
3
node_modules/undici/lib/websocket/symbols.js
generated
vendored
|
@ -5,10 +5,7 @@ module.exports = {
|
|||
kReadyState: Symbol('ready state'),
|
||||
kController: Symbol('controller'),
|
||||
kResponse: Symbol('response'),
|
||||
kExtensions: Symbol('extensions'),
|
||||
kProtocol: Symbol('protocol'),
|
||||
kBinaryType: Symbol('binary type'),
|
||||
kClosingFrame: Symbol('closing frame'),
|
||||
kSentClose: Symbol('sent close'),
|
||||
kReceivedClose: Symbol('received close'),
|
||||
kByteParser: Symbol('byte parser')
|
||||
|
|
100
node_modules/undici/lib/websocket/websocket.js
generated
vendored
100
node_modules/undici/lib/websocket/websocket.js
generated
vendored
|
@ -8,16 +8,17 @@ const {
|
|||
kWebSocketURL,
|
||||
kReadyState,
|
||||
kController,
|
||||
kExtensions,
|
||||
kProtocol,
|
||||
kBinaryType,
|
||||
kResponse,
|
||||
kSentClose
|
||||
kSentClose,
|
||||
kByteParser
|
||||
} = require('./symbols')
|
||||
const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection } = require('./util')
|
||||
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
|
||||
|
@ -32,6 +33,8 @@ class WebSocket extends EventTarget {
|
|||
}
|
||||
|
||||
#bufferedAmount = 0
|
||||
#protocol = ''
|
||||
#extensions = ''
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
|
@ -49,8 +52,10 @@ class WebSocket extends EventTarget {
|
|||
})
|
||||
}
|
||||
|
||||
const options = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols)
|
||||
|
||||
url = webidl.converters.USVString(url)
|
||||
protocols = webidl.converters['DOMString or sequence<DOMString>'](protocols)
|
||||
protocols = options.protocols
|
||||
|
||||
// 1. Let urlRecord be the result of applying the URL parser to url.
|
||||
let urlRecord
|
||||
|
@ -104,7 +109,13 @@ class WebSocket extends EventTarget {
|
|||
|
||||
// 1. Establish a WebSocket connection given urlRecord, protocols,
|
||||
// and client.
|
||||
this[kController] = establishWebSocketConnection(urlRecord, protocols, this)
|
||||
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
|
||||
|
@ -112,10 +123,8 @@ class WebSocket extends EventTarget {
|
|||
this[kReadyState] = WebSocket.CONNECTING
|
||||
|
||||
// The extensions attribute must initially return the empty string.
|
||||
this[kExtensions] = ''
|
||||
|
||||
// The protocol attribute must initially return the empty string.
|
||||
this[kProtocol] = ''
|
||||
|
||||
// Each WebSocket object has an associated binary type, which is a
|
||||
// BinaryType. Initially it must be "blob".
|
||||
|
@ -368,13 +377,13 @@ class WebSocket extends EventTarget {
|
|||
get extensions () {
|
||||
webidl.brandCheck(this, WebSocket)
|
||||
|
||||
return this[kExtensions]
|
||||
return this.#extensions
|
||||
}
|
||||
|
||||
get protocol () {
|
||||
webidl.brandCheck(this, WebSocket)
|
||||
|
||||
return this[kProtocol]
|
||||
return this.#protocol
|
||||
}
|
||||
|
||||
get onopen () {
|
||||
|
@ -476,6 +485,47 @@ class WebSocket extends EventTarget {
|
|||
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
|
||||
|
@ -531,6 +581,36 @@ webidl.converters['DOMString or sequence<DOMString>'] = function (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)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue