Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 51ded81

Browse filesBrowse files
nodejs-github-botrichardlau
authored andcommitted
deps: update undici to 7.22.0
PR-URL: #62035 Reviewed-By: Matthew Aitken <maitken033380023@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Richard Lau <richard.lau@ibm.com>
1 parent 4e54c10 commit 51ded81
Copy full SHA for 51ded81

13 files changed

+723-525Lines changed: 723 additions & 525 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎deps/undici/src/docs/docs/api/CacheStore.md‎

Copy file name to clipboardExpand all lines: deps/undici/src/docs/docs/api/CacheStore.md
+16-3Lines changed: 16 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ Parameters:
6666
Returns: `GetResult | Promise<GetResult | undefined> | undefined` - If the request is cached, the cached response is returned. If the request's method is anything other than HEAD, the response is also returned.
6767
If the request isn't cached, `undefined` is returned.
6868

69+
The `get` method may return a `Promise` for async cache stores (e.g. Redis-backed or remote stores). The cache interceptor handles both synchronous and asynchronous return values, including in revalidation paths (304 Not Modified handling and stale-while-revalidate background revalidation).
70+
6971
Response properties:
7072

7173
* **response** `CacheValue` - The cached response data.
72-
* **body** `Readable | undefined` - The response's body.
74+
* **body** `Readable | Iterable<Buffer> | undefined` - The response's body. This can be an array of `Buffer` chunks (with a `.values()` method) or a `Readable` stream. Both formats are supported in all code paths, including 304 revalidation.
7375

7476
### Function: `createWriteStream`
7577

@@ -98,8 +100,11 @@ This is an interface containing the majority of a response's data (minus the bod
98100

99101
### Property `vary`
100102

101-
`Record<string, string | string[]> | undefined` - The headers defined by the response's `Vary` header
102-
and their respective values for later comparison
103+
`Record<string, string | string[] | null> | undefined` - The headers defined by the response's `Vary` header
104+
and their respective values for later comparison. Values are `null` when the
105+
header specified in `Vary` was not present in the original request. These `null`
106+
values are automatically filtered out during revalidation so they are not sent
107+
as request headers.
103108

104109
For example, for a response like
105110
```
@@ -116,6 +121,14 @@ This would be
116121
}
117122
```
118123

124+
If the original request did not include the `accepts` header:
125+
```js
126+
{
127+
'content-encoding': 'utf8',
128+
accepts: null
129+
}
130+
```
131+
119132
### Property `cachedAt`
120133

121134
`number` - Time in millis that this value was cached.
Collapse file

‎deps/undici/src/docs/docs/api/WebSocket.md‎

Copy file name to clipboardExpand all lines: deps/undici/src/docs/docs/api/WebSocket.md
+3-3Lines changed: 3 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Arguments:
1515

1616
This example will not work in browsers or other platforms that don't allow passing an object.
1717

18-
```mjs
18+
```js
1919
import { WebSocket, ProxyAgent } from 'undici'
2020

2121
const proxyAgent = new ProxyAgent('my.proxy.server')
@@ -28,7 +28,7 @@ const ws = new WebSocket('wss://echo.websocket.events', {
2828

2929
If you do not need a custom Dispatcher, it's recommended to use the following pattern:
3030

31-
```mjs
31+
```js
3232
import { WebSocket } from 'undici'
3333

3434
const ws = new WebSocket('wss://echo.websocket.events', ['echo', 'chat'])
@@ -44,7 +44,7 @@ const ws = new WebSocket('wss://echo.websocket.events', ['echo', 'chat'])
4444
4545
This example will not work in browsers or other platforms that don't allow passing an object.
4646

47-
```mjs
47+
```js
4848
import { Agent } from 'undici'
4949

5050
const agent = new Agent({ allowH2: true })
Collapse file

‎deps/undici/src/lib/dispatcher/env-http-proxy-agent.js‎

Copy file name to clipboardExpand all lines: deps/undici/src/lib/dispatcher/env-http-proxy-agent.js
+10-11Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,14 @@ class EnvHttpProxyAgent extends DispatcherBase {
9595
if (entry.port && entry.port !== port) {
9696
continue // Skip if ports don't match.
9797
}
98-
if (!/^[.*]/.test(entry.hostname)) {
99-
// No wildcards, so don't proxy only if there is not an exact match.
100-
if (hostname === entry.hostname) {
101-
return false
102-
}
103-
} else {
104-
// Don't proxy if the hostname ends with the no_proxy host.
105-
if (hostname.endsWith(entry.hostname.replace(/^\*/, ''))) {
106-
return false
107-
}
98+
// Don't proxy if the hostname is equal with the no_proxy host.
99+
if (hostname === entry.hostname) {
100+
return false
101+
}
102+
// Don't proxy if the hostname is the subdomain of the no_proxy host.
103+
// Reference - https://github.com/denoland/deno/blob/6fbce91e40cc07fc6da74068e5cc56fdd40f7b4c/ext/fetch/proxy.rs#L485
104+
if (hostname.slice(-(entry.hostname.length + 1)) === `.${entry.hostname}`) {
105+
return false
108106
}
109107
}
110108

@@ -123,7 +121,8 @@ class EnvHttpProxyAgent extends DispatcherBase {
123121
}
124122
const parsed = entry.match(/^(.+):(\d+)$/)
125123
noProxyEntries.push({
126-
hostname: (parsed ? parsed[1] : entry).toLowerCase(),
124+
// strip leading dot or asterisk with dot
125+
hostname: (parsed ? parsed[1] : entry).replace(/^\*?\./, '').toLowerCase(),
127126
port: parsed ? Number.parseInt(parsed[2], 10) : 0
128127
})
129128
}
Collapse file

‎deps/undici/src/lib/handler/cache-handler.js‎

Copy file name to clipboardExpand all lines: deps/undici/src/lib/handler/cache-handler.js
+77-42Lines changed: 77 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -193,57 +193,92 @@ class CacheHandler {
193193
// Not modified, re-use the cached value
194194
// https://www.rfc-editor.org/rfc/rfc9111.html#name-handling-304-not-modified
195195
if (statusCode === 304) {
196-
/**
197-
* @type {import('../../types/cache-interceptor.d.ts').default.CacheValue}
198-
*/
199-
const cachedValue = this.#store.get(this.#cacheKey)
200-
if (!cachedValue) {
201-
// Do not create a new cache entry, as a 304 won't have a body - so cannot be cached.
202-
return downstreamOnHeaders()
203-
}
204-
205-
// Re-use the cached value: statuscode, statusmessage, headers and body
206-
value.statusCode = cachedValue.statusCode
207-
value.statusMessage = cachedValue.statusMessage
208-
value.etag = cachedValue.etag
209-
value.headers = { ...cachedValue.headers, ...strippedHeaders }
196+
const handle304 = (cachedValue) => {
197+
if (!cachedValue) {
198+
// Do not create a new cache entry, as a 304 won't have a body - so cannot be cached.
199+
return downstreamOnHeaders()
200+
}
210201

211-
downstreamOnHeaders()
202+
// Re-use the cached value: statuscode, statusmessage, headers and body
203+
value.statusCode = cachedValue.statusCode
204+
value.statusMessage = cachedValue.statusMessage
205+
value.etag = cachedValue.etag
206+
value.headers = { ...cachedValue.headers, ...strippedHeaders }
212207

213-
this.#writeStream = this.#store.createWriteStream(this.#cacheKey, value)
208+
downstreamOnHeaders()
214209

215-
if (!this.#writeStream || !cachedValue?.body) {
216-
return
217-
}
210+
this.#writeStream = this.#store.createWriteStream(this.#cacheKey, value)
218211

219-
const bodyIterator = cachedValue.body.values()
212+
if (!this.#writeStream || !cachedValue?.body) {
213+
return
214+
}
220215

221-
const streamCachedBody = () => {
222-
for (const chunk of bodyIterator) {
223-
const full = this.#writeStream.write(chunk) === false
224-
this.#handler.onResponseData?.(controller, chunk)
225-
// when stream is full stop writing until we get a 'drain' event
226-
if (full) {
227-
break
216+
if (typeof cachedValue.body.values === 'function') {
217+
const bodyIterator = cachedValue.body.values()
218+
219+
const streamCachedBody = () => {
220+
for (const chunk of bodyIterator) {
221+
const full = this.#writeStream.write(chunk) === false
222+
this.#handler.onResponseData?.(controller, chunk)
223+
// when stream is full stop writing until we get a 'drain' event
224+
if (full) {
225+
break
226+
}
227+
}
228228
}
229-
}
230-
}
231229

232-
this.#writeStream
233-
.on('error', function () {
234-
handler.#writeStream = undefined
235-
handler.#store.delete(handler.#cacheKey)
236-
})
237-
.on('drain', () => {
230+
this.#writeStream
231+
.on('error', function () {
232+
handler.#writeStream = undefined
233+
handler.#store.delete(handler.#cacheKey)
234+
})
235+
.on('drain', () => {
236+
streamCachedBody()
237+
})
238+
.on('close', function () {
239+
if (handler.#writeStream === this) {
240+
handler.#writeStream = undefined
241+
}
242+
})
243+
238244
streamCachedBody()
239-
})
240-
.on('close', function () {
241-
if (handler.#writeStream === this) {
242-
handler.#writeStream = undefined
243-
}
244-
})
245+
} else if (typeof cachedValue.body.on === 'function') {
246+
// Readable stream body (e.g. from async/remote cache stores)
247+
cachedValue.body
248+
.on('data', (chunk) => {
249+
this.#writeStream.write(chunk)
250+
this.#handler.onResponseData?.(controller, chunk)
251+
})
252+
.on('end', () => {
253+
this.#writeStream.end()
254+
})
255+
.on('error', () => {
256+
this.#writeStream = undefined
257+
this.#store.delete(this.#cacheKey)
258+
})
259+
260+
this.#writeStream
261+
.on('error', function () {
262+
handler.#writeStream = undefined
263+
handler.#store.delete(handler.#cacheKey)
264+
})
265+
.on('close', function () {
266+
if (handler.#writeStream === this) {
267+
handler.#writeStream = undefined
268+
}
269+
})
270+
}
271+
}
245272

246-
streamCachedBody()
273+
/**
274+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheValue}
275+
*/
276+
const result = this.#store.get(this.#cacheKey)
277+
if (result && typeof result.then === 'function') {
278+
result.then(handle304)
279+
} else {
280+
handle304(result)
281+
}
247282
} else {
248283
if (typeof resHeaders.etag === 'string' && isEtagUsable(resHeaders.etag)) {
249284
value.etag = resHeaders.etag
Collapse file

‎deps/undici/src/lib/interceptor/cache.js‎

Copy file name to clipboardExpand all lines: deps/undici/src/lib/interceptor/cache.js
+10-8Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ function handleResult (
292292

293293
// Start background revalidation (fire-and-forget)
294294
queueMicrotask(() => {
295-
let headers = {
295+
const headers = {
296296
...opts.headers,
297297
'if-modified-since': new Date(result.cachedAt).toUTCString()
298298
}
@@ -302,9 +302,10 @@ function handleResult (
302302
}
303303

304304
if (result.vary) {
305-
headers = {
306-
...headers,
307-
...result.vary
305+
for (const key in result.vary) {
306+
if (result.vary[key] != null) {
307+
headers[key] = result.vary[key]
308+
}
308309
}
309310
}
310311

@@ -335,7 +336,7 @@ function handleResult (
335336
withinStaleIfErrorThreshold = now < (result.staleAt + (staleIfErrorExpiry * 1000))
336337
}
337338

338-
let headers = {
339+
const headers = {
339340
...opts.headers,
340341
'if-modified-since': new Date(result.cachedAt).toUTCString()
341342
}
@@ -345,9 +346,10 @@ function handleResult (
345346
}
346347

347348
if (result.vary) {
348-
headers = {
349-
...headers,
350-
...result.vary
349+
for (const key in result.vary) {
350+
if (result.vary[key] != null) {
351+
headers[key] = result.vary[key]
352+
}
351353
}
352354
}
353355

Collapse file

‎deps/undici/src/lib/interceptor/deduplicate.js‎

Copy file name to clipboardExpand all lines: deps/undici/src/lib/interceptor/deduplicate.js
+1-3Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ module.exports = (opts = {}) => {
4646
// Convert to lowercase Set for case-insensitive header exclusion from deduplication key
4747
const excludeHeaderNamesSet = new Set(excludeHeaderNames.map(name => name.toLowerCase()))
4848

49-
const safeMethodsToNotDeduplicate = util.safeHTTPMethods.filter(method => methods.includes(method) === false)
50-
5149
/**
5250
* Map of pending requests for deduplication
5351
* @type {Map<string, DeduplicationHandler>}
@@ -56,7 +54,7 @@ module.exports = (opts = {}) => {
5654

5755
return dispatch => {
5856
return (opts, handler) => {
59-
if (!opts.origin || safeMethodsToNotDeduplicate.includes(opts.method)) {
57+
if (!opts.origin || methods.includes(opts.method) === false) {
6058
return dispatch(opts, handler)
6159
}
6260

Collapse file

‎deps/undici/src/lib/llhttp/wasm_build_env.txt‎

Copy file name to clipboardExpand all lines: deps/undici/src/lib/llhttp/wasm_build_env.txt
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
> undici@7.21.0 build:wasm
2+
> undici@7.22.0 build:wasm
33
> node build/wasm.js --docker
44

55
> docker run --rm --platform=linux/x86_64 --user 1001:1001 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/build/lib/llhttp --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/build,target=/home/node/build/build --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/deps,target=/home/node/build/deps -t ghcr.io/nodejs/wasm-builder@sha256:975f391d907e42a75b8c72eb77c782181e941608687d4d8694c3e9df415a0970 node build/wasm.js
Collapse file

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

Copy file name to clipboardExpand all lines: deps/undici/src/lib/web/fetch/index.js
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,6 +2302,41 @@ async function httpNetworkFetch (
23022302
reject(error)
23032303
},
23042304

2305+
onRequestUpgrade (_controller, status, headers, socket) {
2306+
// We need to support 200 for websocket over h2 as per RFC-8441
2307+
// Absence of session means H1
2308+
if ((socket.session != null && status !== 200) || (socket.session == null && status !== 101)) {
2309+
return false
2310+
}
2311+
2312+
const headersList = new HeadersList()
2313+
2314+
for (const [name, value] of Object.entries(headers)) {
2315+
if (value == null) {
2316+
continue
2317+
}
2318+
2319+
const headerName = name.toLowerCase()
2320+
2321+
if (Array.isArray(value)) {
2322+
for (const entry of value) {
2323+
headersList.append(headerName, String(entry), true)
2324+
}
2325+
} else {
2326+
headersList.append(headerName, String(value), true)
2327+
}
2328+
}
2329+
2330+
resolve({
2331+
status,
2332+
statusText: STATUS_CODES[status],
2333+
headersList,
2334+
socket
2335+
})
2336+
2337+
return true
2338+
},
2339+
23052340
onUpgrade (status, rawHeaders, socket) {
23062341
// We need to support 200 for websocket over h2 as per RFC-8441
23072342
// Absence of session means H1
Collapse file

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

Copy file name to clipboardExpand all lines: deps/undici/src/lib/web/fetch/util.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ function hasAuthenticationEntry (request) {
14391439
*/
14401440
function includesCredentials (url) {
14411441
// A URL includes credentials if its username or password is not the empty string.
1442-
return !!(url.username && url.password)
1442+
return !!(url.username || url.password)
14431443
}
14441444

14451445
/**

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.