undici 7.2.1 → 7.2.3
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/lib/core/util.js +17 -12
- package/lib/interceptor/dns.js +77 -24
- package/lib/web/fetch/body.js +9 -1
- package/lib/web/websocket/connection.js +26 -1
- package/lib/web/websocket/receiver.js +1 -1
- package/lib/web/websocket/stream/websocketstream.js +2 -2
- package/lib/web/websocket/util.js +0 -27
- package/lib/web/websocket/websocket.js +1 -2
- package/package.json +1 -1
package/lib/core/util.js
CHANGED
|
@@ -600,20 +600,25 @@ function ReadableStreamFrom (iterable) {
|
|
|
600
600
|
async start () {
|
|
601
601
|
iterator = iterable[Symbol.asyncIterator]()
|
|
602
602
|
},
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
603
|
+
pull (controller) {
|
|
604
|
+
async function pull () {
|
|
605
|
+
const { done, value } = await iterator.next()
|
|
606
|
+
if (done) {
|
|
607
|
+
queueMicrotask(() => {
|
|
608
|
+
controller.close()
|
|
609
|
+
controller.byobRequest?.respond(0)
|
|
610
|
+
})
|
|
611
|
+
} else {
|
|
612
|
+
const buf = Buffer.isBuffer(value) ? value : Buffer.from(value)
|
|
613
|
+
if (buf.byteLength) {
|
|
614
|
+
controller.enqueue(new Uint8Array(buf))
|
|
615
|
+
} else {
|
|
616
|
+
return await pull()
|
|
617
|
+
}
|
|
614
618
|
}
|
|
615
619
|
}
|
|
616
|
-
|
|
620
|
+
|
|
621
|
+
return pull()
|
|
617
622
|
},
|
|
618
623
|
async cancel () {
|
|
619
624
|
await iterator.return()
|
package/lib/interceptor/dns.js
CHANGED
|
@@ -32,7 +32,7 @@ class DNSInstance {
|
|
|
32
32
|
|
|
33
33
|
// If full, we just return the origin
|
|
34
34
|
if (ips == null && this.full) {
|
|
35
|
-
cb(null, origin
|
|
35
|
+
cb(null, origin)
|
|
36
36
|
return
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -74,9 +74,9 @@ class DNSInstance {
|
|
|
74
74
|
|
|
75
75
|
cb(
|
|
76
76
|
null,
|
|
77
|
-
`${origin.protocol}//${
|
|
77
|
+
new URL(`${origin.protocol}//${
|
|
78
78
|
ip.family === 6 ? `[${ip.address}]` : ip.address
|
|
79
|
-
}${port}`
|
|
79
|
+
}${port}`)
|
|
80
80
|
)
|
|
81
81
|
})
|
|
82
82
|
} else {
|
|
@@ -105,9 +105,9 @@ class DNSInstance {
|
|
|
105
105
|
|
|
106
106
|
cb(
|
|
107
107
|
null,
|
|
108
|
-
`${origin.protocol}//${
|
|
108
|
+
new URL(`${origin.protocol}//${
|
|
109
109
|
ip.family === 6 ? `[${ip.address}]` : ip.address
|
|
110
|
-
}${port}`
|
|
110
|
+
}${port}`)
|
|
111
111
|
)
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -192,6 +192,38 @@ class DNSInstance {
|
|
|
192
192
|
return ip
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
pickFamily (origin, ipFamily) {
|
|
196
|
+
const records = this.#records.get(origin.hostname)?.records
|
|
197
|
+
if (!records) {
|
|
198
|
+
return null
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const family = records[ipFamily]
|
|
202
|
+
if (!family) {
|
|
203
|
+
return null
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (family.offset == null || family.offset === maxInt) {
|
|
207
|
+
family.offset = 0
|
|
208
|
+
} else {
|
|
209
|
+
family.offset++
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const position = family.offset % family.ips.length
|
|
213
|
+
const ip = family.ips[position] ?? null
|
|
214
|
+
if (ip == null) {
|
|
215
|
+
return ip
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (Date.now() - ip.timestamp > ip.ttl) { // record TTL is already in ms
|
|
219
|
+
// We delete expired records
|
|
220
|
+
// It is possible that they have different TTL, so we manage them individually
|
|
221
|
+
family.ips.splice(position, 1)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return ip
|
|
225
|
+
}
|
|
226
|
+
|
|
195
227
|
setRecords (origin, addresses) {
|
|
196
228
|
const timestamp = Date.now()
|
|
197
229
|
const records = { records: { 4: null, 6: null } }
|
|
@@ -228,10 +260,13 @@ class DNSDispatchHandler extends DecoratorHandler {
|
|
|
228
260
|
#dispatch = null
|
|
229
261
|
#origin = null
|
|
230
262
|
#controller = null
|
|
263
|
+
#newOrigin = null
|
|
264
|
+
#firstTry = true
|
|
231
265
|
|
|
232
|
-
constructor (state, { origin, handler, dispatch }, opts) {
|
|
266
|
+
constructor (state, { origin, handler, dispatch, newOrigin }, opts) {
|
|
233
267
|
super(handler)
|
|
234
268
|
this.#origin = origin
|
|
269
|
+
this.#newOrigin = newOrigin
|
|
235
270
|
this.#opts = { ...opts }
|
|
236
271
|
this.#state = state
|
|
237
272
|
this.#dispatch = dispatch
|
|
@@ -242,21 +277,36 @@ class DNSDispatchHandler extends DecoratorHandler {
|
|
|
242
277
|
case 'ETIMEDOUT':
|
|
243
278
|
case 'ECONNREFUSED': {
|
|
244
279
|
if (this.#state.dualStack) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
280
|
+
if (!this.#firstTry) {
|
|
281
|
+
super.onResponseError(controller, err)
|
|
282
|
+
return
|
|
283
|
+
}
|
|
284
|
+
this.#firstTry = false
|
|
285
|
+
|
|
286
|
+
// Pick an ip address from the other family
|
|
287
|
+
const otherFamily = this.#newOrigin.hostname[0] === '[' ? 4 : 6
|
|
288
|
+
const ip = this.#state.pickFamily(this.#origin, otherFamily)
|
|
289
|
+
if (ip == null) {
|
|
290
|
+
super.onResponseError(controller, err)
|
|
291
|
+
return
|
|
292
|
+
}
|
|
256
293
|
|
|
257
|
-
|
|
258
|
-
|
|
294
|
+
let port
|
|
295
|
+
if (typeof ip.port === 'number') {
|
|
296
|
+
port = `:${ip.port}`
|
|
297
|
+
} else if (this.#origin.port !== '') {
|
|
298
|
+
port = `:${this.#origin.port}`
|
|
299
|
+
} else {
|
|
300
|
+
port = ''
|
|
301
|
+
}
|
|
259
302
|
|
|
303
|
+
const dispatchOpts = {
|
|
304
|
+
...this.#opts,
|
|
305
|
+
origin: `${this.#origin.protocol}//${
|
|
306
|
+
ip.family === 6 ? `[${ip.address}]` : ip.address
|
|
307
|
+
}${port}`
|
|
308
|
+
}
|
|
309
|
+
this.#dispatch(dispatchOpts, this)
|
|
260
310
|
return
|
|
261
311
|
}
|
|
262
312
|
|
|
@@ -266,7 +316,8 @@ class DNSDispatchHandler extends DecoratorHandler {
|
|
|
266
316
|
}
|
|
267
317
|
case 'ENOTFOUND':
|
|
268
318
|
this.#state.deleteRecords(this.#origin)
|
|
269
|
-
|
|
319
|
+
super.onResponseError(controller, err)
|
|
320
|
+
break
|
|
270
321
|
default:
|
|
271
322
|
super.onResponseError(controller, err)
|
|
272
323
|
break
|
|
@@ -356,11 +407,10 @@ module.exports = interceptorOpts => {
|
|
|
356
407
|
return handler.onResponseError(null, err)
|
|
357
408
|
}
|
|
358
409
|
|
|
359
|
-
|
|
360
|
-
dispatchOpts = {
|
|
410
|
+
const dispatchOpts = {
|
|
361
411
|
...origDispatchOpts,
|
|
362
412
|
servername: origin.hostname, // For SNI on TLS
|
|
363
|
-
origin: newOrigin,
|
|
413
|
+
origin: newOrigin.origin,
|
|
364
414
|
headers: {
|
|
365
415
|
host: origin.host,
|
|
366
416
|
...origDispatchOpts.headers
|
|
@@ -369,7 +419,10 @@ module.exports = interceptorOpts => {
|
|
|
369
419
|
|
|
370
420
|
dispatch(
|
|
371
421
|
dispatchOpts,
|
|
372
|
-
instance.getHandler(
|
|
422
|
+
instance.getHandler(
|
|
423
|
+
{ origin, dispatch, handler, newOrigin },
|
|
424
|
+
origDispatchOpts
|
|
425
|
+
)
|
|
373
426
|
)
|
|
374
427
|
})
|
|
375
428
|
|
package/lib/web/fetch/body.js
CHANGED
|
@@ -17,6 +17,14 @@ const { isErrored, isDisturbed } = require('node:stream')
|
|
|
17
17
|
const { isArrayBuffer } = require('node:util/types')
|
|
18
18
|
const { serializeAMimeType } = require('./data-url')
|
|
19
19
|
const { multipartFormDataParser } = require('./formdata-parser')
|
|
20
|
+
let random
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const crypto = require('node:crypto')
|
|
24
|
+
random = (max) => crypto.randomInt(0, max)
|
|
25
|
+
} catch {
|
|
26
|
+
random = (max) => Math.floor(Math.random(max))
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
const textEncoder = new TextEncoder()
|
|
22
30
|
function noop () {}
|
|
@@ -110,7 +118,7 @@ function extractBody (object, keepalive = false) {
|
|
|
110
118
|
// Set source to a copy of the bytes held by object.
|
|
111
119
|
source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
|
|
112
120
|
} else if (webidl.is.FormData(object)) {
|
|
113
|
-
const boundary = `----formdata-undici-0${`${
|
|
121
|
+
const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
|
|
114
122
|
const prefix = `--${boundary}\r\nContent-Disposition: form-data`
|
|
115
123
|
|
|
116
124
|
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = require('./constants')
|
|
4
|
-
const {
|
|
4
|
+
const { parseExtensions, isClosed, isClosing, isEstablished, validateCloseCodeAndReason } = require('./util')
|
|
5
5
|
const { channels } = require('../../core/diagnostics')
|
|
6
6
|
const { makeRequest } = require('../fetch/request')
|
|
7
7
|
const { fetching } = require('../fetch/index')
|
|
@@ -294,7 +294,32 @@ function closeWebSocketConnection (object, code, reason, validate = false) {
|
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
/**
|
|
298
|
+
* @param {import('./websocket').Handler} handler
|
|
299
|
+
* @param {number} code
|
|
300
|
+
* @param {string|undefined} reason
|
|
301
|
+
* @returns {void}
|
|
302
|
+
*/
|
|
303
|
+
function failWebsocketConnection (handler, code, reason) {
|
|
304
|
+
// If _The WebSocket Connection is Established_ prior to the point where
|
|
305
|
+
// the endpoint is required to _Fail the WebSocket Connection_, the
|
|
306
|
+
// endpoint SHOULD send a Close frame with an appropriate status code
|
|
307
|
+
// (Section 7.4) before proceeding to _Close the WebSocket Connection_.
|
|
308
|
+
if (isEstablished(handler.readyState)) {
|
|
309
|
+
closeWebSocketConnection(handler, code, reason, false)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
handler.controller.abort()
|
|
313
|
+
|
|
314
|
+
if (handler.socket?.destroyed === false) {
|
|
315
|
+
handler.socket.destroy()
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
handler.onFail(code, reason)
|
|
319
|
+
}
|
|
320
|
+
|
|
297
321
|
module.exports = {
|
|
298
322
|
establishWebSocketConnection,
|
|
323
|
+
failWebsocketConnection,
|
|
299
324
|
closeWebSocketConnection
|
|
300
325
|
}
|
|
@@ -7,13 +7,13 @@ const { channels } = require('../../core/diagnostics')
|
|
|
7
7
|
const {
|
|
8
8
|
isValidStatusCode,
|
|
9
9
|
isValidOpcode,
|
|
10
|
-
failWebsocketConnection,
|
|
11
10
|
websocketMessageReceived,
|
|
12
11
|
utf8Decode,
|
|
13
12
|
isControlFrame,
|
|
14
13
|
isTextBinaryFrame,
|
|
15
14
|
isContinuationFrame
|
|
16
15
|
} = require('./util')
|
|
16
|
+
const { failWebsocketConnection } = require('./connection')
|
|
17
17
|
const { WebsocketFrameSend } = require('./frame')
|
|
18
18
|
const { PerMessageDeflate } = require('./permessage-deflate')
|
|
19
19
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const { createDeferredPromise, environmentSettingsObject } = require('../../fetch/util')
|
|
4
4
|
const { states, opcodes, sentCloseFrameState } = require('../constants')
|
|
5
5
|
const { webidl } = require('../../fetch/webidl')
|
|
6
|
-
const { getURLRecord, isValidSubprotocol, isEstablished,
|
|
7
|
-
const { establishWebSocketConnection, closeWebSocketConnection } = require('../connection')
|
|
6
|
+
const { getURLRecord, isValidSubprotocol, isEstablished, utf8Decode } = require('../util')
|
|
7
|
+
const { establishWebSocketConnection, failWebsocketConnection, closeWebSocketConnection } = require('../connection')
|
|
8
8
|
const { types } = require('node:util')
|
|
9
9
|
const { channels } = require('../../../core/diagnostics')
|
|
10
10
|
const { WebsocketFrameSend } = require('../frame')
|
|
@@ -156,32 +156,6 @@ function isValidStatusCode (code) {
|
|
|
156
156
|
return code >= 3000 && code <= 4999
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
/**
|
|
160
|
-
* @param {import('./websocket').Handler} handler
|
|
161
|
-
* @param {number} code
|
|
162
|
-
* @param {string|undefined} reason
|
|
163
|
-
* @returns {void}
|
|
164
|
-
*/
|
|
165
|
-
function failWebsocketConnection (handler, code, reason) {
|
|
166
|
-
// If _The WebSocket Connection is Established_ prior to the point where
|
|
167
|
-
// the endpoint is required to _Fail the WebSocket Connection_, the
|
|
168
|
-
// endpoint SHOULD send a Close frame with an appropriate status code
|
|
169
|
-
// (Section 7.4) before proceeding to _Close the WebSocket Connection_.
|
|
170
|
-
if (isEstablished(handler.readyState)) {
|
|
171
|
-
// avoid circular require - performance is not important here
|
|
172
|
-
const { closeWebSocketConnection } = require('./connection')
|
|
173
|
-
closeWebSocketConnection(handler, code, reason, false)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
handler.controller.abort()
|
|
177
|
-
|
|
178
|
-
if (handler.socket?.destroyed === false) {
|
|
179
|
-
handler.socket.destroy()
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
handler.onFail(code, reason)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
159
|
/**
|
|
186
160
|
* @see https://datatracker.ietf.org/doc/html/rfc6455#section-5.5
|
|
187
161
|
* @param {number} opcode
|
|
@@ -350,7 +324,6 @@ module.exports = {
|
|
|
350
324
|
fireEvent,
|
|
351
325
|
isValidSubprotocol,
|
|
352
326
|
isValidStatusCode,
|
|
353
|
-
failWebsocketConnection,
|
|
354
327
|
websocketMessageReceived,
|
|
355
328
|
utf8Decode,
|
|
356
329
|
isControlFrame,
|
|
@@ -10,12 +10,11 @@ const {
|
|
|
10
10
|
isClosing,
|
|
11
11
|
isValidSubprotocol,
|
|
12
12
|
fireEvent,
|
|
13
|
-
failWebsocketConnection,
|
|
14
13
|
utf8Decode,
|
|
15
14
|
toArrayBuffer,
|
|
16
15
|
getURLRecord
|
|
17
16
|
} = require('./util')
|
|
18
|
-
const { establishWebSocketConnection, closeWebSocketConnection } = require('./connection')
|
|
17
|
+
const { establishWebSocketConnection, closeWebSocketConnection, failWebsocketConnection } = require('./connection')
|
|
19
18
|
const { ByteParser } = require('./receiver')
|
|
20
19
|
const { kEnumerableProperty } = require('../../core/util')
|
|
21
20
|
const { getGlobalDispatcher } = require('../../global')
|