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.18.0 #46502

Closed
wants to merge 2 commits 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions deps/undici/src/docs/api/Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Furthermore, the following options can be passed:
* **maxCachedSessions** `number | null` (optional) - Default: `100` - Maximum number of TLS cached sessions. Use 0 to disable TLS session caching. Default: 100.
* **timeout** `number | null` (optional) - Default `10e3`
* **servername** `string | null` (optional)
* **keepAlive** `boolean | null` (optional) - Default: `true` - TCP keep-alive enabled
* **keepAliveInitialDelay** `number | null` (optional) - Default: `60000` - TCP keep-alive interval for the socket in milliseconds

### Example - Basic Client instantiation

Expand Down
57 changes: 57 additions & 0 deletions deps/undici/src/docs/api/ContentType.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# MIME Type Parsing

## `MIMEType` interface

* **type** `string`
* **subtype** `string`
* **parameters** `Map<string, string>`
* **essence** `string`

## `parseMIMEType(input)`

Implements [parse a MIME type](https://mimesniff.spec.whatwg.org/#parse-a-mime-type).

Parses a MIME type, returning its type, subtype, and any associated parameters. If the parser can't parse an input it returns the string literal `'failure'`.

```js
import { parseMIMEType } from 'undici'

parseMIMEType('text/html; charset=gbk')
// {
// type: 'text',
// subtype: 'html',
// parameters: Map(1) { 'charset' => 'gbk' },
// essence: 'text/html'
// }
```

Arguments:

* **input** `string`

Returns: `MIMEType|'failure'`

## `serializeAMimeType(input)`

Implements [serialize a MIME type](https://mimesniff.spec.whatwg.org/#serialize-a-mime-type).

Serializes a MIMEType object.

```js
import { serializeAMimeType } from 'undici'

serializeAMimeType({
type: 'text',
subtype: 'html',
parameters: new Map([['charset', 'gbk']]),
essence: 'text/html'
})
// text/html;charset=gbk

```

Arguments:

* **mimeType** `MIMEType`

Returns: `string`
14 changes: 7 additions & 7 deletions deps/undici/src/docs/api/Dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Returns: `void | Promise<ConnectData>` - Only returns a `Promise` if no `callbac
#### Parameter: `ConnectData`

* **statusCode** `number`
* **headers** `http.IncomingHttpHeaders`
* **headers** `Record<string, string | string[]>`
* **socket** `stream.Duplex`
* **opaque** `unknown`

Expand Down Expand Up @@ -383,7 +383,7 @@ Extends: [`RequestOptions`](#parameter-requestoptions)
#### Parameter: PipelineHandlerData

* **statusCode** `number`
* **headers** `IncomingHttpHeaders`
* **headers** `Record<string, string | string[]>`
* **opaque** `unknown`
* **body** `stream.Readable`
* **context** `object`
Expand Down Expand Up @@ -477,7 +477,7 @@ The `RequestOptions.method` property should not be value `'CONNECT'`.
#### Parameter: `ResponseData`

* **statusCode** `number`
* **headers** `http.IncomingHttpHeaders` - Note that all header keys are lower-cased, e. g. `content-type`.
* **headers** `Record<string, string | string[]>` - Note that all header keys are lower-cased, e. g. `content-type`.
* **body** `stream.Readable` which also implements [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin).
* **trailers** `Record<string, string>` - This object starts out
as empty and will be mutated to contain trailers after `body` has emitted `'end'`.
Expand Down Expand Up @@ -631,7 +631,7 @@ try {

A faster version of `Dispatcher.request`. This method expects the second argument `factory` to return a [`stream.Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable) stream which the response will be written to. This improves performance by avoiding creating an intermediate [`stream.Readable`](https://nodejs.org/api/stream.html#stream_readable_streams) stream when the user expects to directly pipe the response body to a [`stream.Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable) stream.

As demonstrated in [Example 1 - Basic GET stream request](#example-1-basic-get-stream-request), it is recommended to use the `option.opaque` property to avoid creating a closure for the `factory` method. This pattern works well with Node.js Web Frameworks such as [Fastify](https://fastify.io). See [Example 2 - Stream to Fastify Response](#example-2-stream-to-fastify-response) for more details.
As demonstrated in [Example 1 - Basic GET stream request](#example-1---basic-get-stream-request), it is recommended to use the `option.opaque` property to avoid creating a closure for the `factory` method. This pattern works well with Node.js Web Frameworks such as [Fastify](https://fastify.io). See [Example 2 - Stream to Fastify Response](#example-2---stream-to-fastify-response) for more details.

Arguments:

Expand All @@ -644,7 +644,7 @@ Returns: `void | Promise<StreamData>` - Only returns a `Promise` if no `callback
#### Parameter: `StreamFactoryData`

* **statusCode** `number`
* **headers** `http.IncomingHttpHeaders`
* **headers** `Record<string, string | string[]>`
* **opaque** `unknown`
* **onInfo** `({statusCode: number, headers: Record<string, string | string[]>}) => void | null` (optional) - Default: `null` - Callback collecting all the info headers (HTTP 100-199) received.

Expand Down Expand Up @@ -853,9 +853,9 @@ Emitted when dispatcher is no longer busy.

## Parameter: `UndiciHeaders`

* `http.IncomingHttpHeaders | string[] | null`
* `Record<string, string | string[]> | string[] | null`

Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in two forms; either as an object specified by the `http.IncomingHttpHeaders` type, or an array of strings. An array representation of a header list must have an even length or an `InvalidArgumentError` will be thrown.
Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in two forms; either as an object specified by the `Record<string, string | string[]>` (`IncomingHttpHeaders`) type, or an array of strings. An array representation of a header list must have an even length or an `InvalidArgumentError` will be thrown.

Keys are lowercase and values are not modified.

Expand Down
1 change: 1 addition & 0 deletions deps/undici/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export * from './types/filereader'
export * from './types/formdata'
export * from './types/diagnostics-channel'
export * from './types/websocket'
export * from './types/content-type'
export { Interceptable } from './types/mock-interceptor'

export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler }
Expand Down
5 changes: 5 additions & 0 deletions deps/undici/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ if (nodeMajor >= 16) {
module.exports.getCookies = getCookies
module.exports.getSetCookies = getSetCookies
module.exports.setCookie = setCookie

const { parseMIMEType, serializeAMimeType } = require('./lib/fetch/dataURL')

module.exports.parseMIMEType = parseMIMEType
module.exports.serializeAMimeType = serializeAMimeType
}

if (nodeMajor >= 18 && hasCrypto) {
Expand Down
28 changes: 13 additions & 15 deletions deps/undici/src/lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
const assert = require('assert')
const net = require('net')
const util = require('./core/util')
const timers = require('./timers')
const Request = require('./core/request')
const DispatcherBase = require('./dispatcher-base')
const {
Expand Down Expand Up @@ -65,6 +66,7 @@ const {
kLocalAddress,
kMaxResponseSize
} = require('./core/symbols')
const FastBuffer = Buffer[Symbol.species]

const kClosedResolve = Symbol('kClosedResolve')

Expand Down Expand Up @@ -362,35 +364,31 @@ async function lazyllhttp () {
},
wasm_on_status: (p, at, len) => {
assert.strictEqual(currentParser.ptr, p)
const start = at - currentBufferPtr
const end = start + len
return currentParser.onStatus(currentBufferRef.slice(start, end)) || 0
const start = at - currentBufferPtr + currentBufferRef.byteOffset
return currentParser.onStatus(new FastBuffer(currentBufferRef.buffer, start, len)) || 0
},
wasm_on_message_begin: (p) => {
assert.strictEqual(currentParser.ptr, p)
return currentParser.onMessageBegin() || 0
},
wasm_on_header_field: (p, at, len) => {
assert.strictEqual(currentParser.ptr, p)
const start = at - currentBufferPtr
const end = start + len
return currentParser.onHeaderField(currentBufferRef.slice(start, end)) || 0
const start = at - currentBufferPtr + currentBufferRef.byteOffset
return currentParser.onHeaderField(new FastBuffer(currentBufferRef.buffer, start, len)) || 0
},
wasm_on_header_value: (p, at, len) => {
assert.strictEqual(currentParser.ptr, p)
const start = at - currentBufferPtr
const end = start + len
return currentParser.onHeaderValue(currentBufferRef.slice(start, end)) || 0
const start = at - currentBufferPtr + currentBufferRef.byteOffset
return currentParser.onHeaderValue(new FastBuffer(currentBufferRef.buffer, start, len)) || 0
},
wasm_on_headers_complete: (p, statusCode, upgrade, shouldKeepAlive) => {
assert.strictEqual(currentParser.ptr, p)
return currentParser.onHeadersComplete(statusCode, Boolean(upgrade), Boolean(shouldKeepAlive)) || 0
},
wasm_on_body: (p, at, len) => {
assert.strictEqual(currentParser.ptr, p)
const start = at - currentBufferPtr
const end = start + len
return currentParser.onBody(currentBufferRef.slice(start, end)) || 0
const start = at - currentBufferPtr + currentBufferRef.byteOffset
return currentParser.onBody(new FastBuffer(currentBufferRef.buffer, start, len)) || 0
},
wasm_on_message_complete: (p) => {
assert.strictEqual(currentParser.ptr, p)
Expand Down Expand Up @@ -447,9 +445,9 @@ class Parser {
setTimeout (value, type) {
this.timeoutType = type
if (value !== this.timeoutValue) {
clearTimeout(this.timeout)
timers.clearTimeout(this.timeout)
if (value) {
this.timeout = setTimeout(onParserTimeout, value, this)
this.timeout = timers.setTimeout(onParserTimeout, value, this)
// istanbul ignore else: only for jest
if (this.timeout.unref) {
this.timeout.unref()
Expand Down Expand Up @@ -565,7 +563,7 @@ class Parser {
this.llhttp.llhttp_free(this.ptr)
this.ptr = null

clearTimeout(this.timeout)
timers.clearTimeout(this.timeout)
this.timeout = null
this.timeoutValue = null
this.timeoutType = null
Expand Down
6 changes: 6 additions & 0 deletions deps/undici/src/lib/core/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
})
}

// Set TCP keep alive options on the socket here instead of in connect() for the case of assigning the socket
if (options.keepAlive == null || options.keepAlive) {
const keepAliveInitialDelay = options.keepAliveInitialDelay === undefined ? 60e3 : options.keepAliveInitialDelay
socket.setKeepAlive(true, keepAliveInitialDelay)
}

const cancelTimeout = setupTimeout(() => onConnectTimeout(socket), timeout)

socket
Expand Down
16 changes: 10 additions & 6 deletions deps/undici/src/lib/core/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,16 @@ class Request {
}

function processHeaderValue (key, val) {
if (val && (typeof val === 'object' && !Array.isArray(val))) {
if (val && typeof val === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`)
} else if (headerCharRegex.exec(val) !== null) {
}

val = val != null ? `${val}` : ''

if (headerCharRegex.exec(val) !== null) {
throw new InvalidArgumentError(`invalid ${key} header`)
}

return `${key}: ${val}\r\n`
}

Expand Down Expand Up @@ -313,11 +318,10 @@ function processHeader (request, key, val) {
} else if (
request.contentType === null &&
key.length === 12 &&
key.toLowerCase() === 'content-type' &&
headerCharRegex.exec(val) === null
key.toLowerCase() === 'content-type'
) {
request.contentType = val
request.headers += `${key}: ${val}\r\n`
request.headers += processHeaderValue(key, val)
} else if (
key.length === 17 &&
key.toLowerCase() === 'transfer-encoding'
Expand All @@ -327,7 +331,7 @@ function processHeader (request, key, val) {
key.length === 10 &&
key.toLowerCase() === 'connection'
) {
const value = val.toLowerCase()
const value = typeof val === 'string' ? val.toLowerCase() : null
if (value !== 'close' && value !== 'keep-alive') {
throw new InvalidArgumentError('invalid connection header')
} else if (value === 'close') {
Expand Down
39 changes: 29 additions & 10 deletions deps/undici/src/lib/fetch/dataURL.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ function dataURLProcessor (dataURL) {
// 5. Let mimeType be the result of collecting a
// sequence of code points that are not equal
// to U+002C (,), given position.
let mimeType = collectASequenceOfCodePoints(
(char) => char !== ',',
let mimeType = collectASequenceOfCodePointsFast(
',',
input,
position
)
Expand Down Expand Up @@ -145,6 +145,25 @@ function collectASequenceOfCodePoints (condition, input, position) {
return result
}

/**
* A faster collectASequenceOfCodePoints that only works when comparing a single character.
* @param {string} char
* @param {string} input
* @param {{ position: number }} position
*/
function collectASequenceOfCodePointsFast (char, input, position) {
const idx = input.indexOf(char, position.position)
const start = position.position

if (idx === -1) {
position.position = input.length
return input.slice(start)
}

position.position = idx
return input.slice(start, position.position)
}

// https://url.spec.whatwg.org/#string-percent-decode
/** @param {string} input */
function stringPercentDecode (input) {
Expand Down Expand Up @@ -214,8 +233,8 @@ function parseMIMEType (input) {
// 3. Let type be the result of collecting a sequence
// of code points that are not U+002F (/) from
// input, given position.
const type = collectASequenceOfCodePoints(
(char) => char !== '/',
const type = collectASequenceOfCodePointsFast(
'/',
input,
position
)
Expand All @@ -239,8 +258,8 @@ function parseMIMEType (input) {
// 7. Let subtype be the result of collecting a sequence of
// code points that are not U+003B (;) from input, given
// position.
let subtype = collectASequenceOfCodePoints(
(char) => char !== ';',
let subtype = collectASequenceOfCodePointsFast(
';',
input,
position
)
Expand Down Expand Up @@ -324,8 +343,8 @@ function parseMIMEType (input) {

// 2. Collect a sequence of code points that are not
// U+003B (;) from input, given position.
collectASequenceOfCodePoints(
(char) => char !== ';',
collectASequenceOfCodePointsFast(
';',
input,
position
)
Expand All @@ -335,8 +354,8 @@ function parseMIMEType (input) {
// 1. Set parameterValue to the result of collecting
// a sequence of code points that are not U+003B (;)
// from input, given position.
parameterValue = collectASequenceOfCodePoints(
(char) => char !== ';',
parameterValue = collectASequenceOfCodePointsFast(
';',
input,
position
)
Expand Down
6 changes: 5 additions & 1 deletion deps/undici/src/lib/fetch/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ class HeadersList {

// 2. Append (name, value) to list.
if (exists) {
this[kHeadersMap].set(lowercaseName, { name: exists.name, value: `${exists.value}, ${value}` })
const delimiter = lowercaseName === 'cookie' ? '; ' : ', '
this[kHeadersMap].set(lowercaseName, {
name: exists.name,
value: `${exists.value}${delimiter}${value}`
})
} else {
this[kHeadersMap].set(lowercaseName, { name, value })
}
Expand Down
Loading