Skip to content

Commit 53d5522

Browse files
authored
Merge branch 'nodejs:main' into main
2 parents 25efdd8 + 7102eb0 commit 53d5522

File tree

193 files changed

+30263
-624
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

193 files changed

+30263
-624
lines changed

benchmarks/benchmark.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ const httpBaseOptions = {
3232
hostname: 'localhost',
3333
method: 'GET',
3434
path: '/',
35+
query: {
36+
frappucino: 'muffin',
37+
goat: 'scone',
38+
pond: 'moose',
39+
foo: ['bar', 'baz', 'bal'],
40+
bool: true,
41+
numberKey: 256
42+
},
3543
...dest
3644
}
3745

@@ -104,14 +112,14 @@ function printResults (results) {
104112
let last
105113

106114
const rows = Object.entries(results)
107-
// If any failed, put on the top of the list, otherwise order by mean, ascendin
115+
// If any failed, put on the top of the list, otherwise order by mean, ascending
108116
.sort((a, b) => (!a[1].success ? -1 : b[1].mean - a[1].mean))
109117
.map(([name, result]) => {
110118
if (!result.success) {
111119
return [name, result.size, 'Errored', 'N/A', 'N/A']
112120
}
113121

114-
// Calculate throughtput and relative performance
122+
// Calculate throughput and relative performance
115123
const { size, mean, standardError } = result
116124
const relative = last !== 0 ? (last / mean - 1) * 100 : 0
117125

benchmarks/server.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if (cluster.isPrimary) {
1616
try {
1717
unlinkSync(socketPath)
1818
} catch (_) {
19-
// Do not nothing if the socket does not exist
19+
// Do nothing if the socket does not exist
2020
}
2121

2222
for (let i = 0; i < workers; i++) {

docs/api/Agent.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Extends: [`PoolOptions`](Pool.md#parameter-pooloptions)
2020

2121
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`
2222
* **maxRedirections** `Integer` - Default: `0`. The number of HTTP redirection to follow unless otherwise specified in `DispatchOptions`.
23-
* **interceptors** `{ Agent: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching).
23+
* **interceptors** `{ Agent: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time.
2424

2525
## Instance Properties
2626

docs/api/Client.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Returns: `Client`
2626
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
2727
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
2828
* **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body.
29-
* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching).
29+
* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time.
3030

3131
#### Parameter: `ConnectOptions`
3232

docs/api/ProxyAgent.md

+22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Returns: `ProxyAgent`
1717
Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
1818

1919
* **uri** `string` (required) - It can be passed either by a string or a object containing `uri` as string.
20+
* **token** `string` (optional) - It can be passed by a string of token for authentication.
21+
* **auth** `string` (**deprecated**) - Use token.
2022

2123
Examples:
2224

@@ -74,6 +76,26 @@ for await (const data of body) {
7476
}
7577
```
7678

79+
#### Example - Basic Proxy Request with authentication
80+
81+
```js
82+
import { setGlobalDispatcher, request, ProxyAgent } from 'undici';
83+
84+
const proxyAgent = new ProxyAgent({
85+
uri: 'my.proxy.server',
86+
token: 'Bearer xxxx'
87+
});
88+
setGlobalDispatcher(proxyAgent);
89+
90+
const { statusCode, body } = await request('http://localhost:3000/foo');
91+
92+
console.log('response received', statusCode); // response received 200
93+
94+
for await (const data of body) {
95+
console.log('data', data.toString('utf8')); // data foo
96+
}
97+
```
98+
7799
### `ProxyAgent.close()`
78100

79101
Closes the proxy agent and waits for registered pools and clients to also close before resolving.

index-fetch.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
'use strict'
22

3-
const { getGlobalDispatcher } = require('./lib/global')
43
const fetchImpl = require('./lib/fetch').fetch
54

65
module.exports.fetch = async function fetch (resource) {
7-
const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher()
86
try {
9-
return await fetchImpl.apply(dispatcher, arguments)
7+
return await fetchImpl(...arguments)
108
} catch (err) {
119
Error.captureStackTrace(err, this)
1210
throw err

index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { request, pipeline, stream, connect, upgrade } from './types/api'
1818

1919
export * from './types/fetch'
2020
export * from './types/file'
21+
export * from './types/filereader'
2122
export * from './types/formdata'
2223
export * from './types/diagnostics-channel'
2324
export { Interceptable } from './types/mock-interceptor'

index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ if (nodeMajor > 16 || (nodeMajor === 16 && nodeMinor >= 8)) {
9898
if (!fetchImpl) {
9999
fetchImpl = require('./lib/fetch').fetch
100100
}
101-
const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher()
101+
102102
try {
103-
return await fetchImpl.apply(dispatcher, arguments)
103+
return await fetchImpl(...arguments)
104104
} catch (err) {
105105
Error.captureStackTrace(err, this)
106106
throw err
@@ -111,6 +111,7 @@ if (nodeMajor > 16 || (nodeMajor === 16 && nodeMinor >= 8)) {
111111
module.exports.Request = require('./lib/fetch/request').Request
112112
module.exports.FormData = require('./lib/fetch/formdata').FormData
113113
module.exports.File = require('./lib/fetch/file').File
114+
module.exports.FileReader = require('./lib/fileapi/filereader').FileReader
114115

115116
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/fetch/global')
116117

lib/api/api-stream.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class StreamHandler extends AsyncResource {
106106
}
107107

108108
res.on('drain', resume)
109-
// TODO: Avoid finished. It registers an unecessary amount of listeners.
109+
// TODO: Avoid finished. It registers an unnecessary amount of listeners.
110110
finished(res, { readable: false }, (err) => {
111111
const { callback, res, opaque, trailers, abort } = this
112112

lib/client.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ const {
6060
kClose,
6161
kDestroy,
6262
kDispatch,
63-
kInterceptors
63+
kInterceptors,
64+
kLocalAddress
6465
} = require('./core/symbols')
6566

6667
const kClosedResolve = Symbol('kClosedResolve')
@@ -102,7 +103,8 @@ class Client extends DispatcherBase {
102103
maxCachedSessions,
103104
maxRedirections,
104105
connect,
105-
maxRequestsPerClient
106+
maxRequestsPerClient,
107+
localAddress
106108
} = {}) {
107109
super()
108110

@@ -170,6 +172,10 @@ class Client extends DispatcherBase {
170172
throw new InvalidArgumentError('maxRequestsPerClient must be a positive number')
171173
}
172174

175+
if (localAddress != null && (typeof localAddress !== 'string' || net.isIP(localAddress) === 0)) {
176+
throw new InvalidArgumentError('localAddress must be valid string IP address')
177+
}
178+
173179
if (typeof connect !== 'function') {
174180
connect = buildConnector({
175181
...tls,
@@ -193,6 +199,7 @@ class Client extends DispatcherBase {
193199
this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold
194200
this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]
195201
this[kServerName] = null
202+
this[kLocalAddress] = localAddress != null ? localAddress : null
196203
this[kResuming] = 0 // 0, idle, 1, scheduled, 2 resuming
197204
this[kNeedDrain] = 0 // 0, idle, 1, scheduled, 2 resuming
198205
this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}\r\n`
@@ -1020,7 +1027,8 @@ async function connect (client) {
10201027
hostname,
10211028
protocol,
10221029
port,
1023-
servername: client[kServerName]
1030+
servername: client[kServerName],
1031+
localAddress: client[kLocalAddress]
10241032
},
10251033
connector: client[kConnector]
10261034
})
@@ -1033,7 +1041,8 @@ async function connect (client) {
10331041
hostname,
10341042
protocol,
10351043
port,
1036-
servername: client[kServerName]
1044+
servername: client[kServerName],
1045+
localAddress: client[kLocalAddress]
10371046
}, (err, socket) => {
10381047
if (err) {
10391048
reject(err)
@@ -1076,7 +1085,8 @@ async function connect (client) {
10761085
hostname,
10771086
protocol,
10781087
port,
1079-
servername: client[kServerName]
1088+
servername: client[kServerName],
1089+
localAddress: client[kLocalAddress]
10801090
},
10811091
connector: client[kConnector],
10821092
socket
@@ -1093,7 +1103,8 @@ async function connect (client) {
10931103
hostname,
10941104
protocol,
10951105
port,
1096-
servername: client[kServerName]
1106+
servername: client[kServerName],
1107+
localAddress: client[kLocalAddress]
10971108
},
10981109
connector: client[kConnector],
10991110
error: err

lib/core/connect.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
2121
timeout = timeout == null ? 10e3 : timeout
2222
maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions
2323

24-
return function connect ({ hostname, host, protocol, port, servername, httpSocket }, callback) {
24+
return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) {
2525
let socket
2626
if (protocol === 'https:') {
2727
if (!tls) {
@@ -39,6 +39,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
3939
...options,
4040
servername,
4141
session,
42+
localAddress,
4243
socket: httpSocket, // upgrade socket connection
4344
port: port || 443,
4445
host: hostname
@@ -70,6 +71,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
7071
socket = net.connect({
7172
highWaterMark: 64 * 1024, // Same as nodejs fs streams.
7273
...options,
74+
localAddress,
7375
port: port || 80,
7476
host: hostname
7577
})

lib/core/symbols.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = {
1717
kHeadersTimeout: Symbol('headers timeout'),
1818
kBodyTimeout: Symbol('body timeout'),
1919
kServerName: Symbol('server name'),
20+
kLocalAddress: Symbol('local address'),
2021
kHost: Symbol('host'),
2122
kNoRef: Symbol('no ref'),
2223
kBodyUsed: Symbol('used'),

lib/core/util.js

+4-34
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const net = require('net')
88
const { InvalidArgumentError } = require('./errors')
99
const { Blob } = require('buffer')
1010
const nodeUtil = require('util')
11+
const { stringify } = require('querystring')
1112

1213
function nop () {}
1314

@@ -26,46 +27,15 @@ function isBlobLike (object) {
2627
)
2728
}
2829

29-
function isObject (val) {
30-
return val !== null && typeof val === 'object'
31-
}
32-
33-
// this escapes all non-uri friendly characters
34-
function encode (val) {
35-
return encodeURIComponent(val)
36-
}
37-
38-
// based on https://github.com/axios/axios/blob/63e559fa609c40a0a460ae5d5a18c3470ffc6c9e/lib/helpers/buildURL.js (MIT license)
3930
function buildURL (url, queryParams) {
4031
if (url.includes('?') || url.includes('#')) {
4132
throw new Error('Query params cannot be passed when url already contains "?" or "#".')
4233
}
43-
if (!isObject(queryParams)) {
44-
throw new Error('Query params must be an object')
45-
}
46-
47-
const parts = []
48-
for (let [key, val] of Object.entries(queryParams)) {
49-
if (val === null || typeof val === 'undefined') {
50-
continue
51-
}
52-
53-
if (!Array.isArray(val)) {
54-
val = [val]
55-
}
56-
57-
for (const v of val) {
58-
if (isObject(v)) {
59-
throw new Error('Passing object as a query param is not supported, please serialize to string up-front')
60-
}
61-
parts.push(encode(key) + '=' + encode(v))
62-
}
63-
}
6434

65-
const serializedParams = parts.join('&')
35+
const stringified = stringify(queryParams)
6636

67-
if (serializedParams) {
68-
url += '?' + serializedParams
37+
if (stringified) {
38+
url += '?' + stringified
6939
}
7040

7141
return url

0 commit comments

Comments
 (0)