Skip to content

Commit 57da3db

Browse files
nodejs-github-botRafaelGSS
authored andcommitted
deps: update undici to 5.9.1
PR-URL: #44319 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent c4a45a9 commit 57da3db

File tree

13 files changed

+335
-62
lines changed

13 files changed

+335
-62
lines changed

deps/undici/src/docs/api/Client.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Returns: `Client`
1818
### Parameter: `ClientOptions`
1919

2020
* **bodyTimeout** `number | null` (optional) - Default: `30e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 30 seconds.
21-
* **headersTimeout** `number | null` (optional) - Default: `30e3` - The amount of time the parser will wait to receive the complete HTTP headers. Defaults to 30 seconds.
21+
* **headersTimeout** `number | null` (optional) - Default: `30e3` - The amount of time the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 30 seconds.
2222
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout` when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
2323
* **keepAliveTimeout** `number | null` (optional) - Default: `4e3` - The timeout after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. Defaults to 4 seconds.
2424
* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `1e3` - A number subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 1 second.

deps/undici/src/docs/api/Dispatcher.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ Returns: `Boolean` - `false` if dispatcher is busy and further dispatch calls wo
199199
* **blocking** `boolean` (optional) - Default: `false` - Whether the response is expected to take a long time and would end up blocking the pipeline. When this is set to `true` further pipelining will be avoided on the same connection until headers have been received.
200200
* **upgrade** `string | null` (optional) - Default: `null` - Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`.
201201
* **bodyTimeout** `number | null` (optional) - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 30 seconds.
202-
* **headersTimeout** `number | null` (optional) - The amount of time the parser will wait to receive the complete HTTP headers. Defaults to 30 seconds.
202+
* **headersTimeout** `number | null` (optional) - The amount of time the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 30 seconds.
203203
* **throwOnError** `boolean` (optional) - Default: `false` - Whether Undici should throw an error upon receiving a 4xx or 5xx response from the server.
204204

205205
#### Parameter: `DispatchHandler`

deps/undici/src/lib/api/readable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ module.exports = class BodyReadable extends Readable {
9393
}
9494

9595
push (chunk) {
96-
if (this[kConsume] && chunk !== null) {
96+
if (this[kConsume] && chunk !== null && this.readableLength === 0) {
9797
consumePush(this[kConsume], chunk)
9898
return this[kReading] ? super.push(chunk) : true
9999
}

deps/undici/src/lib/client.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,8 +889,10 @@ function onParserTimeout (parser) {
889889

890890
/* istanbul ignore else */
891891
if (timeoutType === TIMEOUT_HEADERS) {
892-
assert(!parser.paused, 'cannot be paused while waiting for headers')
893-
util.destroy(socket, new HeadersTimeoutError())
892+
if (!socket[kWriting] || socket.writableNeedDrain || client[kRunning] > 1) {
893+
assert(!parser.paused, 'cannot be paused while waiting for headers')
894+
util.destroy(socket, new HeadersTimeoutError())
895+
}
894896
} else if (timeoutType === TIMEOUT_BODY) {
895897
if (!parser.paused) {
896898
util.destroy(socket, new BodyTimeoutError())
@@ -1641,7 +1643,18 @@ class AsyncWriter {
16411643
this.bytesWritten += len
16421644

16431645
const ret = socket.write(chunk)
1646+
16441647
request.onBodySent(chunk)
1648+
1649+
if (!ret) {
1650+
if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) {
1651+
// istanbul ignore else: only for jest
1652+
if (socket[kParser].timeout.refresh) {
1653+
socket[kParser].timeout.refresh()
1654+
}
1655+
}
1656+
}
1657+
16451658
return ret
16461659
}
16471660

deps/undici/src/lib/core/util.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,11 @@ function parseHeaders (headers, obj = {}) {
244244
const key = headers[i].toString().toLowerCase()
245245
let val = obj[key]
246246
if (!val) {
247-
obj[key] = headers[i + 1].toString()
247+
if (Array.isArray(headers[i + 1])) {
248+
obj[key] = headers[i + 1]
249+
} else {
250+
obj[key] = headers[i + 1].toString()
251+
}
248252
} else {
249253
if (!Array.isArray(val)) {
250254
val = [val]

deps/undici/src/lib/fetch/body.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@ function extractBody (object, keepalive = false) {
5757

5858
// Set Content-Type to `application/x-www-form-urlencoded;charset=UTF-8`.
5959
contentType = 'application/x-www-form-urlencoded;charset=UTF-8'
60-
} else if (isArrayBuffer(object) || ArrayBuffer.isView(object)) {
61-
// BufferSource
60+
} else if (isArrayBuffer(object)) {
61+
// BufferSource/ArrayBuffer
6262

63-
if (object instanceof DataView) {
64-
// TODO: Blob doesn't seem to work with DataView?
65-
object = object.buffer
66-
}
63+
// Set source to a copy of the bytes held by object.
64+
source = new Uint8Array(object.slice())
65+
} else if (ArrayBuffer.isView(object)) {
66+
// BufferSource/ArrayBufferView
6767

6868
// Set source to a copy of the bytes held by object.
69-
source = new Uint8Array(object)
69+
source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
7070
} else if (util.isFormDataLike(object)) {
7171
const boundary = '----formdata-undici-' + Math.random()
7272
const prefix = `--${boundary}\r\nContent-Disposition: form-data`

deps/undici/src/lib/fetch/file.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,9 @@ function processBlobParts (parts, options) {
278278
if (!element.buffer) { // ArrayBuffer
279279
bytes.push(new Uint8Array(element))
280280
} else {
281-
bytes.push(element.buffer)
281+
bytes.push(
282+
new Uint8Array(element.buffer, element.byteOffset, element.byteLength)
283+
)
282284
}
283285
} else if (isBlobLike(element)) {
284286
// 3. If element is a Blob, append the bytes it represents

deps/undici/src/lib/fetch/index.js

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const { Headers } = require('./headers')
1313
const { Request, makeRequest } = require('./request')
1414
const zlib = require('zlib')
1515
const {
16-
matchRequestIntegrity,
16+
bytesMatch,
1717
makePolicyContainer,
1818
clonePolicyContainer,
1919
requestBadPort,
@@ -34,7 +34,8 @@ const {
3434
sameOrigin,
3535
isCancelled,
3636
isAborted,
37-
isErrorLike
37+
isErrorLike,
38+
fullyReadBody
3839
} = require('./util')
3940
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
4041
const assert = require('assert')
@@ -724,7 +725,7 @@ async function mainFetch (fetchParams, recursive = false) {
724725
const processBody = (bytes) => {
725726
// 1. If bytes do not match request’s integrity metadata,
726727
// then run processBodyError and abort these steps. [SRI]
727-
if (!matchRequestIntegrity(request, bytes)) {
728+
if (!bytesMatch(bytes, request.integrity)) {
728729
processBodyError('integrity mismatch')
729730
return
730731
}
@@ -738,11 +739,7 @@ async function mainFetch (fetchParams, recursive = false) {
738739
}
739740

740741
// 4. Fully read response’s body given processBody and processBodyError.
741-
try {
742-
processBody(await response.arrayBuffer())
743-
} catch (err) {
744-
processBodyError(err)
745-
}
742+
await fullyReadBody(response.body, processBody, processBodyError)
746743
} else {
747744
// 21. Otherwise, run fetch finale given fetchParams and response.
748745
fetchFinale(fetchParams, response)
@@ -974,11 +971,7 @@ async function fetchFinale (fetchParams, response) {
974971
} else {
975972
// 4. Otherwise, fully read response’s body given processBody, processBodyError,
976973
// and fetchParams’s task destination.
977-
try {
978-
processBody(await response.body.stream.arrayBuffer())
979-
} catch (err) {
980-
processBodyError(err)
981-
}
974+
await fullyReadBody(response.body, processBody, processBodyError)
982975
}
983976
}
984977
}

deps/undici/src/lib/fetch/request.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
const { extractBody, mixinBody, cloneBody } = require('./body')
66
const { Headers, fill: fillHeaders, HeadersList } = require('./headers')
7+
const { FinalizationRegistry } = require('../compat/dispatcher-weakref')()
78
const util = require('../core/util')
89
const {
910
isValidHTTPToken,
@@ -914,7 +915,10 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([
914915
{
915916
key: 'signal',
916917
converter: webidl.nullableConverter(
917-
webidl.converters.AbortSignal
918+
(signal) => webidl.converters.AbortSignal(
919+
signal,
920+
{ strict: false }
921+
)
918922
)
919923
},
920924
{

deps/undici/src/lib/fetch/util.js

Lines changed: 168 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,20 @@ const { redirectStatus } = require('./constants')
44
const { performance } = require('perf_hooks')
55
const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
66
const assert = require('assert')
7+
const { isUint8Array } = require('util/types')
78

89
let File
910

11+
// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable
12+
/** @type {import('crypto')|undefined} */
13+
let crypto
14+
15+
try {
16+
crypto = require('crypto')
17+
} catch {
18+
19+
}
20+
1021
// https://fetch.spec.whatwg.org/#block-bad-port
1122
const badPorts = [
1223
'1', '7', '9', '11', '13', '15', '17', '19', '20', '21', '22', '23', '25', '37', '42', '43', '53', '69', '77', '79',
@@ -339,10 +350,116 @@ function determineRequestsReferrer (request) {
339350
return 'no-referrer'
340351
}
341352

342-
function matchRequestIntegrity (request, bytes) {
353+
/**
354+
* @see https://w3c.github.io/webappsec-subresource-integrity/#does-response-match-metadatalist
355+
* @param {Uint8Array} bytes
356+
* @param {string} metadataList
357+
*/
358+
function bytesMatch (bytes, metadataList) {
359+
// If node is not built with OpenSSL support, we cannot check
360+
// a request's integrity, so allow it by default (the spec will
361+
// allow requests if an invalid hash is given, as precedence).
362+
/* istanbul ignore if: only if node is built with --without-ssl */
363+
if (crypto === undefined) {
364+
return true
365+
}
366+
367+
// 1. Let parsedMetadata be the result of parsing metadataList.
368+
const parsedMetadata = parseMetadata(metadataList)
369+
370+
// 2. If parsedMetadata is no metadata, return true.
371+
if (parsedMetadata === 'no metadata') {
372+
return true
373+
}
374+
375+
// 3. If parsedMetadata is the empty set, return true.
376+
if (parsedMetadata.length === 0) {
377+
return true
378+
}
379+
380+
// 4. Let metadata be the result of getting the strongest
381+
// metadata from parsedMetadata.
382+
// Note: this will only work for SHA- algorithms and it's lazy *at best*.
383+
const metadata = parsedMetadata.sort((c, d) => d.algo.localeCompare(c.algo))
384+
385+
// 5. For each item in metadata:
386+
for (const item of metadata) {
387+
// 1. Let algorithm be the alg component of item.
388+
const algorithm = item.algo
389+
390+
// 2. Let expectedValue be the val component of item.
391+
const expectedValue = item.hash
392+
393+
// 3. Let actualValue be the result of applying algorithm to bytes.
394+
// Note: "applying algorithm to bytes" converts the result to base64
395+
const actualValue = crypto.createHash(algorithm).update(bytes).digest('base64')
396+
397+
// 4. If actualValue is a case-sensitive match for expectedValue,
398+
// return true.
399+
if (actualValue === expectedValue) {
400+
return true
401+
}
402+
}
403+
404+
// 6. Return false.
343405
return false
344406
}
345407

408+
// https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options
409+
// hash-algo is defined in Content Security Policy 2 Section 4.2
410+
// base64-value is similary defined there
411+
// VCHAR is defined https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
412+
const parseHashWithOptions = /((?<algo>sha256|sha384|sha512)-(?<hash>[A-z0-9+/]{1}.*={1,2}))( +[\x21-\x7e]?)?/i
413+
414+
/**
415+
* @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
416+
* @param {string} metadata
417+
*/
418+
function parseMetadata (metadata) {
419+
// 1. Let result be the empty set.
420+
/** @type {{ algo: string, hash: string }[]} */
421+
const result = []
422+
423+
// 2. Let empty be equal to true.
424+
let empty = true
425+
426+
const supportedHashes = crypto.getHashes()
427+
428+
// 3. For each token returned by splitting metadata on spaces:
429+
for (const token of metadata.split(' ')) {
430+
// 1. Set empty to false.
431+
empty = false
432+
433+
// 2. Parse token as a hash-with-options.
434+
const parsedToken = parseHashWithOptions.exec(token)
435+
436+
// 3. If token does not parse, continue to the next token.
437+
if (parsedToken === null || parsedToken.groups === undefined) {
438+
// Note: Chromium blocks the request at this point, but Firefox
439+
// gives a warning that an invalid integrity was given. The
440+
// correct behavior is to ignore these, and subsequently not
441+
// check the integrity of the resource.
442+
continue
443+
}
444+
445+
// 4. Let algorithm be the hash-algo component of token.
446+
const algorithm = parsedToken.groups.algo
447+
448+
// 5. If algorithm is a hash function recognized by the user
449+
// agent, add the parsed token to result.
450+
if (supportedHashes.includes(algorithm.toLowerCase())) {
451+
result.push(parsedToken.groups)
452+
}
453+
}
454+
455+
// 4. Return no metadata if empty is true, otherwise return result.
456+
if (empty === true) {
457+
return 'no metadata'
458+
}
459+
460+
return result
461+
}
462+
346463
// https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request
347464
function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) {
348465
// TODO
@@ -438,6 +555,53 @@ function makeIterator (iterator, name) {
438555
return Object.setPrototypeOf({}, i)
439556
}
440557

558+
/**
559+
* @see https://fetch.spec.whatwg.org/#body-fully-read
560+
*/
561+
async function fullyReadBody (body, processBody, processBodyError) {
562+
// 1. If taskDestination is null, then set taskDestination to
563+
// the result of starting a new parallel queue.
564+
565+
// 2. Let promise be the result of fully reading body as promise
566+
// given body.
567+
try {
568+
/** @type {Uint8Array[]} */
569+
const chunks = []
570+
let length = 0
571+
572+
const reader = body.stream.getReader()
573+
574+
while (true) {
575+
const { done, value } = await reader.read()
576+
577+
if (done === true) {
578+
break
579+
}
580+
581+
// read-loop chunk steps
582+
assert(isUint8Array(value))
583+
584+
chunks.push(value)
585+
length += value.byteLength
586+
}
587+
588+
// 3. Let fulfilledSteps given a byte sequence bytes be to queue
589+
// a fetch task to run processBody given bytes, with
590+
// taskDestination.
591+
const fulfilledSteps = (bytes) => queueMicrotask(() => {
592+
processBody(bytes)
593+
})
594+
595+
fulfilledSteps(Buffer.concat(chunks, length))
596+
} catch (err) {
597+
// 4. Let rejectedSteps be to queue a fetch task to run
598+
// processBodyError, with taskDestination.
599+
queueMicrotask(() => processBodyError(err))
600+
}
601+
602+
// 5. React to promise with fulfilledSteps and rejectedSteps.
603+
}
604+
441605
/**
442606
* Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0.
443607
*/
@@ -451,7 +615,6 @@ module.exports = {
451615
toUSVString,
452616
tryUpgradeRequestToAPotentiallyTrustworthyURL,
453617
coarsenedSharedCurrentTime,
454-
matchRequestIntegrity,
455618
determineRequestsReferrer,
456619
makePolicyContainer,
457620
clonePolicyContainer,
@@ -477,5 +640,7 @@ module.exports = {
477640
isValidHeaderName,
478641
isValidHeaderValue,
479642
hasOwn,
480-
isErrorLike
643+
isErrorLike,
644+
fullyReadBody,
645+
bytesMatch
481646
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy