undici 7.11.0 → 7.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/docs/docs/api/DiagnosticsChannel.md +7 -4
- package/docs/docs/api/Dispatcher.md +2 -2
- package/docs/docs/api/WebSocket.md +27 -0
- package/index.js +3 -1
- package/lib/api/readable.js +1 -3
- package/lib/core/request.js +6 -1
- package/lib/core/tree.js +1 -1
- package/lib/dispatcher/client-h1.js +8 -17
- package/lib/handler/cache-handler.js +4 -1
- package/lib/handler/redirect-handler.js +2 -2
- package/lib/interceptor/cache.js +2 -2
- package/lib/interceptor/redirect.js +1 -1
- package/lib/util/cache.js +1 -1
- package/lib/util/promise.js +28 -0
- package/lib/web/cache/cache.js +10 -8
- package/lib/web/fetch/body.js +35 -23
- package/lib/web/fetch/index.js +221 -225
- package/lib/web/fetch/request.js +15 -7
- package/lib/web/fetch/response.js +5 -3
- package/lib/web/fetch/util.js +21 -23
- package/lib/web/websocket/connection.js +0 -9
- package/lib/web/websocket/receiver.js +2 -12
- package/lib/web/websocket/stream/websocketstream.js +7 -4
- package/lib/web/websocket/websocket.js +57 -1
- package/package.json +2 -2
- package/types/webidl.d.ts +10 -0
- package/types/websocket.d.ts +2 -0
- package/lib/web/fetch/dispatcher-weakref.js +0 -5
package/lib/web/fetch/util.js
CHANGED
|
@@ -924,17 +924,6 @@ function sameOrigin (A, B) {
|
|
|
924
924
|
return false
|
|
925
925
|
}
|
|
926
926
|
|
|
927
|
-
function createDeferredPromise () {
|
|
928
|
-
let res
|
|
929
|
-
let rej
|
|
930
|
-
const promise = new Promise((resolve, reject) => {
|
|
931
|
-
res = resolve
|
|
932
|
-
rej = reject
|
|
933
|
-
})
|
|
934
|
-
|
|
935
|
-
return { promise, resolve: res, reject: rej }
|
|
936
|
-
}
|
|
937
|
-
|
|
938
927
|
function isAborted (fetchParams) {
|
|
939
928
|
return fetchParams.controller.state === 'aborted'
|
|
940
929
|
}
|
|
@@ -1177,6 +1166,11 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
|
|
|
1177
1166
|
}
|
|
1178
1167
|
|
|
1179
1168
|
/**
|
|
1169
|
+
* @param {import('./body').ExtractBodyResult} body
|
|
1170
|
+
* @param {(bytes: Uint8Array) => void} processBody
|
|
1171
|
+
* @param {(error: Error) => void} processBodyError
|
|
1172
|
+
* @returns {void}
|
|
1173
|
+
*
|
|
1180
1174
|
* @see https://fetch.spec.whatwg.org/#body-fully-read
|
|
1181
1175
|
*/
|
|
1182
1176
|
function fullyReadBody (body, processBody, processBodyError) {
|
|
@@ -1191,20 +1185,17 @@ function fullyReadBody (body, processBody, processBodyError) {
|
|
|
1191
1185
|
// with taskDestination.
|
|
1192
1186
|
const errorSteps = processBodyError
|
|
1193
1187
|
|
|
1188
|
+
try {
|
|
1194
1189
|
// 4. Let reader be the result of getting a reader for body’s stream.
|
|
1195
1190
|
// If that threw an exception, then run errorSteps with that
|
|
1196
1191
|
// exception and return.
|
|
1197
|
-
|
|
1192
|
+
const reader = body.stream.getReader()
|
|
1198
1193
|
|
|
1199
|
-
|
|
1200
|
-
reader
|
|
1194
|
+
// 5. Read all bytes from reader, given successSteps and errorSteps.
|
|
1195
|
+
readAllBytes(reader, successSteps, errorSteps)
|
|
1201
1196
|
} catch (e) {
|
|
1202
1197
|
errorSteps(e)
|
|
1203
|
-
return
|
|
1204
1198
|
}
|
|
1205
|
-
|
|
1206
|
-
// 5. Read all bytes from reader, given successSteps and errorSteps.
|
|
1207
|
-
readAllBytes(reader, successSteps, errorSteps)
|
|
1208
1199
|
}
|
|
1209
1200
|
|
|
1210
1201
|
/**
|
|
@@ -1241,15 +1232,16 @@ function isomorphicEncode (input) {
|
|
|
1241
1232
|
/**
|
|
1242
1233
|
* @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes
|
|
1243
1234
|
* @see https://streams.spec.whatwg.org/#read-loop
|
|
1244
|
-
* @param {
|
|
1235
|
+
* @param {ReadableStream<Uint8Array<ArrayBuffer>>} reader
|
|
1245
1236
|
* @param {(bytes: Uint8Array) => void} successSteps
|
|
1246
1237
|
* @param {(error: Error) => void} failureSteps
|
|
1238
|
+
* @returns {Promise<void>}
|
|
1247
1239
|
*/
|
|
1248
1240
|
async function readAllBytes (reader, successSteps, failureSteps) {
|
|
1249
|
-
const bytes = []
|
|
1250
|
-
let byteLength = 0
|
|
1251
|
-
|
|
1252
1241
|
try {
|
|
1242
|
+
const bytes = []
|
|
1243
|
+
let byteLength = 0
|
|
1244
|
+
|
|
1253
1245
|
do {
|
|
1254
1246
|
const { done, value: chunk } = await reader.read()
|
|
1255
1247
|
|
|
@@ -1324,10 +1316,17 @@ function urlIsHttpHttpsScheme (url) {
|
|
|
1324
1316
|
return protocol === 'http:' || protocol === 'https:'
|
|
1325
1317
|
}
|
|
1326
1318
|
|
|
1319
|
+
/**
|
|
1320
|
+
* @typedef {Object} RangeHeaderValue
|
|
1321
|
+
* @property {number|null} rangeStartValue
|
|
1322
|
+
* @property {number|null} rangeEndValue
|
|
1323
|
+
*/
|
|
1324
|
+
|
|
1327
1325
|
/**
|
|
1328
1326
|
* @see https://fetch.spec.whatwg.org/#simple-range-header-value
|
|
1329
1327
|
* @param {string} value
|
|
1330
1328
|
* @param {boolean} allowWhitespace
|
|
1329
|
+
* @return {RangeHeaderValue|'failure'}
|
|
1331
1330
|
*/
|
|
1332
1331
|
function simpleRangeHeaderValue (value, allowWhitespace) {
|
|
1333
1332
|
// 1. Let data be the isomorphic decoding of value.
|
|
@@ -1732,7 +1731,6 @@ module.exports = {
|
|
|
1732
1731
|
isAborted,
|
|
1733
1732
|
isCancelled,
|
|
1734
1733
|
isValidEncodedURL,
|
|
1735
|
-
createDeferredPromise,
|
|
1736
1734
|
ReadableStreamFrom,
|
|
1737
1735
|
tryUpgradeRequestToAPotentiallyTrustworthyURL,
|
|
1738
1736
|
clampAndCoarsenConnectionTimingInfo,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = require('./constants')
|
|
4
4
|
const { parseExtensions, isClosed, isClosing, isEstablished, validateCloseCodeAndReason } = require('./util')
|
|
5
|
-
const { channels } = require('../../core/diagnostics')
|
|
6
5
|
const { makeRequest } = require('../fetch/request')
|
|
7
6
|
const { fetching } = require('../fetch/index')
|
|
8
7
|
const { Headers, getHeadersList } = require('../fetch/headers')
|
|
@@ -200,14 +199,6 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
|
|
|
200
199
|
response.socket.on('close', handler.onSocketClose)
|
|
201
200
|
response.socket.on('error', handler.onSocketError)
|
|
202
201
|
|
|
203
|
-
if (channels.open.hasSubscribers) {
|
|
204
|
-
channels.open.publish({
|
|
205
|
-
address: response.socket.address(),
|
|
206
|
-
protocol: secProtocol,
|
|
207
|
-
extensions: secExtension
|
|
208
|
-
})
|
|
209
|
-
}
|
|
210
|
-
|
|
211
202
|
handler.wasEverConnected = true
|
|
212
203
|
handler.onConnectionEstablished(response, extensions)
|
|
213
204
|
}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { Writable } = require('node:stream')
|
|
4
4
|
const assert = require('node:assert')
|
|
5
5
|
const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
|
|
6
|
-
const { channels } = require('../../core/diagnostics')
|
|
7
6
|
const {
|
|
8
7
|
isValidStatusCode,
|
|
9
8
|
isValidOpcode,
|
|
@@ -423,22 +422,13 @@ class ByteParser extends Writable {
|
|
|
423
422
|
|
|
424
423
|
this.#handler.socket.write(frame.createFrame(opcodes.PONG))
|
|
425
424
|
|
|
426
|
-
|
|
427
|
-
channels.ping.publish({
|
|
428
|
-
payload: body
|
|
429
|
-
})
|
|
430
|
-
}
|
|
425
|
+
this.#handler.onPing(body)
|
|
431
426
|
}
|
|
432
427
|
} else if (opcode === opcodes.PONG) {
|
|
433
428
|
// A Pong frame MAY be sent unsolicited. This serves as a
|
|
434
429
|
// unidirectional heartbeat. A response to an unsolicited Pong frame is
|
|
435
430
|
// not expected.
|
|
436
|
-
|
|
437
|
-
if (channels.pong.hasSubscribers) {
|
|
438
|
-
channels.pong.publish({
|
|
439
|
-
payload: body
|
|
440
|
-
})
|
|
441
|
-
}
|
|
431
|
+
this.#handler.onPong(body)
|
|
442
432
|
}
|
|
443
433
|
|
|
444
434
|
return true
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { createDeferredPromise
|
|
3
|
+
const { createDeferredPromise } = require('../../../util/promise')
|
|
4
|
+
const { environmentSettingsObject } = require('../../fetch/util')
|
|
4
5
|
const { states, opcodes, sentCloseFrameState } = require('../constants')
|
|
5
6
|
const { webidl } = require('../../webidl')
|
|
6
7
|
const { getURLRecord, isValidSubprotocol, isEstablished, utf8Decode } = require('../util')
|
|
@@ -21,11 +22,11 @@ class WebSocketStream {
|
|
|
21
22
|
#url
|
|
22
23
|
|
|
23
24
|
// Each WebSocketStream object has an associated opened promise , which is a promise.
|
|
24
|
-
/** @type {
|
|
25
|
+
/** @type {import('../../../util/promise').DeferredPromise} */
|
|
25
26
|
#openedPromise
|
|
26
27
|
|
|
27
28
|
// Each WebSocketStream object has an associated closed promise , which is a promise.
|
|
28
|
-
/** @type {
|
|
29
|
+
/** @type {import('../../../util/promise').DeferredPromise} */
|
|
29
30
|
#closedPromise
|
|
30
31
|
|
|
31
32
|
// Each WebSocketStream object has an associated readable stream , which is a ReadableStream .
|
|
@@ -64,6 +65,8 @@ class WebSocketStream {
|
|
|
64
65
|
this.#handler.socket.destroy()
|
|
65
66
|
},
|
|
66
67
|
onSocketClose: () => this.#onSocketClose(),
|
|
68
|
+
onPing: () => {},
|
|
69
|
+
onPong: () => {},
|
|
67
70
|
|
|
68
71
|
readyState: states.CONNECTING,
|
|
69
72
|
socket: null,
|
|
@@ -388,7 +391,7 @@ class WebSocketStream {
|
|
|
388
391
|
// 6. If the connection was closed cleanly ,
|
|
389
392
|
if (wasClean) {
|
|
390
393
|
// 6.1. Close stream ’s readable stream .
|
|
391
|
-
this.#
|
|
394
|
+
this.#readableStreamController.close()
|
|
392
395
|
|
|
393
396
|
// 6.2. Error stream ’s writable stream with an " InvalidStateError " DOMException indicating that a closed WebSocketStream cannot be written to.
|
|
394
397
|
if (!this.#writableStream.locked) {
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
isConnecting,
|
|
9
9
|
isEstablished,
|
|
10
10
|
isClosing,
|
|
11
|
+
isClosed,
|
|
11
12
|
isValidSubprotocol,
|
|
12
13
|
fireEvent,
|
|
13
14
|
utf8Decode,
|
|
@@ -21,6 +22,7 @@ const { getGlobalDispatcher } = require('../../global')
|
|
|
21
22
|
const { types } = require('node:util')
|
|
22
23
|
const { ErrorEvent, CloseEvent, createFastMessageEvent } = require('./events')
|
|
23
24
|
const { SendQueue } = require('./sender')
|
|
25
|
+
const { WebsocketFrameSend } = require('./frame')
|
|
24
26
|
const { channels } = require('../../core/diagnostics')
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -33,6 +35,8 @@ const { channels } = require('../../core/diagnostics')
|
|
|
33
35
|
* @property {(chunk: Buffer) => void} onSocketData
|
|
34
36
|
* @property {(err: Error) => void} onSocketError
|
|
35
37
|
* @property {() => void} onSocketClose
|
|
38
|
+
* @property {(body: Buffer) => void} onPing
|
|
39
|
+
* @property {(body: Buffer) => void} onPong
|
|
36
40
|
*
|
|
37
41
|
* @property {number} readyState
|
|
38
42
|
* @property {import('stream').Duplex} socket
|
|
@@ -79,6 +83,22 @@ class WebSocket extends EventTarget {
|
|
|
79
83
|
this.#handler.socket.destroy()
|
|
80
84
|
},
|
|
81
85
|
onSocketClose: () => this.#onSocketClose(),
|
|
86
|
+
onPing: (body) => {
|
|
87
|
+
if (channels.ping.hasSubscribers) {
|
|
88
|
+
channels.ping.publish({
|
|
89
|
+
payload: body,
|
|
90
|
+
websocket: this
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
onPong: (body) => {
|
|
95
|
+
if (channels.pong.hasSubscribers) {
|
|
96
|
+
channels.pong.publish({
|
|
97
|
+
payload: body,
|
|
98
|
+
websocket: this
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
},
|
|
82
102
|
|
|
83
103
|
readyState: states.CONNECTING,
|
|
84
104
|
socket: null,
|
|
@@ -460,6 +480,15 @@ class WebSocket extends EventTarget {
|
|
|
460
480
|
|
|
461
481
|
// 4. Fire an event named open at the WebSocket object.
|
|
462
482
|
fireEvent('open', this)
|
|
483
|
+
|
|
484
|
+
if (channels.open.hasSubscribers) {
|
|
485
|
+
channels.open.publish({
|
|
486
|
+
address: response.socket.address(),
|
|
487
|
+
protocol: this.#protocol,
|
|
488
|
+
extensions: this.#extensions,
|
|
489
|
+
websocket: this
|
|
490
|
+
})
|
|
491
|
+
}
|
|
463
492
|
}
|
|
464
493
|
|
|
465
494
|
#onFail (code, reason, cause) {
|
|
@@ -586,8 +615,34 @@ class WebSocket extends EventTarget {
|
|
|
586
615
|
})
|
|
587
616
|
}
|
|
588
617
|
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @param {WebSocket} ws
|
|
621
|
+
* @param {Buffer|undefined} buffer
|
|
622
|
+
*/
|
|
623
|
+
static ping (ws, buffer) {
|
|
624
|
+
if (Buffer.isBuffer(buffer)) {
|
|
625
|
+
if (buffer.length > 125) {
|
|
626
|
+
throw new TypeError('A PING frame cannot have a body larger than 125 bytes.')
|
|
627
|
+
}
|
|
628
|
+
} else if (buffer !== undefined) {
|
|
629
|
+
throw new TypeError('Expected buffer payload')
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// An endpoint MAY send a Ping frame any time after the connection is
|
|
633
|
+
// established and before the connection is closed.
|
|
634
|
+
const readyState = ws.#handler.readyState
|
|
635
|
+
|
|
636
|
+
if (isEstablished(readyState) && !isClosing(readyState) && !isClosed(readyState)) {
|
|
637
|
+
const frame = new WebsocketFrameSend(buffer)
|
|
638
|
+
ws.#handler.socket.write(frame.createFrame(opcodes.PING))
|
|
639
|
+
}
|
|
640
|
+
}
|
|
589
641
|
}
|
|
590
642
|
|
|
643
|
+
const { ping } = WebSocket
|
|
644
|
+
Reflect.deleteProperty(WebSocket, 'ping')
|
|
645
|
+
|
|
591
646
|
// https://websockets.spec.whatwg.org/#dom-websocket-connecting
|
|
592
647
|
WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING
|
|
593
648
|
// https://websockets.spec.whatwg.org/#dom-websocket-open
|
|
@@ -682,5 +737,6 @@ webidl.converters.WebSocketSendData = function (V) {
|
|
|
682
737
|
}
|
|
683
738
|
|
|
684
739
|
module.exports = {
|
|
685
|
-
WebSocket
|
|
740
|
+
WebSocket,
|
|
741
|
+
ping
|
|
686
742
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.12.0",
|
|
4
4
|
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
|
5
5
|
"homepage": "https://undici.nodejs.org",
|
|
6
6
|
"bugs": {
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"test:tdd:node-test": "borp -p \"test/node-test/**/*.js\" -w",
|
|
92
92
|
"test:typescript": "tsd && tsc test/imports/undici-import.ts --typeRoots ./types --noEmit && tsc ./types/*.d.ts --noEmit --typeRoots ./types",
|
|
93
93
|
"test:webidl": "borp -p \"test/webidl/*.js\"",
|
|
94
|
-
"test:websocket": "borp -p \"test/websocket
|
|
94
|
+
"test:websocket": "borp -p \"test/websocket/**/*.js\"",
|
|
95
95
|
"test:websocket:autobahn": "node test/autobahn/client.js",
|
|
96
96
|
"test:websocket:autobahn:report": "node test/autobahn/report.js",
|
|
97
97
|
"test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs",
|
package/types/webidl.d.ts
CHANGED
|
@@ -182,6 +182,16 @@ interface WebidlConverters {
|
|
|
182
182
|
|
|
183
183
|
['record<ByteString, ByteString>']: RecordConverter<string, string>
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* @see https://fetch.spec.whatwg.org/#requestinfo
|
|
187
|
+
*/
|
|
188
|
+
RequestInfo (V: unknown): undici.Request | string
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @see https://fetch.spec.whatwg.org/#requestinit
|
|
192
|
+
*/
|
|
193
|
+
RequestInit (V: unknown): undici.RequestInit
|
|
194
|
+
|
|
185
195
|
[Key: string]: (...args: any[]) => unknown
|
|
186
196
|
}
|
|
187
197
|
|
package/types/websocket.d.ts
CHANGED