Skip to content

Commit d8433f6

Browse files
mcollinaaduh95
authored andcommitted
deps: update undici to v6.24.1
Signed-off-by: Matteo Collina <hello@matteocollina.com>
1 parent d5ed384 commit d8433f6

File tree

15 files changed

+230
-53
lines changed

15 files changed

+230
-53
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { errors } from 'undici'
2727
| `InformationalError` | `UND_ERR_INFO` | expected error with reason |
2828
| `ResponseExceededMaxSizeError` | `UND_ERR_RES_EXCEEDED_MAX_SIZE` | response body exceed the max size allowed |
2929
| `SecureProxyConnectionError` | `UND_ERR_PRX_TLS` | tls connection to a proxy failed |
30+
| `MessageSizeExceededError` | `UND_ERR_WS_MESSAGE_SIZE_EXCEEDED` | WebSocket decompressed message exceeded the maximum allowed size |
3031

3132
### `SocketError`
3233

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ Arguments:
1313
* **url** `URL | string` - The url's protocol *must* be `ws` or `wss`.
1414
* **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](./Dispatcher.md).
1515

16+
### WebSocketInit
17+
18+
When passing an object as the second argument, the following options are available:
19+
20+
* **protocols** `string | string[]` (optional) - Subprotocol(s) to request the server use.
21+
* **dispatcher** `Dispatcher` (optional) - A custom [`Dispatcher`](/docs/docs/api/Dispatcher.md) to use for the connection.
22+
* **headers** `HeadersInit` (optional) - Custom headers to include in the WebSocket handshake request.
23+
1624
### Example:
1725

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

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,24 @@ class SecureProxyConnectionError extends UndiciError {
379379
[kSecureProxyConnectionError] = true
380380
}
381381

382+
const kMessageSizeExceededError = Symbol.for('undici.error.UND_ERR_WS_MESSAGE_SIZE_EXCEEDED')
383+
class MessageSizeExceededError extends UndiciError {
384+
constructor (message) {
385+
super(message)
386+
this.name = 'MessageSizeExceededError'
387+
this.message = message || 'Max decompressed message size exceeded'
388+
this.code = 'UND_ERR_WS_MESSAGE_SIZE_EXCEEDED'
389+
}
390+
391+
static [Symbol.hasInstance] (instance) {
392+
return instance && instance[kMessageSizeExceededError] === true
393+
}
394+
395+
get [kMessageSizeExceededError] () {
396+
return true
397+
}
398+
}
399+
382400
module.exports = {
383401
AbortError,
384402
HTTPParserError,
@@ -402,5 +420,6 @@ module.exports = {
402420
ResponseExceededMaxSizeError,
403421
RequestRetryError,
404422
ResponseError,
405-
SecureProxyConnectionError
423+
SecureProxyConnectionError,
424+
MessageSizeExceededError
406425
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ class Request {
6666
throw new InvalidArgumentError('upgrade must be a string')
6767
}
6868

69+
if (upgrade && !isValidHeaderValue(upgrade)) {
70+
throw new InvalidArgumentError('invalid upgrade header')
71+
}
72+
6973
if (headersTimeout != null && (!Number.isFinite(headersTimeout) || headersTimeout < 0)) {
7074
throw new InvalidArgumentError('invalid headersTimeout')
7175
}
@@ -360,13 +364,19 @@ function processHeader (request, key, val) {
360364
val = `${val}`
361365
}
362366

363-
if (request.host === null && headerName === 'host') {
367+
if (headerName === 'host') {
368+
if (request.host !== null) {
369+
throw new InvalidArgumentError('duplicate host header')
370+
}
364371
if (typeof val !== 'string') {
365372
throw new InvalidArgumentError('invalid host header')
366373
}
367374
// Consumed by Client
368375
request.host = val
369-
} else if (request.contentLength === null && headerName === 'content-length') {
376+
} else if (headerName === 'content-length') {
377+
if (request.contentLength !== null) {
378+
throw new InvalidArgumentError('duplicate content-length header')
379+
}
370380
request.contentLength = parseInt(val, 10)
371381
if (!Number.isFinite(request.contentLength)) {
372382
throw new InvalidArgumentError('invalid content-length header')
Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
2-
> undici@6.23.0 prebuild:wasm
3-
> node build/wasm.js --prebuild
4-
5-
> docker build --platform=linux/aarch64 -t llhttp_wasm_builder -f /Users/matteo/repos/node-private/deps/undici/src/build/Dockerfile /Users/matteo/repos/node-private/deps/undici/src
6-
7-
8-
9-
> undici@6.23.0 build:wasm
10-
> node build/wasm.js --docker
11-
12-
> docker run --rm -t --platform=linux/aarch64 --mount type=bind,source=/Users/matteo/repos/node-private/deps/undici/src/lib/llhttp,target=/home/node/undici/lib/llhttp llhttp_wasm_builder node build/wasm.js
13-
14-
1+
2+
> undici@6.24.1 prebuild:wasm
3+
> node build/wasm.js --prebuild
4+
5+
> docker build --platform=linux/x86_64 -t llhttp_wasm_builder -f /home/runner/work/node/node/deps/undici/src/build/Dockerfile /home/runner/work/node/node/deps/undici/src
6+
7+
8+
9+
> undici@6.24.1 build:wasm
10+
> node build/wasm.js --docker
11+
12+
> docker run --rm -t --platform=linux/x86_64 --user 1000:1000 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/undici/lib/llhttp llhttp_wasm_builder node build/wasm.js
13+
14+
1515
alpine-baselayout-3.4.3-r2
1616
alpine-baselayout-data-3.4.3-r2
1717
alpine-keys-2.4-r1
1818
apk-tools-2.14.0-r5
19-
binutils-2.41-r0
19+
binutils-2.41-r1
2020
busybox-1.36.1-r15
2121
busybox-binsh-1.36.1-r15
2222
ca-certificates-bundle-20230506-r0
@@ -37,15 +37,15 @@ libgomp-13.2.1_git20231014-r0
3737
libssl3-3.1.4-r5
3838
libstdc++-13.2.1_git20231014-r0
3939
libstdc++-dev-13.2.1_git20231014-r0
40-
libxml2-2.11.8-r0
40+
libxml2-2.11.8-r3
4141
lld-17.0.5-r0
4242
lld-libs-17.0.5-r0
4343
llvm17-libs-17.0.5-r0
4444
llvm17-linker-tools-17.0.5-r0
4545
mpc1-1.3.1-r1
4646
mpfr4-4.2.1-r0
47-
musl-1.2.4_git20230717-r4
48-
musl-dev-1.2.4_git20230717-r4
47+
musl-1.2.4_git20230717-r5
48+
musl-dev-1.2.4_git20230717-r5
4949
musl-utils-1.2.4_git20230717-r4
5050
scanelf-1.3.7-r2
5151
scudo-malloc-17.0.5-r0
@@ -54,7 +54,7 @@ wasi-compiler-rt-17.0.5-r1
5454
wasi-libc-0.20231012-r0
5555
wasi-libcxx-17.0.5-r0
5656
wasi-sdk-20-r3
57-
xz-libs-5.4.5-r0
57+
xz-libs-5.4.5-r1
5858
zlib-1.3.1-r0
5959
zstd-libs-1.5.5-r8
6060

deps/undici/src/lib/web/websocket/permessage-deflate.js

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,30 @@
22

33
const { createInflateRaw, Z_DEFAULT_WINDOWBITS } = require('node:zlib')
44
const { isValidClientWindowBits } = require('./util')
5+
const { MessageSizeExceededError } = require('../../core/errors')
56

67
const tail = Buffer.from([0x00, 0x00, 0xff, 0xff])
78
const kBuffer = Symbol('kBuffer')
89
const kLength = Symbol('kLength')
910

11+
// Default maximum decompressed message size: 4 MB
12+
const kDefaultMaxDecompressedSize = 4 * 1024 * 1024
13+
1014
class PerMessageDeflate {
1115
/** @type {import('node:zlib').InflateRaw} */
1216
#inflate
1317

1418
#options = {}
1519

20+
/** @type {boolean} */
21+
#aborted = false
22+
23+
/** @type {Function|null} */
24+
#currentCallback = null
25+
26+
/**
27+
* @param {Map<string, string>} extensions
28+
*/
1629
constructor (extensions) {
1730
this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover')
1831
this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits')
@@ -24,6 +37,11 @@ class PerMessageDeflate {
2437
// payload of the message.
2538
// 2. Decompress the resulting data using DEFLATE.
2639

40+
if (this.#aborted) {
41+
callback(new MessageSizeExceededError())
42+
return
43+
}
44+
2745
if (!this.#inflate) {
2846
let windowBits = Z_DEFAULT_WINDOWBITS
2947

@@ -36,13 +54,37 @@ class PerMessageDeflate {
3654
windowBits = Number.parseInt(this.#options.serverMaxWindowBits)
3755
}
3856

39-
this.#inflate = createInflateRaw({ windowBits })
57+
try {
58+
this.#inflate = createInflateRaw({ windowBits })
59+
} catch (err) {
60+
callback(err)
61+
return
62+
}
4063
this.#inflate[kBuffer] = []
4164
this.#inflate[kLength] = 0
4265

4366
this.#inflate.on('data', (data) => {
44-
this.#inflate[kBuffer].push(data)
67+
if (this.#aborted) {
68+
return
69+
}
70+
4571
this.#inflate[kLength] += data.length
72+
73+
if (this.#inflate[kLength] > kDefaultMaxDecompressedSize) {
74+
this.#aborted = true
75+
this.#inflate.removeAllListeners()
76+
this.#inflate.destroy()
77+
this.#inflate = null
78+
79+
if (this.#currentCallback) {
80+
const cb = this.#currentCallback
81+
this.#currentCallback = null
82+
cb(new MessageSizeExceededError())
83+
}
84+
return
85+
}
86+
87+
this.#inflate[kBuffer].push(data)
4688
})
4789

4890
this.#inflate.on('error', (err) => {
@@ -51,16 +93,22 @@ class PerMessageDeflate {
5193
})
5294
}
5395

96+
this.#currentCallback = callback
5497
this.#inflate.write(chunk)
5598
if (fin) {
5699
this.#inflate.write(tail)
57100
}
58101

59102
this.#inflate.flush(() => {
103+
if (this.#aborted || !this.#inflate) {
104+
return
105+
}
106+
60107
const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength])
61108

62109
this.#inflate[kBuffer].length = 0
63110
this.#inflate[kLength] = 0
111+
this.#currentCallback = null
64112

65113
callback(null, full)
66114
})

deps/undici/src/lib/web/websocket/receiver.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class ByteParser extends Writable {
3737
/** @type {Map<string, PerMessageDeflate>} */
3838
#extensions
3939

40+
/**
41+
* @param {import('./websocket').WebSocket} ws
42+
* @param {Map<string, string>|null} extensions
43+
*/
4044
constructor (ws, extensions) {
4145
super()
4246

@@ -179,21 +183,20 @@ class ByteParser extends Writable {
179183

180184
const buffer = this.consume(8)
181185
const upper = buffer.readUInt32BE(0)
186+
const lower = buffer.readUInt32BE(4)
182187

183188
// 2^31 is the maximum bytes an arraybuffer can contain
184189
// on 32-bit systems. Although, on 64-bit systems, this is
185190
// 2^53-1 bytes.
186191
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length
187192
// https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275
188193
// https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e
189-
if (upper > 2 ** 31 - 1) {
194+
if (upper !== 0 || lower > 2 ** 31 - 1) {
190195
failWebsocketConnection(this.ws, 'Received payload length > 2^31 bytes.')
191196
return
192197
}
193198

194-
const lower = buffer.readUInt32BE(4)
195-
196-
this.#info.payloadLength = (upper << 8) + lower
199+
this.#info.payloadLength = lower
197200
this.#state = parserStates.READ_DATA
198201
} else if (this.#state === parserStates.READ_DATA) {
199202
if (this.#byteOffset < this.#info.payloadLength) {
@@ -223,7 +226,7 @@ class ByteParser extends Writable {
223226
} else {
224227
this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => {
225228
if (error) {
226-
closeWebSocketConnection(this.ws, 1007, error.message, error.message.length)
229+
failWebsocketConnection(this.ws, error.message)
227230
return
228231
}
229232

deps/undici/src/lib/web/websocket/util.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,12 @@ function parseExtensions (extensions) {
266266
* @param {string} value
267267
*/
268268
function isValidClientWindowBits (value) {
269+
// Must have at least one character
270+
if (value.length === 0) {
271+
return false
272+
}
273+
274+
// Check all characters are ASCII digits
269275
for (let i = 0; i < value.length; i++) {
270276
const byte = value.charCodeAt(i)
271277

@@ -274,7 +280,9 @@ function isValidClientWindowBits (value) {
274280
}
275281
}
276282

277-
return true
283+
// Check numeric range: zlib requires windowBits in range 8-15
284+
const num = Number.parseInt(value, 10)
285+
return num >= 8 && num <= 15
278286
}
279287

280288
// https://nodejs.org/api/intl.html#detecting-internationalization-support

deps/undici/src/lib/web/websocket/websocket.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ class WebSocket extends EventTarget {
431431
* @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
432432
*/
433433
#onConnectionEstablished (response, parsedExtensions) {
434-
// processResponse is called when the "responses header list has been received and initialized."
434+
// processResponse is called when the "response's header list has been received and initialized."
435435
// once this happens, the connection is open
436436
this[kResponse] = response
437437

deps/undici/src/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "undici",
3-
"version": "6.23.0",
3+
"version": "6.24.1",
44
"description": "An HTTP/1.1 client, written from scratch for Node.js",
55
"homepage": "https://undici.nodejs.org",
66
"bugs": {
@@ -107,6 +107,7 @@
107107
"devDependencies": {
108108
"@fastify/busboy": "2.1.1",
109109
"@matteo.collina/tspl": "^0.1.1",
110+
"@metcoder95/https-pem": "^1.0.0",
110111
"@sinonjs/fake-timers": "^11.1.0",
111112
"@types/node": "~18.19.50",
112113
"abort-controller": "^3.0.0",
@@ -117,7 +118,6 @@
117118
"fast-check": "^3.17.1",
118119
"form-data": "^4.0.0",
119120
"formdata-node": "^6.0.3",
120-
"https-pem": "^3.0.0",
121121
"husky": "^9.0.7",
122122
"jest": "^29.0.2",
123123
"jsdom": "^24.0.0",

0 commit comments

Comments
 (0)