diff --git a/deps/undici/src/README.md b/deps/undici/src/README.md index c8dc260e12a613..c2639bb7633d89 100644 --- a/deps/undici/src/README.md +++ b/deps/undici/src/README.md @@ -185,13 +185,12 @@ Help us improve the test coverage by following instructions at [nodejs/undici/#9 Basic usage example: ```js - import {fetch} from 'undici'; +import { fetch } from 'undici'; - async function fetchJson() { - const res = await fetch('https://example.com') - const json = await res.json() - console.log(json); - } + +const res = await fetch('https://example.com') +const json = await res.json() +console.log(json); ``` You can pass an optional dispatcher to `fetch` as: @@ -235,9 +234,7 @@ const data = { }, }; -(async () => { - await fetch("https://example.com", { body: data, method: 'POST' }); -})(); +await fetch("https://example.com", { body: data, method: 'POST' }); ``` #### `response.body` @@ -245,14 +242,12 @@ const data = { Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html), which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`. ```js - import {fetch} from 'undici'; - import {Readable} from 'node:stream'; +import { fetch } from 'undici'; +import { Readable } from 'node:stream'; - async function fetchStream() { - const response = await fetch('https://example.com') - const readableWebStream = response.body; - const readableNodeStream = Readable.fromWeb(readableWebStream); - } +const response = await fetch('https://example.com') +const readableWebStream = response.body; +const readableNodeStream = Readable.fromWeb(readableWebStream); ``` #### Specification Compliance diff --git a/deps/undici/src/lib/api/api-connect.js b/deps/undici/src/lib/api/api-connect.js index 0503b1a2f0eb10..e4981af00de1b7 100644 --- a/deps/undici/src/lib/api/api-connect.js +++ b/deps/undici/src/lib/api/api-connect.js @@ -15,7 +15,7 @@ class ConnectHandler extends AsyncResource { throw new InvalidArgumentError('invalid callback') } - const { signal, opaque, responseHeaders } = opts + const { signal, opaque, responseHeaders, httpTunnel } = opts if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') @@ -27,6 +27,7 @@ class ConnectHandler extends AsyncResource { this.responseHeaders = responseHeaders || null this.callback = callback this.abort = null + this.httpTunnel = httpTunnel addSignal(this, signal) } @@ -40,8 +41,23 @@ class ConnectHandler extends AsyncResource { this.context = context } - onHeaders () { - throw new SocketError('bad connect', null) + onHeaders (statusCode) { + // when httpTunnel headers are allowed + if (this.httpTunnel) { + const { callback, opaque } = this + if (statusCode !== 200) { + if (callback) { + this.callback = null + const err = new RequestAbortedError('Proxy response !== 200 when HTTP Tunneling') + queueMicrotask(() => { + this.runInAsyncScope(callback, null, err, { opaque }) + }) + } + return 1 + } + } else { + throw new SocketError('bad connect', null) + } } onUpgrade (statusCode, rawHeaders, socket) { diff --git a/deps/undici/src/lib/core/connect.js b/deps/undici/src/lib/core/connect.js index 33a07e6d02dc73..57667a1314afa0 100644 --- a/deps/undici/src/lib/core/connect.js +++ b/deps/undici/src/lib/core/connect.js @@ -21,7 +21,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) { timeout = timeout == null ? 10e3 : timeout maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions - return function connect ({ hostname, host, protocol, port, servername }, callback) { + return function connect ({ hostname, host, protocol, port, servername, httpSocket }, callback) { let socket if (protocol === 'https:') { if (!tls) { @@ -39,6 +39,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) { ...options, servername, session, + socket: httpSocket, // upgrade socket connection port: port || 443, host: hostname }) @@ -65,6 +66,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) { } }) } else { + assert(!httpSocket, 'httpSocket can only be sent on TLS update') socket = net.connect({ highWaterMark: 64 * 1024, // Same as nodejs fs streams. ...options, diff --git a/deps/undici/src/lib/core/request.js b/deps/undici/src/lib/core/request.js index 2a13b0549a80ff..1969f84deb186b 100644 --- a/deps/undici/src/lib/core/request.js +++ b/deps/undici/src/lib/core/request.js @@ -48,7 +48,11 @@ class Request { }, handler) { if (typeof path !== 'string') { throw new InvalidArgumentError('path must be a string') - } else if (path[0] !== '/' && !(path.startsWith('http://') || path.startsWith('https://'))) { + } else if ( + path[0] !== '/' && + !(path.startsWith('http://') || path.startsWith('https://')) && + method !== 'CONNECT' + ) { throw new InvalidArgumentError('path must be an absolute URL or start with a slash') } @@ -80,13 +84,12 @@ class Request { this.body = null } else if (util.isStream(body)) { this.body = body - } else if (body instanceof DataView) { - // TODO: Why is DataView special? - this.body = body.buffer.byteLength ? Buffer.from(body.buffer) : null - } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) { - this.body = body.byteLength ? Buffer.from(body) : null } else if (util.isBuffer(body)) { this.body = body.byteLength ? body : null + } else if (ArrayBuffer.isView(body)) { + this.body = body.buffer.byteLength ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : null + } else if (body instanceof ArrayBuffer) { + this.body = body.byteLength ? Buffer.from(body) : null } else if (typeof body === 'string') { this.body = body.length ? Buffer.from(body) : null } else if (util.isFormDataLike(body) || util.isIterable(body) || util.isBlobLike(body)) { diff --git a/deps/undici/src/lib/fetch/body.js b/deps/undici/src/lib/fetch/body.js index 415e4ea34dacb2..beb1e027c98af6 100644 --- a/deps/undici/src/lib/fetch/body.js +++ b/deps/undici/src/lib/fetch/body.js @@ -9,7 +9,7 @@ const { kBodyUsed } = require('../core/symbols') const assert = require('assert') const { NotSupportedError } = require('../core/errors') const { isErrored } = require('../core/util') -const { isUint8Array } = require('util/types') +const { isUint8Array, isArrayBuffer } = require('util/types') let ReadableStream @@ -61,7 +61,7 @@ function extractBody (object, keepalive = false) { // Set Content-Type to `application/x-www-form-urlencoded;charset=UTF-8`. contentType = 'application/x-www-form-urlencoded;charset=UTF-8' - } else if (object instanceof ArrayBuffer || ArrayBuffer.isView(object)) { + } else if (isArrayBuffer(object) || ArrayBuffer.isView(object)) { // BufferSource if (object instanceof DataView) { diff --git a/deps/undici/src/lib/fetch/formdata.js b/deps/undici/src/lib/fetch/formdata.js index 40df747e843f05..965e47c3a7f6ca 100644 --- a/deps/undici/src/lib/fetch/formdata.js +++ b/deps/undici/src/lib/fetch/formdata.js @@ -1,6 +1,6 @@ 'use strict' -const { isBlobLike, isFileLike, toUSVString } = require('./util') +const { isBlobLike, isFileLike, toUSVString, makeIterator } = require('./util') const { kState } = require('./symbols') const { File, FileLike } = require('./file') const { Blob } = require('buffer') @@ -187,45 +187,68 @@ class FormData { return this.constructor.name } - * entries () { + entries () { if (!(this instanceof FormData)) { throw new TypeError('Illegal invocation') } - for (const pair of this) { - yield pair - } + return makeIterator( + makeIterable(this[kState], 'entries'), + 'FormData' + ) } - * keys () { + keys () { if (!(this instanceof FormData)) { throw new TypeError('Illegal invocation') } - for (const [key] of this) { - yield key + return makeIterator( + makeIterable(this[kState], 'keys'), + 'FormData' + ) + } + + values () { + if (!(this instanceof FormData)) { + throw new TypeError('Illegal invocation') } + + return makeIterator( + makeIterable(this[kState], 'values'), + 'FormData' + ) } - * values () { + /** + * @param {(value: string, key: string, self: FormData) => void} callbackFn + * @param {unknown} thisArg + */ + forEach (callbackFn, thisArg = globalThis) { if (!(this instanceof FormData)) { throw new TypeError('Illegal invocation') } - for (const [, value] of this) { - yield value + if (arguments.length < 1) { + throw new TypeError( + `Failed to execute 'forEach' on 'FormData': 1 argument required, but only ${arguments.length} present.` + ) } - } - * [Symbol.iterator] () { - // The value pairs to iterate over are this’s entry list’s entries with - // the key being the name and the value being the value. - for (const { name, value } of this[kState]) { - yield [name, value] + if (typeof callbackFn !== 'function') { + throw new TypeError( + "Failed to execute 'forEach' on 'FormData': parameter 1 is not of type 'Function'." + ) + } + + for (const [key, value] of this) { + callbackFn.apply(thisArg, [value, key, this]) } } } +FormData.prototype[Symbol.iterator] = FormData.prototype.entries + function makeEntry (name, value, filename) { // To create an entry for name, value, and optionally a filename, run these // steps: @@ -267,4 +290,18 @@ function makeEntry (name, value, filename) { return entry } +function * makeIterable (entries, type) { + // The value pairs to iterate over are this’s entry list’s entries + // with the key being the name and the value being the value. + for (const { name, value } of entries) { + if (type === 'entries') { + yield [name, value] + } else if (type === 'values') { + yield value + } else { + yield name + } + } +} + module.exports = { FormData } diff --git a/deps/undici/src/lib/fetch/headers.js b/deps/undici/src/lib/fetch/headers.js index 0c6e5584d33003..582e0c0f576ff1 100644 --- a/deps/undici/src/lib/fetch/headers.js +++ b/deps/undici/src/lib/fetch/headers.js @@ -6,6 +6,7 @@ const { validateHeaderName, validateHeaderValue } = require('http') const { kHeadersList } = require('../core/symbols') const { kGuard } = require('./symbols') const { kEnumerableProperty } = require('../core/util') +const { makeIterator } = require('./util') const kHeadersMap = Symbol('headers map') const kHeadersSortedMap = Symbol('headers map sorted') @@ -73,33 +74,6 @@ function fill (headers, object) { } } -// https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object -const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) - -// https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object -function makeHeadersIterator (iterator) { - const i = { - next () { - if (Object.getPrototypeOf(this) !== i) { - throw new TypeError( - '\'next\' called on an object that does not implement interface Headers Iterator.' - ) - } - - return iterator.next() - }, - // The class string of an iterator prototype object for a given interface is the - // result of concatenating the identifier of the interface and the string " Iterator". - [Symbol.toStringTag]: 'Headers Iterator' - } - - // The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%. - Object.setPrototypeOf(i, esIteratorPrototype) - // esIteratorPrototype needs to be the prototype of i - // which is the prototype of an empty object. Yes, it's confusing. - return Object.setPrototypeOf({}, i) -} - class HeadersList { constructor (init) { if (init instanceof HeadersList) { @@ -306,7 +280,7 @@ class Headers { throw new TypeError('Illegal invocation') } - return makeHeadersIterator(this[kHeadersSortedMap].keys()) + return makeIterator(this[kHeadersSortedMap].keys(), 'Headers') } values () { @@ -314,7 +288,7 @@ class Headers { throw new TypeError('Illegal invocation') } - return makeHeadersIterator(this[kHeadersSortedMap].values()) + return makeIterator(this[kHeadersSortedMap].values(), 'Headers') } entries () { @@ -322,7 +296,7 @@ class Headers { throw new TypeError('Illegal invocation') } - return makeHeadersIterator(this[kHeadersSortedMap].entries()) + return makeIterator(this[kHeadersSortedMap].entries(), 'Headers') } /** diff --git a/deps/undici/src/lib/fetch/index.js b/deps/undici/src/lib/fetch/index.js index c1f3391995e357..ddf4b03d4cbab8 100644 --- a/deps/undici/src/lib/fetch/index.js +++ b/deps/undici/src/lib/fetch/index.js @@ -1164,7 +1164,7 @@ async function httpRedirectFetch (fetchParams, response) { if ( ([301, 302].includes(actualResponse.status) && request.method === 'POST') || (actualResponse.status === 303 && - !['GET', 'HEADER'].includes(request.method)) + !['GET', 'HEAD'].includes(request.method)) ) { // then: // 1. Set request’s method to `GET` and request’s body to null. diff --git a/deps/undici/src/lib/fetch/util.js b/deps/undici/src/lib/fetch/util.js index 1c67f9c7c841fa..3c088fbc6e92ad 100644 --- a/deps/undici/src/lib/fetch/util.js +++ b/deps/undici/src/lib/fetch/util.js @@ -361,6 +361,33 @@ function serializeJavascriptValueToJSONString (value) { return result } +// https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object +const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) + +// https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object +function makeIterator (iterator, name) { + const i = { + next () { + if (Object.getPrototypeOf(this) !== i) { + throw new TypeError( + `'next' called on an object that does not implement interface ${name} Iterator.` + ) + } + + return iterator.next() + }, + // The class string of an iterator prototype object for a given interface is the + // result of concatenating the identifier of the interface and the string " Iterator". + [Symbol.toStringTag]: `${name} Iterator` + } + + // The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%. + Object.setPrototypeOf(i, esIteratorPrototype) + // esIteratorPrototype needs to be the prototype of i + // which is the prototype of an empty object. Yes, it's confusing. + return Object.setPrototypeOf({}, i) +} + module.exports = { isAborted, isCancelled, @@ -390,5 +417,6 @@ module.exports = { isValidReasonPhrase, sameOrigin, normalizeMethod, - serializeJavascriptValueToJSONString + serializeJavascriptValueToJSONString, + makeIterator } diff --git a/deps/undici/src/lib/proxy-agent.js b/deps/undici/src/lib/proxy-agent.js index 37a416806178c1..8799650e62d30e 100644 --- a/deps/undici/src/lib/proxy-agent.js +++ b/deps/undici/src/lib/proxy-agent.js @@ -1,28 +1,46 @@ 'use strict' const { kProxy, kClose, kDestroy } = require('./core/symbols') +const Client = require('./agent') const Agent = require('./agent') const DispatcherBase = require('./dispatcher-base') const { InvalidArgumentError } = require('./core/errors') +const buildConnector = require('./core/connect') const kAgent = Symbol('proxy agent') +const kClient = Symbol('proxy client') +const kProxyHeaders = Symbol('proxy headers') +const kRequestTls = Symbol('request tls settings') +const kProxyTls = Symbol('proxy tls settings') +const kConnectEndpoint = Symbol('connect endpoint function') class ProxyAgent extends DispatcherBase { constructor (opts) { super(opts) this[kProxy] = buildProxyOptions(opts) - this[kAgent] = new Agent(opts) + this[kRequestTls] = opts.requestTls + this[kProxyTls] = opts.proxyTls + this[kProxyHeaders] = {} + + if (opts.auth) { + this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` + } + + const connect = buildConnector({ ...opts.proxyTls }) + this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) + this[kClient] = new Client({ origin: opts.origin, connect }) + this[kAgent] = new Agent({ ...opts, connect: this.connectTunnel.bind(this) }) } dispatch (opts, handler) { const { host } = new URL(opts.origin) + const headers = buildHeaders(opts.headers) + throwIfProxyAuthIsSent(headers) return this[kAgent].dispatch( { ...opts, - origin: this[kProxy].uri, - path: opts.origin + opts.path, headers: { - ...buildHeaders(opts.headers), + ...headers, host } }, @@ -30,12 +48,43 @@ class ProxyAgent extends DispatcherBase { ) } + async connectTunnel (opts, callback) { + try { + const { socket } = await this[kClient].connect({ + origin: this[kProxy].origin, + port: this[kProxy].port, + path: opts.host, + signal: opts.signal, + headers: { + ...this[kProxyHeaders], + host: opts.host + }, + httpTunnel: true + }) + if (opts.protocol !== 'https:') { + callback(null, socket) + return + } + let servername + if (this[kRequestTls]) { + servername = this[kRequestTls].servername + } else { + servername = opts.servername + } + this[kConnectEndpoint]({ ...opts, servername, httpSocket: socket }, callback) + } catch (err) { + callback(err) + } + } + async [kClose] () { await this[kAgent].close() + await this[kClient].close() } async [kDestroy] () { await this[kAgent].destroy() + await this[kClient].destroy() } } @@ -48,10 +97,7 @@ function buildProxyOptions (opts) { throw new InvalidArgumentError('Proxy opts.uri is mandatory') } - return { - uri: opts.uri, - protocol: opts.protocol || 'https' - } + return new URL(opts.uri) } /** @@ -75,4 +121,20 @@ function buildHeaders (headers) { return headers } +/** + * @param {Record} headers + * + * Previous versions of ProxyAgent suggests the Proxy-Authorization in request headers + * Nevertheless, it was changed and to avoid a security vulnerability by end users + * this check was created. + * It should be removed in the next major version for performance reasons + */ +function throwIfProxyAuthIsSent (headers) { + const existProxyAuth = headers && Object.keys(headers) + .find((key) => key.toLowerCase() === 'proxy-authorization') + if (existProxyAuth) { + throw new InvalidArgumentError('Proxy-Authorization should be sent in ProxyAgent constructor') + } +} + module.exports = ProxyAgent diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json index 3fda0f8e557088..dd029b6cfb0e06 100644 --- a/deps/undici/src/package.json +++ b/deps/undici/src/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "5.4.0", + "version": "5.5.1", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { diff --git a/deps/undici/src/types/connector.d.ts b/deps/undici/src/types/connector.d.ts index 0794903cf0879b..38016b00008091 100644 --- a/deps/undici/src/types/connector.d.ts +++ b/deps/undici/src/types/connector.d.ts @@ -1,16 +1,15 @@ -import { URL } from 'url' -import { TLSSocket, TlsOptions } from 'tls' -import { Socket } from 'net' +import {TLSSocket, ConnectionOptions} from 'tls' +import {IpcNetConnectOpts, Socket, TcpNetConnectOpts} from 'net' export = buildConnector declare function buildConnector (options?: buildConnector.BuildOptions): typeof buildConnector.connector declare namespace buildConnector { - export interface BuildOptions extends TlsOptions { + export type BuildOptions = (ConnectionOptions | TcpNetConnectOpts | IpcNetConnectOpts) & { maxCachedSessions?: number | null; socketPath?: string | null; timeout?: number | null; - servername?: string | null; + port?: number; } export interface Options { diff --git a/deps/undici/src/types/fetch.d.ts b/deps/undici/src/types/fetch.d.ts index 47a08dd0510f05..87980bed40b3df 100644 --- a/deps/undici/src/types/fetch.d.ts +++ b/deps/undici/src/types/fetch.d.ts @@ -38,21 +38,21 @@ export interface BodyMixin { readonly text: () => Promise } -export interface HeadersIterator { +export interface SpecIterator { next(...args: [] | [TNext]): IteratorResult; } -export interface HeadersIterableIterator extends HeadersIterator { - [Symbol.iterator](): HeadersIterableIterator; +export interface SpecIterableIterator extends SpecIterator { + [Symbol.iterator](): SpecIterableIterator; } -export interface HeadersIterable { - [Symbol.iterator](): HeadersIterator; +export interface SpecIterable { + [Symbol.iterator](): SpecIterator; } export type HeadersInit = string[][] | Record> | Headers -export declare class Headers implements HeadersIterable<[string, string]> { +export declare class Headers implements SpecIterable<[string, string]> { constructor (init?: HeadersInit) readonly append: (name: string, value: string) => void readonly delete: (name: string) => void @@ -64,10 +64,10 @@ export declare class Headers implements HeadersIterable<[string, string]> { thisArg?: unknown ) => void - readonly keys: () => HeadersIterableIterator - readonly values: () => HeadersIterableIterator - readonly entries: () => HeadersIterableIterator<[string, string]> - readonly [Symbol.iterator]: () => HeadersIterator<[string, string]> + readonly keys: () => SpecIterableIterator + readonly values: () => SpecIterableIterator + readonly entries: () => SpecIterableIterator<[string, string]> + readonly [Symbol.iterator]: () => SpecIterator<[string, string]> } export type RequestCache = diff --git a/deps/undici/src/types/formdata.d.ts b/deps/undici/src/types/formdata.d.ts index 2e652bacdb731f..df29a572d6bd4f 100644 --- a/deps/undici/src/types/formdata.d.ts +++ b/deps/undici/src/types/formdata.d.ts @@ -2,6 +2,7 @@ /// import { File } from './file' +import { SpecIterator, SpecIterableIterator } from './fetch' /** * A `string` or `File` that represents a single value from a set of `FormData` key-value pairs. @@ -73,32 +74,35 @@ export declare class FormData { delete(name: string): void /** - * Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through all keys contained in this `FormData` object. - * Each key is a `string`. + * Executes given callback function for each field of the FormData instance */ - keys(): Generator + forEach: ( + callbackfn: (value: FormDataEntryValue, key: string, iterable: FormData) => void, + thisArg?: unknown + ) => void /** - * Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through the `FormData` key/value pairs. - * The key of each pair is a string; the value is a [`FormDataValue`](https://developer.mozilla.org/en-US/docs/Web/API/FormDataEntryValue). + * Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through all keys contained in this `FormData` object. + * Each key is a `string`. */ - entries(): Generator<[string, FormDataEntryValue]> + keys: () => SpecIterableIterator /** * Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through all values contained in this object `FormData` object. * Each value is a [`FormDataValue`](https://developer.mozilla.org/en-US/docs/Web/API/FormDataEntryValue). */ - values(): Generator + values: () => SpecIterableIterator /** - * An alias for FormData#entries() + * Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through the `FormData` key/value pairs. + * The key of each pair is a string; the value is a [`FormDataValue`](https://developer.mozilla.org/en-US/docs/Web/API/FormDataEntryValue). */ - [Symbol.iterator](): Generator<[string, FormDataEntryValue], void> + entries: () => SpecIterableIterator<[string, FormDataEntryValue]> /** - * Executes given callback function for each field of the FormData instance + * An alias for FormData#entries() */ - forEach(callback: (value: FormDataEntryValue, key: string, formData: FormData) => void, thisArg?: unknown): void + [Symbol.iterator]: () => SpecIterableIterator<[string, FormDataEntryValue]> readonly [Symbol.toStringTag]: string } diff --git a/deps/undici/src/types/proxy-agent.d.ts b/deps/undici/src/types/proxy-agent.d.ts index c22369e96ee1ec..30fef450215380 100644 --- a/deps/undici/src/types/proxy-agent.d.ts +++ b/deps/undici/src/types/proxy-agent.d.ts @@ -1,3 +1,4 @@ +import { TlsOptions } from 'tls' import Agent = require('./agent') import Dispatcher = require('./dispatcher') @@ -13,5 +14,8 @@ declare class ProxyAgent extends Dispatcher { declare namespace ProxyAgent { export interface Options extends Agent.Options { uri: string; + auth?: string; + requestTls?: TlsOptions & { servername?: string }; + proxyTls?: TlsOptions & { servername?: string }; } } diff --git a/deps/undici/undici.js b/deps/undici/undici.js index 25de978273c344..5716d965a9618b 100644 --- a/deps/undici/undici.js +++ b/deps/undici/undici.js @@ -1415,6 +1415,20 @@ var require_util2 = __commonJS({ assert(typeof result === "string"); return result; } + var esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); + function makeIterator(iterator, name) { + const i = { + next() { + if (Object.getPrototypeOf(this) !== i) { + throw new TypeError(`'next' called on an object that does not implement interface ${name} Iterator.`); + } + return iterator.next(); + }, + [Symbol.toStringTag]: `${name} Iterator` + }; + Object.setPrototypeOf(i, esIteratorPrototype); + return Object.setPrototypeOf({}, i); + } module2.exports = { isAborted, isCancelled, @@ -1444,7 +1458,8 @@ var require_util2 = __commonJS({ isValidReasonPhrase, sameOrigin, normalizeMethod, - serializeJavascriptValueToJSONString + serializeJavascriptValueToJSONString, + makeIterator }; } }); @@ -1453,7 +1468,7 @@ var require_util2 = __commonJS({ var require_formdata = __commonJS({ "lib/fetch/formdata.js"(exports2, module2) { "use strict"; - var { isBlobLike, isFileLike, toUSVString } = require_util2(); + var { isBlobLike, isFileLike, toUSVString, makeIterator } = require_util2(); var { kState } = require_symbols2(); var { File, FileLike } = require_file(); var { Blob } = require("buffer"); @@ -1558,38 +1573,42 @@ var require_formdata = __commonJS({ get [Symbol.toStringTag]() { return this.constructor.name; } - *entries() { + entries() { if (!(this instanceof _FormData)) { throw new TypeError("Illegal invocation"); } - for (const pair of this) { - yield pair; - } + return makeIterator(makeIterable(this[kState], "entries"), "FormData"); } - *keys() { + keys() { if (!(this instanceof _FormData)) { throw new TypeError("Illegal invocation"); } - for (const [key] of this) { - yield key; + return makeIterator(makeIterable(this[kState], "keys"), "FormData"); + } + values() { + if (!(this instanceof _FormData)) { + throw new TypeError("Illegal invocation"); } + return makeIterator(makeIterable(this[kState], "values"), "FormData"); } - *values() { + forEach(callbackFn, thisArg = globalThis) { if (!(this instanceof _FormData)) { throw new TypeError("Illegal invocation"); } - for (const [, value] of this) { - yield value; + if (arguments.length < 1) { + throw new TypeError(`Failed to execute 'forEach' on 'FormData': 1 argument required, but only ${arguments.length} present.`); } - } - *[Symbol.iterator]() { - for (const { name, value } of this[kState]) { - yield [name, value]; + if (typeof callbackFn !== "function") { + throw new TypeError("Failed to execute 'forEach' on 'FormData': parameter 1 is not of type 'Function'."); + } + for (const [key, value] of this) { + callbackFn.apply(thisArg, [value, key, this]); } } }; var FormData = _FormData; __publicField(FormData, "name", "FormData"); + FormData.prototype[Symbol.iterator] = FormData.prototype.entries; function makeEntry(name, value, filename) { const entry = { name: null, @@ -1605,6 +1624,17 @@ var require_formdata = __commonJS({ entry.value = value; return entry; } + function* makeIterable(entries, type) { + for (const { name, value } of entries) { + if (type === "entries") { + yield [name, value]; + } else if (type === "values") { + yield value; + } else { + yield name; + } + } + } module2.exports = { FormData }; } }); @@ -1622,7 +1652,7 @@ var require_body = __commonJS({ var assert = require("assert"); var { NotSupportedError } = require_errors(); var { isErrored } = require_util(); - var { isUint8Array } = require("util/types"); + var { isUint8Array, isArrayBuffer } = require("util/types"); var ReadableStream; async function* blobGen(blob) { if (blob.stream) { @@ -1644,7 +1674,7 @@ var require_body = __commonJS({ } else if (object instanceof URLSearchParams) { source = object.toString(); contentType = "application/x-www-form-urlencoded;charset=UTF-8"; - } else if (object instanceof ArrayBuffer || ArrayBuffer.isView(object)) { + } else if (isArrayBuffer(object) || ArrayBuffer.isView(object)) { if (object instanceof DataView) { object = object.buffer; } @@ -1880,7 +1910,7 @@ var require_request = __commonJS({ }, handler) { if (typeof path !== "string") { throw new InvalidArgumentError("path must be a string"); - } else if (path[0] !== "/" && !(path.startsWith("http://") || path.startsWith("https://"))) { + } else if (path[0] !== "/" && !(path.startsWith("http://") || path.startsWith("https://")) && method !== "CONNECT") { throw new InvalidArgumentError("path must be an absolute URL or start with a slash"); } if (typeof method !== "string") { @@ -1903,12 +1933,12 @@ var require_request = __commonJS({ this.body = null; } else if (util.isStream(body)) { this.body = body; - } else if (body instanceof DataView) { - this.body = body.buffer.byteLength ? Buffer.from(body.buffer) : null; - } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) { - this.body = body.byteLength ? Buffer.from(body) : null; } else if (util.isBuffer(body)) { this.body = body.byteLength ? body : null; + } else if (ArrayBuffer.isView(body)) { + this.body = body.buffer.byteLength ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : null; + } else if (body instanceof ArrayBuffer) { + this.body = body.byteLength ? Buffer.from(body) : null; } else if (typeof body === "string") { this.body = body.length ? Buffer.from(body) : null; } else if (util.isFormDataLike(body) || util.isIterable(body) || util.isBlobLike(body)) { @@ -2221,7 +2251,7 @@ var require_connect = __commonJS({ const sessionCache = /* @__PURE__ */ new Map(); timeout = timeout == null ? 1e4 : timeout; maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions; - return function connect({ hostname, host, protocol, port, servername }, callback) { + return function connect({ hostname, host, protocol, port, servername, httpSocket }, callback) { let socket; if (protocol === "https:") { if (!tls) { @@ -2236,6 +2266,7 @@ var require_connect = __commonJS({ ...options, servername, session, + socket: httpSocket, port: port || 443, host: hostname }); @@ -2254,6 +2285,7 @@ var require_connect = __commonJS({ } }); } else { + assert(!httpSocket, "httpSocket can only be sent on TLS update"); socket = net.connect({ highWaterMark: 64 * 1024, ...options, @@ -4205,6 +4237,7 @@ var require_headers = __commonJS({ var { kHeadersList } = require_symbols(); var { kGuard } = require_symbols2(); var { kEnumerableProperty } = require_util(); + var { makeIterator } = require_util2(); var kHeadersMap = Symbol("headers map"); var kHeadersSortedMap = Symbol("headers map sorted"); function normalizeAndValidateHeaderName(name) { @@ -4248,20 +4281,6 @@ var require_headers = __commonJS({ throw TypeError(); } } - var esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); - function makeHeadersIterator(iterator) { - const i = { - next() { - if (Object.getPrototypeOf(this) !== i) { - throw new TypeError("'next' called on an object that does not implement interface Headers Iterator."); - } - return iterator.next(); - }, - [Symbol.toStringTag]: "Headers Iterator" - }; - Object.setPrototypeOf(i, esIteratorPrototype); - return Object.setPrototypeOf({}, i); - } var HeadersList = class { constructor(init) { if (init instanceof HeadersList) { @@ -4396,19 +4415,19 @@ var require_headers = __commonJS({ if (!(this instanceof Headers)) { throw new TypeError("Illegal invocation"); } - return makeHeadersIterator(this[kHeadersSortedMap].keys()); + return makeIterator(this[kHeadersSortedMap].keys(), "Headers"); } values() { if (!(this instanceof Headers)) { throw new TypeError("Illegal invocation"); } - return makeHeadersIterator(this[kHeadersSortedMap].values()); + return makeIterator(this[kHeadersSortedMap].values(), "Headers"); } entries() { if (!(this instanceof Headers)) { throw new TypeError("Illegal invocation"); } - return makeHeadersIterator(this[kHeadersSortedMap].entries()); + return makeIterator(this[kHeadersSortedMap].entries(), "Headers"); } forEach(callbackFn, thisArg = globalThis) { if (!(this instanceof Headers)) { @@ -5950,7 +5969,7 @@ var require_fetch = __commonJS({ if (actualResponse.status !== 303 && request.body != null && request.body.source == null) { return makeNetworkError(); } - if ([301, 302].includes(actualResponse.status) && request.method === "POST" || actualResponse.status === 303 && !["GET", "HEADER"].includes(request.method)) { + if ([301, 302].includes(actualResponse.status) && request.method === "POST" || actualResponse.status === 303 && !["GET", "HEAD"].includes(request.method)) { request.method = "GET"; request.body = null; for (const headerName of requestBodyHeader) {