Skip to content

Commit 99fec0b

Browse files
nodejs-github-bottargos
authored andcommitted
deps: update undici to 5.14.0
PR-URL: #45812 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent ca9b9b9 commit 99fec0b

16 files changed

+359
-137
lines changed

deps/undici/src/docs/api/Connector.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ Once you call `buildConnector`, it will return a connector function, which takes
2424
* **hostname** `string` (required)
2525
* **host** `string` (optional)
2626
* **protocol** `string` (required)
27-
* **port** `number` (required)
27+
* **port** `string` (required)
2828
* **servername** `string` (optional)
29+
* **localAddress** `string | null` (optional) Local address the socket should connect from.
30+
* **httpSocket** `Socket` (optional) Establish secure connection on a given socket rather than creating a new socket. It can only be sent on TLS update.
2931

3032
### Basic example
3133

deps/undici/src/lib/core/connect.js

+62-19
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,81 @@ const net = require('net')
44
const assert = require('assert')
55
const util = require('./util')
66
const { InvalidArgumentError, ConnectTimeoutError } = require('./errors')
7+
78
let tls // include tls conditionally since it is not always available
89

910
// TODO: session re-use does not wait for the first
1011
// connection to resolve the session and might therefore
1112
// resolve the same servername multiple times even when
1213
// re-use is enabled.
1314

15+
let SessionCache
16+
if (global.FinalizationRegistry) {
17+
SessionCache = class WeakSessionCache {
18+
constructor (maxCachedSessions) {
19+
this._maxCachedSessions = maxCachedSessions
20+
this._sessionCache = new Map()
21+
this._sessionRegistry = new global.FinalizationRegistry((key) => {
22+
if (this._sessionCache.size < this._maxCachedSessions) {
23+
return
24+
}
25+
26+
const ref = this._sessionCache.get(key)
27+
if (ref !== undefined && ref.deref() === undefined) {
28+
this._sessionCache.delete(key)
29+
}
30+
})
31+
}
32+
33+
get (sessionKey) {
34+
const ref = this._sessionCache.get(sessionKey)
35+
return ref ? ref.deref() : null
36+
}
37+
38+
set (sessionKey, session) {
39+
if (this._maxCachedSessions === 0) {
40+
return
41+
}
42+
43+
this._sessionCache.set(sessionKey, new WeakRef(session))
44+
this._sessionRegistry.register(session, sessionKey)
45+
}
46+
}
47+
} else {
48+
SessionCache = class SimpleSessionCache {
49+
constructor (maxCachedSessions) {
50+
this._maxCachedSessions = maxCachedSessions
51+
this._sessionCache = new Map()
52+
}
53+
54+
get (sessionKey) {
55+
return this._sessionCache.get(sessionKey)
56+
}
57+
58+
set (sessionKey, session) {
59+
if (this._maxCachedSessions === 0) {
60+
return
61+
}
62+
63+
if (this._sessionCache.size >= this._maxCachedSessions) {
64+
// remove the oldest session
65+
const { value: oldestKey } = this._sessionCache.keys().next()
66+
this._sessionCache.delete(oldestKey)
67+
}
68+
69+
this._sessionCache.set(sessionKey, session)
70+
}
71+
}
72+
}
73+
1474
function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
1575
if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) {
1676
throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero')
1777
}
1878

1979
const options = { path: socketPath, ...opts }
20-
const sessionCache = new Map()
80+
const sessionCache = new SessionCache(maxCachedSessions == null ? 100 : maxCachedSessions)
2181
timeout = timeout == null ? 10e3 : timeout
22-
maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions
2382

2483
return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) {
2584
let socket
@@ -47,25 +106,9 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
47106

48107
socket
49108
.on('session', function (session) {
50-
// cache is disabled
51-
if (maxCachedSessions === 0) {
52-
return
53-
}
54-
55-
if (sessionCache.size >= maxCachedSessions) {
56-
// remove the oldest session
57-
const { value: oldestKey } = sessionCache.keys().next()
58-
sessionCache.delete(oldestKey)
59-
}
60-
109+
// TODO (fix): Can a session become invalid once established? Don't think so?
61110
sessionCache.set(sessionKey, session)
62111
})
63-
.on('error', function (err) {
64-
if (sessionKey && err.code !== 'UND_ERR_INFO') {
65-
// TODO (fix): Only delete for session related errors.
66-
sessionCache.delete(sessionKey)
67-
}
68-
})
69112
} else {
70113
assert(!httpSocket, 'httpSocket can only be sent on TLS update')
71114
socket = net.connect({

deps/undici/src/lib/fetch/body.js

+38-7
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@ const { FormData } = require('./formdata')
77
const { kState } = require('./symbols')
88
const { webidl } = require('./webidl')
99
const { DOMException, structuredClone } = require('./constants')
10-
const { Blob } = require('buffer')
10+
const { Blob, File: NativeFile } = require('buffer')
1111
const { kBodyUsed } = require('../core/symbols')
1212
const assert = require('assert')
1313
const { isErrored } = require('../core/util')
1414
const { isUint8Array, isArrayBuffer } = require('util/types')
15-
const { File } = require('./file')
15+
const { File: UndiciFile } = require('./file')
1616
const { StringDecoder } = require('string_decoder')
1717
const { parseMIMEType, serializeAMimeType } = require('./dataURL')
1818

19-
/** @type {globalThis['ReadableStream']} */
20-
let ReadableStream
19+
let ReadableStream = globalThis.ReadableStream
20+
21+
/** @type {globalThis['File']} */
22+
const File = NativeFile ?? UndiciFile
2123

2224
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract
2325
function extractBody (object, keepalive = false) {
@@ -142,7 +144,33 @@ function extractBody (object, keepalive = false) {
142144
source = object
143145

144146
// Set length to unclear, see html/6424 for improving this.
145-
// TODO
147+
length = (() => {
148+
const prefixLength = prefix.length
149+
const boundaryLength = boundary.length
150+
let bodyLength = 0
151+
152+
for (const [name, value] of object) {
153+
if (typeof value === 'string') {
154+
bodyLength +=
155+
prefixLength +
156+
Buffer.byteLength(`; name="${escape(normalizeLinefeeds(name))}"\r\n\r\n${normalizeLinefeeds(value)}\r\n`)
157+
} else {
158+
bodyLength +=
159+
prefixLength +
160+
Buffer.byteLength(`; name="${escape(normalizeLinefeeds(name))}"` + (value.name ? `; filename="${escape(value.name)}"` : '')) +
161+
2 + // \r\n
162+
`Content-Type: ${
163+
value.type || 'application/octet-stream'
164+
}\r\n\r\n`.length
165+
166+
// value is a Blob or File, and \r\n
167+
bodyLength += value.size + 2
168+
}
169+
}
170+
171+
bodyLength += boundaryLength + 4 // --boundary--
172+
return bodyLength
173+
})()
146174

147175
// Set type to `multipart/form-data; boundary=`,
148176
// followed by the multipart/form-data boundary string generated
@@ -348,7 +376,10 @@ function bodyMixinMethods (instance) {
348376
let busboy
349377

350378
try {
351-
busboy = Busboy({ headers })
379+
busboy = Busboy({
380+
headers,
381+
defParamCharset: 'utf8'
382+
})
352383
} catch (err) {
353384
// Error due to headers:
354385
throw Object.assign(new TypeError(), { cause: err })
@@ -361,7 +392,7 @@ function bodyMixinMethods (instance) {
361392
const { filename, encoding, mimeType } = info
362393
const chunks = []
363394

364-
if (encoding.toLowerCase() === 'base64') {
395+
if (encoding === 'base64' || encoding.toLowerCase() === 'base64') {
365396
let base64chunk = ''
366397

367398
value.on('data', (chunk) => {

deps/undici/src/lib/fetch/file.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const { Blob } = require('buffer')
3+
const { Blob, File: NativeFile } = require('buffer')
44
const { types } = require('util')
55
const { kState } = require('./symbols')
66
const { isBlobLike } = require('./util')
@@ -329,11 +329,14 @@ function convertLineEndingsNative (s) {
329329
// rollup) will warn about circular dependencies. See:
330330
// https://github.com/nodejs/undici/issues/1629
331331
function isFileLike (object) {
332-
return object instanceof File || (
333-
object &&
334-
(typeof object.stream === 'function' ||
335-
typeof object.arrayBuffer === 'function') &&
336-
object[Symbol.toStringTag] === 'File'
332+
return (
333+
(NativeFile && object instanceof NativeFile) ||
334+
object instanceof File || (
335+
object &&
336+
(typeof object.stream === 'function' ||
337+
typeof object.arrayBuffer === 'function') &&
338+
object[Symbol.toStringTag] === 'File'
339+
)
337340
)
338341
}
339342

deps/undici/src/lib/fetch/formdata.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
const { isBlobLike, toUSVString, makeIterator } = require('./util')
44
const { kState } = require('./symbols')
5-
const { File, FileLike, isFileLike } = require('./file')
5+
const { File: UndiciFile, FileLike, isFileLike } = require('./file')
66
const { webidl } = require('./webidl')
7-
const { Blob } = require('buffer')
7+
const { Blob, File: NativeFile } = require('buffer')
8+
9+
/** @type {globalThis['File']} */
10+
const File = NativeFile ?? UndiciFile
811

912
// https://xhr.spec.whatwg.org/#formdata
1013
class FormData {

deps/undici/src/lib/fetch/headers.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'use strict'
44

55
const { kHeadersList } = require('../core/symbols')
6-
const { kGuard } = require('./symbols')
6+
const { kGuard, kHeadersCaseInsensitive } = require('./symbols')
77
const { kEnumerableProperty } = require('../core/util')
88
const {
99
makeIterator,
@@ -96,27 +96,27 @@ class HeadersList {
9696

9797
// 1. If list contains name, then set name to the first such
9898
// header’s name.
99-
name = name.toLowerCase()
100-
const exists = this[kHeadersMap].get(name)
99+
const lowercaseName = name.toLowerCase()
100+
const exists = this[kHeadersMap].get(lowercaseName)
101101

102102
// 2. Append (name, value) to list.
103103
if (exists) {
104-
this[kHeadersMap].set(name, `${exists}, ${value}`)
104+
this[kHeadersMap].set(lowercaseName, { name: exists.name, value: `${exists.value}, ${value}` })
105105
} else {
106-
this[kHeadersMap].set(name, `${value}`)
106+
this[kHeadersMap].set(lowercaseName, { name, value })
107107
}
108108
}
109109

110110
// https://fetch.spec.whatwg.org/#concept-header-list-set
111111
set (name, value) {
112112
this[kHeadersSortedMap] = null
113-
name = name.toLowerCase()
113+
const lowercaseName = name.toLowerCase()
114114

115115
// 1. If list contains name, then set the value of
116116
// the first such header to value and remove the
117117
// others.
118118
// 2. Otherwise, append header (name, value) to list.
119-
return this[kHeadersMap].set(name, value)
119+
return this[kHeadersMap].set(lowercaseName, { name, value })
120120
}
121121

122122
// https://fetch.spec.whatwg.org/#concept-header-list-delete
@@ -137,14 +137,26 @@ class HeadersList {
137137
// 2. Return the values of all headers in list whose name
138138
// is a byte-case-insensitive match for name,
139139
// separated from each other by 0x2C 0x20, in order.
140-
return this[kHeadersMap].get(name.toLowerCase()) ?? null
140+
return this[kHeadersMap].get(name.toLowerCase())?.value ?? null
141141
}
142142

143143
* [Symbol.iterator] () {
144-
for (const pair of this[kHeadersMap]) {
145-
yield pair
144+
// use the lowercased name
145+
for (const [name, { value }] of this[kHeadersMap]) {
146+
yield [name, value]
146147
}
147148
}
149+
150+
get [kHeadersCaseInsensitive] () {
151+
/** @type {string[]} */
152+
const flatList = []
153+
154+
for (const { name, value } of this[kHeadersMap].values()) {
155+
flatList.push(name, value)
156+
}
157+
158+
return flatList
159+
}
148160
}
149161

150162
// https://fetch.spec.whatwg.org/#headers-class

0 commit comments

Comments
 (0)