Skip to content

Commit dd4767f

Browse files
deps: update undici to 6.4.0
PR-URL: #51527 Reviewed-By: Matthew Aitken <maitken033380023@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 1cd9a95 commit dd4767f

28 files changed

+2277
-500
lines changed

deps/undici/src/README.md

+17-30
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,23 @@ npm i undici
1818
## Benchmarks
1919

2020
The benchmark is a simple `hello world` [example](benchmarks/benchmark.js) using a
21-
number of unix sockets (connections) with a pipelining depth of 10 running on Node 20.6.0.
22-
23-
### Connections 1
24-
25-
26-
| Tests | Samples | Result | Tolerance | Difference with slowest |
27-
|---------------------|---------|---------------|-----------|-------------------------|
28-
| http - no keepalive | 15 | 5.32 req/sec | ± 2.61 % | - |
29-
| http - keepalive | 10 | 5.35 req/sec | ± 2.47 % | + 0.44 % |
30-
| undici - fetch | 15 | 41.85 req/sec | ± 2.49 % | + 686.04 % |
31-
| undici - pipeline | 40 | 50.36 req/sec | ± 2.77 % | + 845.92 % |
32-
| undici - stream | 15 | 60.58 req/sec | ± 2.75 % | + 1037.72 % |
33-
| undici - request | 10 | 61.19 req/sec | ± 2.60 % | + 1049.24 % |
34-
| undici - dispatch | 20 | 64.84 req/sec | ± 2.81 % | + 1117.81 % |
35-
36-
37-
### Connections 50
38-
39-
| Tests | Samples | Result | Tolerance | Difference with slowest |
40-
|---------------------|---------|------------------|-----------|-------------------------|
41-
| undici - fetch | 30 | 2107.19 req/sec | ± 2.69 % | - |
42-
| http - no keepalive | 10 | 2698.90 req/sec | ± 2.68 % | + 28.08 % |
43-
| http - keepalive | 10 | 4639.49 req/sec | ± 2.55 % | + 120.17 % |
44-
| undici - pipeline | 40 | 6123.33 req/sec | ± 2.97 % | + 190.59 % |
45-
| undici - stream | 50 | 9426.51 req/sec | ± 2.92 % | + 347.35 % |
46-
| undici - request | 10 | 10162.88 req/sec | ± 2.13 % | + 382.29 % |
47-
| undici - dispatch | 50 | 11191.11 req/sec | ± 2.98 % | + 431.09 % |
21+
50 TCP connections with a pipelining depth of 10 running on Node 20.10.0.
4822

23+
```
24+
│ Tests │ Samples │ Result │ Tolerance │ Difference with slowest │
25+
|─────────────────────|─────────|─────────────────|───────────|─────────────────────────|
26+
│ got │ 45 │ 1661.71 req/sec │ ± 2.93 % │ - │
27+
│ node-fetch │ 20 │ 2164.81 req/sec │ ± 2.63 % │ + 30.28 % │
28+
│ undici - fetch │ 35 │ 2274.27 req/sec │ ± 2.70 % │ + 36.86 % │
29+
│ http - no keepalive │ 15 │ 2376.04 req/sec │ ± 2.99 % │ + 42.99 % │
30+
│ axios │ 25 │ 2612.93 req/sec │ ± 2.89 % │ + 57.24 % │
31+
│ request │ 40 │ 2712.19 req/sec │ ± 2.92 % │ + 63.22 % │
32+
│ http - keepalive │ 45 │ 4393.25 req/sec │ ± 2.86 % │ + 164.38 % │
33+
│ undici - pipeline │ 45 │ 5484.69 req/sec │ ± 2.87 % │ + 230.06 % │
34+
│ undici - request │ 55 │ 7773.98 req/sec │ ± 2.93 % │ + 367.83 % │
35+
│ undici - stream │ 70 │ 8425.96 req/sec │ ± 2.91 % │ + 407.07 % │
36+
│ undici - dispatch │ 50 │ 9488.99 req/sec │ ± 2.85 % │ + 471.04 % │
37+
```
4938

5039
## Quick Start
5140

@@ -62,9 +51,7 @@ const {
6251
console.log('response received', statusCode)
6352
console.log('headers', headers)
6453

65-
for await (const data of body) {
66-
console.log('data', data)
67-
}
54+
for await (const data of body) { console.log('data', data) }
6855

6956
console.log('trailers', trailers)
7057
```

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ This flag enables debug statements for the `Websocket` API.
5353
> **Note**: statements can overlap with `UNDICI` ones if `undici` or `fetch` flag has been enabled as well.
5454
5555
```sh
56-
NODE_DEBUG=fetch node script.js
56+
NODE_DEBUG=websocket node script.js
5757

5858
WEBSOCKET 18309: connecting to echo.websocket.org using https:h1
5959
WEBSOCKET 18309: connected to echo.websocket.org using https:h1
6060
WEBSOCKET 18309: sending request to GET https://echo.websocket.org//
6161
WEBSOCKET 18309: connection opened <ip_address>
62-
```
62+
```
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# EventSource
2+
3+
Undici exposes a WHATWG spec-compliant implementation of [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
4+
for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events).
5+
6+
## Instantiating EventSource
7+
8+
Undici exports a EventSource class. You can instantiate the EventSource as
9+
follows:
10+
11+
```mjs
12+
import { EventSource } from 'undici'
13+
14+
const evenSource = new EventSource('http://localhost:3000')
15+
evenSource.onmessage = (event) => {
16+
console.log(event.data)
17+
}
18+
```
19+
20+
More information about the EventSource API can be found on
21+
[MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Class: RedirectHandler
2+
3+
A class that handles redirection logic for HTTP requests.
4+
5+
## `new RedirectHandler(dispatch, maxRedirections, opts, handler, redirectionLimitReached)`
6+
7+
Arguments:
8+
9+
- **dispatch** `function` - The dispatch function to be called after every retry.
10+
- **maxRedirections** `number` - Maximum number of redirections allowed.
11+
- **opts** `object` - Options for handling redirection.
12+
- **handler** `object` - An object containing handlers for different stages of the request lifecycle.
13+
- **redirectionLimitReached** `boolean` (default: `false`) - A flag that the implementer can provide to enable or disable the feature. If set to `false`, it indicates that the caller doesn't want to use the feature and prefers the old behavior.
14+
15+
Returns: `RedirectHandler`
16+
17+
### Parameters
18+
19+
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every redirection.
20+
- **maxRedirections** `number` (required) - Maximum number of redirections allowed.
21+
- **opts** `object` (required) - Options for handling redirection.
22+
- **handler** `object` (required) - Handlers for different stages of the request lifecycle.
23+
- **redirectionLimitReached** `boolean` (default: `false`) - A flag that the implementer can provide to enable or disable the feature. If set to `false`, it indicates that the caller doesn't want to use the feature and prefers the old behavior.
24+
25+
### Properties
26+
27+
- **location** `string` - The current redirection location.
28+
- **abort** `function` - The abort function.
29+
- **opts** `object` - The options for handling redirection.
30+
- **maxRedirections** `number` - Maximum number of redirections allowed.
31+
- **handler** `object` - Handlers for different stages of the request lifecycle.
32+
- **history** `Array` - An array representing the history of URLs during redirection.
33+
- **redirectionLimitReached** `boolean` - Indicates whether the redirection limit has been reached.
34+
35+
### Methods
36+
37+
#### `onConnect(abort)`
38+
39+
Called when the connection is established.
40+
41+
Parameters:
42+
43+
- **abort** `function` - The abort function.
44+
45+
#### `onUpgrade(statusCode, headers, socket)`
46+
47+
Called when an upgrade is requested.
48+
49+
Parameters:
50+
51+
- **statusCode** `number` - The HTTP status code.
52+
- **headers** `object` - The headers received in the response.
53+
- **socket** `object` - The socket object.
54+
55+
#### `onError(error)`
56+
57+
Called when an error occurs.
58+
59+
Parameters:
60+
61+
- **error** `Error` - The error that occurred.
62+
63+
#### `onHeaders(statusCode, headers, resume, statusText)`
64+
65+
Called when headers are received.
66+
67+
Parameters:
68+
69+
- **statusCode** `number` - The HTTP status code.
70+
- **headers** `object` - The headers received in the response.
71+
- **resume** `function` - The resume function.
72+
- **statusText** `string` - The status text.
73+
74+
#### `onData(chunk)`
75+
76+
Called when data is received.
77+
78+
Parameters:
79+
80+
- **chunk** `Buffer` - The data chunk received.
81+
82+
#### `onComplete(trailers)`
83+
84+
Called when the request is complete.
85+
86+
Parameters:
87+
88+
- **trailers** `object` - The trailers received.
89+
90+
#### `onBodySent(chunk)`
91+
92+
Called when the request body is sent.
93+
94+
Parameters:
95+
96+
- **chunk** `Buffer` - The chunk of the request body sent.

deps/undici/src/index.js

+8-20
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ const DecoratorHandler = require('./lib/handler/DecoratorHandler')
2121
const RedirectHandler = require('./lib/handler/RedirectHandler')
2222
const createRedirectInterceptor = require('./lib/interceptor/redirectInterceptor')
2323

24-
let hasCrypto
25-
try {
26-
require('crypto')
27-
hasCrypto = true
28-
} catch {
29-
hasCrypto = false
30-
}
31-
3224
Object.assign(Dispatcher.prototype, api)
3325

3426
module.exports.Dispatcher = Dispatcher
@@ -102,14 +94,10 @@ function makeDispatcher (fn) {
10294
module.exports.setGlobalDispatcher = setGlobalDispatcher
10395
module.exports.getGlobalDispatcher = getGlobalDispatcher
10496

105-
let fetchImpl = null
106-
module.exports.fetch = async function fetch (resource) {
107-
if (!fetchImpl) {
108-
fetchImpl = require('./lib/fetch').fetch
109-
}
110-
97+
const fetchImpl = require('./lib/fetch').fetch
98+
module.exports.fetch = async function fetch (init, options = undefined) {
11199
try {
112-
return await fetchImpl(...arguments)
100+
return await fetchImpl(init, options)
113101
} catch (err) {
114102
if (typeof err === 'object') {
115103
Error.captureStackTrace(err, this)
@@ -149,11 +137,7 @@ const { parseMIMEType, serializeAMimeType } = require('./lib/fetch/dataURL')
149137
module.exports.parseMIMEType = parseMIMEType
150138
module.exports.serializeAMimeType = serializeAMimeType
151139

152-
if (hasCrypto) {
153-
const { WebSocket } = require('./lib/websocket/websocket')
154-
155-
module.exports.WebSocket = WebSocket
156-
}
140+
module.exports.WebSocket = require('./lib/websocket/websocket').WebSocket
157141

158142
module.exports.request = makeDispatcher(api.request)
159143
module.exports.stream = makeDispatcher(api.stream)
@@ -165,3 +149,7 @@ module.exports.MockClient = MockClient
165149
module.exports.MockPool = MockPool
166150
module.exports.MockAgent = MockAgent
167151
module.exports.mockErrors = mockErrors
152+
153+
const { EventSource } = require('./lib/eventsource/eventsource')
154+
155+
module.exports.EventSource = EventSource

deps/undici/src/lib/api/readable.js

+31-21
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ module.exports = class BodyReadable extends Readable {
9494
}
9595

9696
push (chunk) {
97-
if (this[kConsume] && chunk !== null && this.readableLength === 0) {
97+
if (this[kConsume] && chunk !== null) {
9898
consumePush(this[kConsume], chunk)
9999
return this[kReading] ? super.push(chunk) : true
100100
}
@@ -215,26 +215,28 @@ async function consume (stream, type) {
215215
reject(rState.errored ?? new TypeError('unusable'))
216216
}
217217
} else {
218-
stream[kConsume] = {
219-
type,
220-
stream,
221-
resolve,
222-
reject,
223-
length: 0,
224-
body: []
225-
}
218+
queueMicrotask(() => {
219+
stream[kConsume] = {
220+
type,
221+
stream,
222+
resolve,
223+
reject,
224+
length: 0,
225+
body: []
226+
}
226227

227-
stream
228-
.on('error', function (err) {
229-
consumeFinish(this[kConsume], err)
230-
})
231-
.on('close', function () {
232-
if (this[kConsume].body !== null) {
233-
consumeFinish(this[kConsume], new RequestAbortedError())
234-
}
235-
})
228+
stream
229+
.on('error', function (err) {
230+
consumeFinish(this[kConsume], err)
231+
})
232+
.on('close', function () {
233+
if (this[kConsume].body !== null) {
234+
consumeFinish(this[kConsume], new RequestAbortedError())
235+
}
236+
})
236237

237-
queueMicrotask(() => consumeStart(stream[kConsume]))
238+
consumeStart(stream[kConsume])
239+
})
238240
}
239241
})
240242
}
@@ -246,8 +248,16 @@ function consumeStart (consume) {
246248

247249
const { _readableState: state } = consume.stream
248250

249-
for (const chunk of state.buffer) {
250-
consumePush(consume, chunk)
251+
if (state.bufferIndex) {
252+
const start = state.bufferIndex
253+
const end = state.buffer.length
254+
for (let n = start; n < end; n++) {
255+
consumePush(consume, state.buffer[n])
256+
}
257+
} else {
258+
for (const chunk of state.buffer) {
259+
consumePush(consume, chunk)
260+
}
251261
}
252262

253263
if (state.endEmitted) {

0 commit comments

Comments
 (0)