Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deps: update undici to 5.19.1 #46634

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion deps/undici/src/docs/api/MockPool.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ Returns: `MockInterceptor` corresponding to the input options.

We can define the behaviour of an intercepted request with the following options.

* **reply** `(statusCode: number, replyData: string | Buffer | object | MockInterceptor.MockResponseDataHandler, responseOptions?: MockResponseOptions) => MockScope` - define a reply for a matching request. You can define this as a callback to read incoming request data. Default for `responseOptions` is `{}`.
* **reply** `(statusCode: number, replyData: string | Buffer | object | MockInterceptor.MockResponseDataHandler, responseOptions?: MockResponseOptions) => MockScope` - define a reply for a matching request. You can define the replyData as a callback to read incoming request data. Default for `responseOptions` is `{}`.
* **reply** `(callback: MockInterceptor.MockReplyOptionsCallback) => MockScope` - define a reply for a matching request, allowing dynamic mocking of all reply options rather than just the data.
* **replyWithError** `(error: Error) => MockScope` - define an error for a matching request to throw.
* **defaultReplyHeaders** `(headers: Record<string, string>) => MockInterceptor` - define default headers to be included in subsequent replies. These are in addition to headers on a specific reply.
* **defaultReplyTrailers** `(trailers: Record<string, string>) => MockInterceptor` - define default trailers to be included in subsequent replies. These are in addition to trailers on a specific reply.
Expand Down
3 changes: 2 additions & 1 deletion deps/undici/src/lib/cookies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ function getSetCookies (headers) {
return []
}

return cookies.map((pair) => parseSetCookie(pair[1]))
// In older versions of undici, cookies is a list of name:value.
return cookies.map((pair) => parseSetCookie(Array.isArray(pair) ? pair[1] : pair))
}

/**
Expand Down
3 changes: 3 additions & 0 deletions deps/undici/src/lib/core/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ function processHeader (request, key, val) {
key.length === 4 &&
key.toLowerCase() === 'host'
) {
if (headerCharRegex.exec(val) !== null) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
// Consumed by Client
request.host = val
} else if (
Expand Down
23 changes: 20 additions & 3 deletions deps/undici/src/lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,25 +213,42 @@ function parseHeaders (headers, obj = {}) {
for (let i = 0; i < headers.length; i += 2) {
const key = headers[i].toString().toLowerCase()
let val = obj[key]

const encoding = key.length === 19 && key === 'content-disposition'
? 'latin1'
: 'utf8'

if (!val) {
if (Array.isArray(headers[i + 1])) {
obj[key] = headers[i + 1]
} else {
obj[key] = headers[i + 1].toString()
obj[key] = headers[i + 1].toString(encoding)
}
} else {
if (!Array.isArray(val)) {
val = [val]
obj[key] = val
}
val.push(headers[i + 1].toString())
val.push(headers[i + 1].toString(encoding))
}
}
return obj
}

function parseRawHeaders (headers) {
return headers.map(header => header.toString())
const ret = []
for (let n = 0; n < headers.length; n += 2) {
const key = headers[n + 0].toString()

const encoding = key.length === 19 && key.toLowerCase() === 'content-disposition'
? 'latin1'
: 'utf8'

const val = headers[n + 1].toString(encoding)

ret.push(key, val)
}
return ret
}

function isBuffer (buffer) {
Expand Down
83 changes: 71 additions & 12 deletions deps/undici/src/lib/fetch/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
isValidHeaderValue
} = require('./util')
const { webidl } = require('./webidl')
const assert = require('assert')

const kHeadersMap = Symbol('headers map')
const kHeadersSortedMap = Symbol('headers map sorted')
Expand All @@ -23,10 +24,12 @@ function headerValueNormalize (potentialValue) {
// To normalize a byte sequence potentialValue, remove
// any leading and trailing HTTP whitespace bytes from
// potentialValue.
return potentialValue.replace(
/^[\r\n\t ]+|[\r\n\t ]+$/g,
''
)

// Trimming the end with `.replace()` and a RegExp is typically subject to
// ReDoS. This is safer and faster.
let i = potentialValue.length
while (/[\r\n\t ]/.test(potentialValue.charAt(--i)));
return potentialValue.slice(0, i + 1).replace(/^[\r\n\t ]+/, '')
}

function fill (headers, object) {
Expand Down Expand Up @@ -115,7 +118,7 @@ class HeadersList {

if (lowercaseName === 'set-cookie') {
this.cookies ??= []
this.cookies.push([name, value])
this.cookies.push(value)
}
}

Expand All @@ -125,7 +128,7 @@ class HeadersList {
const lowercaseName = name.toLowerCase()

if (lowercaseName === 'set-cookie') {
this.cookies = [[name, value]]
this.cookies = [value]
}

// 1. If list contains name, then set the value of
Expand Down Expand Up @@ -383,18 +386,74 @@ class Headers {
return this[kHeadersList].set(name, value)
}

// https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
getSetCookie () {
webidl.brandCheck(this, Headers)

// 1. If this’s header list does not contain `Set-Cookie`, then return « ».
// 2. Return the values of all headers in this’s header list whose name is
// a byte-case-insensitive match for `Set-Cookie`, in order.

const list = this[kHeadersList].cookies

if (list) {
return [...list]
}

return []
}

// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
get [kHeadersSortedMap] () {
if (!this[kHeadersList][kHeadersSortedMap]) {
this[kHeadersList][kHeadersSortedMap] = new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1))
if (this[kHeadersList][kHeadersSortedMap]) {
return this[kHeadersList][kHeadersSortedMap]
}
return this[kHeadersList][kHeadersSortedMap]

// 1. Let headers be an empty list of headers with the key being the name
// and value the value.
const headers = []

// 2. Let names be the result of convert header names to a sorted-lowercase
// set with all the names of the headers in list.
const names = [...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)
const cookies = this[kHeadersList].cookies

// 3. For each name of names:
for (const [name, value] of names) {
// 1. If name is `set-cookie`, then:
if (name === 'set-cookie') {
// 1. Let values be a list of all values of headers in list whose name
// is a byte-case-insensitive match for name, in order.

// 2. For each value of values:
// 1. Append (name, value) to headers.
for (const value of cookies) {
headers.push([name, value])
}
} else {
// 2. Otherwise:

// 1. Let value be the result of getting name from list.

// 2. Assert: value is non-null.
assert(value !== null)

// 3. Append (name, value) to headers.
headers.push([name, value])
}
}

this[kHeadersList][kHeadersSortedMap] = headers

// 4. Return headers.
return headers
}

keys () {
webidl.brandCheck(this, Headers)

return makeIterator(
() => [...this[kHeadersSortedMap].entries()],
() => [...this[kHeadersSortedMap].values()],
'Headers',
'key'
)
Expand All @@ -404,7 +463,7 @@ class Headers {
webidl.brandCheck(this, Headers)

return makeIterator(
() => [...this[kHeadersSortedMap].entries()],
() => [...this[kHeadersSortedMap].values()],
'Headers',
'value'
)
Expand All @@ -414,7 +473,7 @@ class Headers {
webidl.brandCheck(this, Headers)

return makeIterator(
() => [...this[kHeadersSortedMap].entries()],
() => [...this[kHeadersSortedMap].values()],
'Headers',
'key+value'
)
Expand Down
6 changes: 6 additions & 0 deletions deps/undici/src/lib/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const { getGlobalOrigin } = require('./global')
const { URLSerializer } = require('./dataURL')
const { kHeadersList } = require('../core/symbols')
const assert = require('assert')
const { setMaxListeners, getEventListeners, defaultMaxListeners } = require('events')

let TransformStream = globalThis.TransformStream

Expand Down Expand Up @@ -352,6 +353,11 @@ class Request {
const abort = function () {
acRef.deref()?.abort(this.reason)
}

if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) {
setMaxListeners(100, signal)
}

signal.addEventListener('abort', abort, { once: true })
requestFinalizer.register(this, { signal, abort })
}
Expand Down
6 changes: 5 additions & 1 deletion deps/undici/src/lib/mock/mock-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ function buildKey (opts) {
}

function generateKeyValues (data) {
return Object.entries(data).reduce((keyValuePairs, [key, value]) => [...keyValuePairs, key, value], [])
return Object.entries(data).reduce((keyValuePairs, [key, value]) => [
...keyValuePairs,
Buffer.from(`${key}`),
Array.isArray(value) ? value.map(x => Buffer.from(`${x}`)) : Buffer.from(`${value}`)
], [])
}

/**
Expand Down
2 changes: 1 addition & 1 deletion deps/undici/src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "undici",
"version": "5.18.0",
"version": "5.19.1",
"description": "An HTTP/1.1 client, written from scratch for Node.js",
"homepage": "https://undici.nodejs.org",
"bugs": {
Expand Down
2 changes: 2 additions & 0 deletions deps/undici/src/types/connector.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ declare namespace buildConnector {
socketPath?: string | null;
timeout?: number | null;
port?: number;
keepAlive?: boolean | null;
keepAliveInitialDelay?: number | null;
}

export interface Options {
Expand Down
1 change: 1 addition & 0 deletions deps/undici/src/types/fetch.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export declare class Headers implements SpecIterable<[string, string]> {
readonly get: (name: string) => string | null
readonly has: (name: string) => boolean
readonly set: (name: string, value: string) => void
readonly getSetCookie: () => string[]
readonly forEach: (
callbackfn: (value: string, key: string, iterable: Headers) => void,
thisArg?: unknown
Expand Down