undici 6.2.1 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -32
- package/docs/api/Debug.md +62 -0
- package/docs/api/DiagnosticsChannel.md +3 -3
- package/docs/api/RedirectHandler.md +96 -0
- package/index-fetch.js +3 -1
- package/index.js +4 -20
- package/lib/api/abort-signal.js +2 -2
- package/lib/cache/cache.js +89 -73
- package/lib/cache/cachestorage.js +1 -1
- package/lib/client.js +31 -30
- package/lib/compat/dispatcher-weakref.js +2 -0
- package/lib/core/diagnostics.js +202 -0
- package/lib/core/request.js +1 -17
- package/lib/core/util.js +2 -8
- package/lib/fetch/body.js +6 -4
- package/lib/fetch/dataURL.js +34 -12
- package/lib/fetch/file.js +2 -8
- package/lib/fetch/index.js +9 -13
- package/lib/fetch/request.js +68 -24
- package/lib/fetch/response.js +1 -1
- package/lib/fetch/util.js +12 -4
- package/lib/fetch/webidl.js +3 -3
- package/lib/handler/RedirectHandler.js +11 -0
- package/lib/mock/mock-utils.js +15 -5
- package/lib/proxy-agent.js +2 -2
- package/lib/websocket/connection.js +1 -6
- package/lib/websocket/receiver.js +1 -5
- package/lib/websocket/websocket.js +1 -1
- package/package.json +22 -14
- package/types/balanced-pool.d.ts +11 -0
- package/types/client.d.ts +11 -0
- package/types/dispatcher.d.ts +8 -1
- package/types/handlers.d.ts +10 -4
- package/types/pool.d.ts +11 -0
- package/types/proxy-agent.d.ts +0 -2
- package/types/readable.d.ts +2 -3
package/README.md
CHANGED
|
@@ -18,34 +18,21 @@ npm i undici
|
|
|
18
18
|
## Benchmarks
|
|
19
19
|
|
|
20
20
|
The benchmark is a simple `hello world` [example](benchmarks/benchmark.js) using a
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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 % |
|
|
48
|
-
|
|
21
|
+
50 TCP connections with a pipelining depth of 10 running on Node 20.10.0.
|
|
22
|
+
|
|
23
|
+
│ Tests │ Samples │ Result │ Tolerance │ Difference with slowest │
|
|
24
|
+
|─────────────────────|─────────|─────────────────|───────────|─────────────────────────|
|
|
25
|
+
│ got │ 45 │ 1661.71 req/sec │ ± 2.93 % │ - │
|
|
26
|
+
│ node-fetch │ 20 │ 2164.81 req/sec │ ± 2.63 % │ + 30.28 % │
|
|
27
|
+
│ undici - fetch │ 35 │ 2274.27 req/sec │ ± 2.70 % │ + 36.86 % │
|
|
28
|
+
│ http - no keepalive │ 15 │ 2376.04 req/sec │ ± 2.99 % │ + 42.99 % │
|
|
29
|
+
│ axios │ 25 │ 2612.93 req/sec │ ± 2.89 % │ + 57.24 % │
|
|
30
|
+
│ request │ 40 │ 2712.19 req/sec │ ± 2.92 % │ + 63.22 % │
|
|
31
|
+
│ http - keepalive │ 45 │ 4393.25 req/sec │ ± 2.86 % │ + 164.38 % │
|
|
32
|
+
│ undici - pipeline │ 45 │ 5484.69 req/sec │ ± 2.87 % │ + 230.06 % │
|
|
33
|
+
│ undici - request │ 55 │ 7773.98 req/sec │ ± 2.93 % │ + 367.83 % │
|
|
34
|
+
│ undici - stream │ 70 │ 8425.96 req/sec │ ± 2.91 % │ + 407.07 % │
|
|
35
|
+
│ undici - dispatch │ 50 │ 9488.99 req/sec │ ± 2.85 % │ + 471.04 % │
|
|
49
36
|
|
|
50
37
|
## Quick Start
|
|
51
38
|
|
|
@@ -62,9 +49,7 @@ const {
|
|
|
62
49
|
console.log('response received', statusCode)
|
|
63
50
|
console.log('headers', headers)
|
|
64
51
|
|
|
65
|
-
for await (const data of body) {
|
|
66
|
-
console.log('data', data)
|
|
67
|
-
}
|
|
52
|
+
for await (const data of body) { console.log('data', data) }
|
|
68
53
|
|
|
69
54
|
console.log('trailers', trailers)
|
|
70
55
|
```
|
|
@@ -119,7 +104,7 @@ Returns a promise with the result of the `Dispatcher.request` method.
|
|
|
119
104
|
|
|
120
105
|
Calls `options.dispatcher.request(options)`.
|
|
121
106
|
|
|
122
|
-
See [Dispatcher.request](./docs/api/Dispatcher.md#dispatcherrequestoptions-callback) for more details.
|
|
107
|
+
See [Dispatcher.request](./docs/api/Dispatcher.md#dispatcherrequestoptions-callback) for more details, and [request examples](./examples/README.md) for examples.
|
|
123
108
|
|
|
124
109
|
### `undici.stream([url, options, ]factory): Promise`
|
|
125
110
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Debug
|
|
2
|
+
|
|
3
|
+
Undici (and subsenquently `fetch` and `websocket`) exposes a debug statement that can be enabled by setting `NODE_DEBUG` within the environment.
|
|
4
|
+
|
|
5
|
+
The flags availabile are:
|
|
6
|
+
|
|
7
|
+
## `undici`
|
|
8
|
+
|
|
9
|
+
This flag enables debug statements for the core undici library.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
NODE_DEBUG=undici node script.js
|
|
13
|
+
|
|
14
|
+
UNDICI 16241: connecting to nodejs.org using https:h1
|
|
15
|
+
UNDICI 16241: connecting to nodejs.org using https:h1
|
|
16
|
+
UNDICI 16241: connected to nodejs.org using https:h1
|
|
17
|
+
UNDICI 16241: sending request to GET https://nodejs.org//
|
|
18
|
+
UNDICI 16241: received response to GET https://nodejs.org// - HTTP 307
|
|
19
|
+
UNDICI 16241: connecting to nodejs.org using https:h1
|
|
20
|
+
UNDICI 16241: trailers received from GET https://nodejs.org//
|
|
21
|
+
UNDICI 16241: connected to nodejs.org using https:h1
|
|
22
|
+
UNDICI 16241: sending request to GET https://nodejs.org//en
|
|
23
|
+
UNDICI 16241: received response to GET https://nodejs.org//en - HTTP 200
|
|
24
|
+
UNDICI 16241: trailers received from GET https://nodejs.org//en
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## `fetch`
|
|
28
|
+
|
|
29
|
+
This flag enables debug statements for the `fetch` API.
|
|
30
|
+
|
|
31
|
+
> **Note**: statements are pretty similar to the ones in the `undici` flag, but scoped to `fetch`
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
NODE_DEBUG=fetch node script.js
|
|
35
|
+
|
|
36
|
+
FETCH 16241: connecting to nodejs.org using https:h1
|
|
37
|
+
FETCH 16241: connecting to nodejs.org using https:h1
|
|
38
|
+
FETCH 16241: connected to nodejs.org using https:h1
|
|
39
|
+
FETCH 16241: sending request to GET https://nodejs.org//
|
|
40
|
+
FETCH 16241: received response to GET https://nodejs.org// - HTTP 307
|
|
41
|
+
FETCH 16241: connecting to nodejs.org using https:h1
|
|
42
|
+
FETCH 16241: trailers received from GET https://nodejs.org//
|
|
43
|
+
FETCH 16241: connected to nodejs.org using https:h1
|
|
44
|
+
FETCH 16241: sending request to GET https://nodejs.org//en
|
|
45
|
+
FETCH 16241: received response to GET https://nodejs.org//en - HTTP 200
|
|
46
|
+
FETCH 16241: trailers received from GET https://nodejs.org//en
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## `websocket`
|
|
50
|
+
|
|
51
|
+
This flag enables debug statements for the `Websocket` API.
|
|
52
|
+
|
|
53
|
+
> **Note**: statements can overlap with `UNDICI` ones if `undici` or `fetch` flag has been enabled as well.
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
NODE_DEBUG=websocket node script.js
|
|
57
|
+
|
|
58
|
+
WEBSOCKET 18309: connecting to echo.websocket.org using https:h1
|
|
59
|
+
WEBSOCKET 18309: connected to echo.websocket.org using https:h1
|
|
60
|
+
WEBSOCKET 18309: sending request to GET https://echo.websocket.org//
|
|
61
|
+
WEBSOCKET 18309: connection opened <ip_address>
|
|
62
|
+
```
|
|
@@ -105,7 +105,7 @@ You can not assume that this event is related to any specific request.
|
|
|
105
105
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
106
106
|
|
|
107
107
|
diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectParams, connector }) => {
|
|
108
|
-
// const { host, hostname, protocol, port, servername } = connectParams
|
|
108
|
+
// const { host, hostname, protocol, port, servername, version } = connectParams
|
|
109
109
|
// connector is a function that creates the socket
|
|
110
110
|
})
|
|
111
111
|
```
|
|
@@ -118,7 +118,7 @@ This message is published after a connection is established.
|
|
|
118
118
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
119
119
|
|
|
120
120
|
diagnosticsChannel.channel('undici:client:connected').subscribe(({ socket, connectParams, connector }) => {
|
|
121
|
-
// const { host, hostname, protocol, port, servername } = connectParams
|
|
121
|
+
// const { host, hostname, protocol, port, servername, version } = connectParams
|
|
122
122
|
// connector is a function that creates the socket
|
|
123
123
|
})
|
|
124
124
|
```
|
|
@@ -131,7 +131,7 @@ This message is published if it did not succeed to create new connection
|
|
|
131
131
|
import diagnosticsChannel from 'diagnostics_channel'
|
|
132
132
|
|
|
133
133
|
diagnosticsChannel.channel('undici:client:connectError').subscribe(({ error, socket, connectParams, connector }) => {
|
|
134
|
-
// const { host, hostname, protocol, port, servername } = connectParams
|
|
134
|
+
// const { host, hostname, protocol, port, servername, version } = connectParams
|
|
135
135
|
// connector is a function that creates the socket
|
|
136
136
|
console.log(`Connect failed with ${error.message}`)
|
|
137
137
|
})
|
|
@@ -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.
|
package/index-fetch.js
CHANGED
|
@@ -4,7 +4,9 @@ const fetchImpl = require('./lib/fetch').fetch
|
|
|
4
4
|
|
|
5
5
|
module.exports.fetch = function fetch (resource, init = undefined) {
|
|
6
6
|
return fetchImpl(resource, init).catch((err) => {
|
|
7
|
-
|
|
7
|
+
if (typeof err === 'object') {
|
|
8
|
+
Error.captureStackTrace(err, this)
|
|
9
|
+
}
|
|
8
10
|
throw err
|
|
9
11
|
})
|
|
10
12
|
}
|
package/index.js
CHANGED
|
@@ -21,14 +21,6 @@ const DecoratorHandler = require('./lib/handler/DecoratorHandler')
|
|
|
21
21
|
const RedirectHandler = require('./lib/handler/RedirectHandler')
|
|
22
22
|
const createRedirectInterceptor = require('./lib/interceptor/redirectInterceptor')
|
|
23
23
|
|
|
24
|
-
let hasCrypto
|
|
25
|
-
try {
|
|
26
|
-
require('crypto')
|
|
27
|
-
hasCrypto = true
|
|
28
|
-
} catch {
|
|
29
|
-
hasCrypto = false
|
|
30
|
-
}
|
|
31
|
-
|
|
32
24
|
Object.assign(Dispatcher.prototype, api)
|
|
33
25
|
|
|
34
26
|
module.exports.Dispatcher = Dispatcher
|
|
@@ -102,14 +94,10 @@ function makeDispatcher (fn) {
|
|
|
102
94
|
module.exports.setGlobalDispatcher = setGlobalDispatcher
|
|
103
95
|
module.exports.getGlobalDispatcher = getGlobalDispatcher
|
|
104
96
|
|
|
105
|
-
|
|
106
|
-
module.exports.fetch = async function fetch (
|
|
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) {
|
|
111
99
|
try {
|
|
112
|
-
return await fetchImpl(
|
|
100
|
+
return await fetchImpl(init, options)
|
|
113
101
|
} catch (err) {
|
|
114
102
|
if (typeof err === 'object') {
|
|
115
103
|
Error.captureStackTrace(err, this)
|
|
@@ -149,11 +137,7 @@ const { parseMIMEType, serializeAMimeType } = require('./lib/fetch/dataURL')
|
|
|
149
137
|
module.exports.parseMIMEType = parseMIMEType
|
|
150
138
|
module.exports.serializeAMimeType = serializeAMimeType
|
|
151
139
|
|
|
152
|
-
|
|
153
|
-
const { WebSocket } = require('./lib/websocket/websocket')
|
|
154
|
-
|
|
155
|
-
module.exports.WebSocket = WebSocket
|
|
156
|
-
}
|
|
140
|
+
module.exports.WebSocket = require('./lib/websocket/websocket').WebSocket
|
|
157
141
|
|
|
158
142
|
module.exports.request = makeDispatcher(api.request)
|
|
159
143
|
module.exports.stream = makeDispatcher(api.stream)
|
package/lib/api/abort-signal.js
CHANGED
|
@@ -6,9 +6,9 @@ const kSignal = Symbol('kSignal')
|
|
|
6
6
|
|
|
7
7
|
function abort (self) {
|
|
8
8
|
if (self.abort) {
|
|
9
|
-
self.abort()
|
|
9
|
+
self.abort(self[kSignal]?.reason)
|
|
10
10
|
} else {
|
|
11
|
-
self.onError(new RequestAbortedError())
|
|
11
|
+
self.onError(self[kSignal]?.reason ?? new RequestAbortedError())
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
package/lib/cache/cache.js
CHANGED
|
@@ -6,8 +6,9 @@ const { kEnumerableProperty, isDisturbed } = require('../core/util')
|
|
|
6
6
|
const { kHeadersList } = require('../core/symbols')
|
|
7
7
|
const { webidl } = require('../fetch/webidl')
|
|
8
8
|
const { Response, cloneResponse } = require('../fetch/response')
|
|
9
|
-
const { Request } = require('../fetch/request')
|
|
10
|
-
const {
|
|
9
|
+
const { Request, fromInnerRequest } = require('../fetch/request')
|
|
10
|
+
const { Headers } = require('../fetch/headers')
|
|
11
|
+
const { kState, kHeaders, kGuard } = require('../fetch/symbols')
|
|
11
12
|
const { fetching } = require('../fetch/index')
|
|
12
13
|
const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = require('../fetch/util')
|
|
13
14
|
const assert = require('assert')
|
|
@@ -49,7 +50,7 @@ class Cache {
|
|
|
49
50
|
request = webidl.converters.RequestInfo(request)
|
|
50
51
|
options = webidl.converters.CacheQueryOptions(options)
|
|
51
52
|
|
|
52
|
-
const p =
|
|
53
|
+
const p = this.#internalMatchAll(request, options, 1)
|
|
53
54
|
|
|
54
55
|
if (p.length === 0) {
|
|
55
56
|
return
|
|
@@ -64,66 +65,7 @@ class Cache {
|
|
|
64
65
|
if (request !== undefined) request = webidl.converters.RequestInfo(request)
|
|
65
66
|
options = webidl.converters.CacheQueryOptions(options)
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
let r = null
|
|
69
|
-
|
|
70
|
-
// 2.
|
|
71
|
-
if (request !== undefined) {
|
|
72
|
-
if (request instanceof Request) {
|
|
73
|
-
// 2.1.1
|
|
74
|
-
r = request[kState]
|
|
75
|
-
|
|
76
|
-
// 2.1.2
|
|
77
|
-
if (r.method !== 'GET' && !options.ignoreMethod) {
|
|
78
|
-
return []
|
|
79
|
-
}
|
|
80
|
-
} else if (typeof request === 'string') {
|
|
81
|
-
// 2.2.1
|
|
82
|
-
r = new Request(request)[kState]
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// 5.
|
|
87
|
-
// 5.1
|
|
88
|
-
const responses = []
|
|
89
|
-
|
|
90
|
-
// 5.2
|
|
91
|
-
if (request === undefined) {
|
|
92
|
-
// 5.2.1
|
|
93
|
-
for (const requestResponse of this.#relevantRequestResponseList) {
|
|
94
|
-
responses.push(requestResponse[1])
|
|
95
|
-
}
|
|
96
|
-
} else { // 5.3
|
|
97
|
-
// 5.3.1
|
|
98
|
-
const requestResponses = this.#queryCache(r, options)
|
|
99
|
-
|
|
100
|
-
// 5.3.2
|
|
101
|
-
for (const requestResponse of requestResponses) {
|
|
102
|
-
responses.push(requestResponse[1])
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// 5.4
|
|
107
|
-
// We don't implement CORs so we don't need to loop over the responses, yay!
|
|
108
|
-
|
|
109
|
-
// 5.5.1
|
|
110
|
-
const responseList = []
|
|
111
|
-
|
|
112
|
-
// 5.5.2
|
|
113
|
-
for (const response of responses) {
|
|
114
|
-
// 5.5.2.1
|
|
115
|
-
const responseObject = new Response(response.body?.source ?? null)
|
|
116
|
-
const body = responseObject[kState].body
|
|
117
|
-
responseObject[kState] = response
|
|
118
|
-
responseObject[kState].body = body
|
|
119
|
-
responseObject[kHeaders][kHeadersList] = response.headersList
|
|
120
|
-
responseObject[kHeaders][kGuard] = 'immutable'
|
|
121
|
-
|
|
122
|
-
responseList.push(responseObject)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 6.
|
|
126
|
-
return Object.freeze(responseList)
|
|
68
|
+
return this.#internalMatchAll(request, options)
|
|
127
69
|
}
|
|
128
70
|
|
|
129
71
|
async add (request) {
|
|
@@ -146,8 +88,6 @@ class Cache {
|
|
|
146
88
|
webidl.brandCheck(this, Cache)
|
|
147
89
|
webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.addAll' })
|
|
148
90
|
|
|
149
|
-
requests = webidl.converters['sequence<RequestInfo>'](requests)
|
|
150
|
-
|
|
151
91
|
// 1.
|
|
152
92
|
const responsePromises = []
|
|
153
93
|
|
|
@@ -155,7 +95,17 @@ class Cache {
|
|
|
155
95
|
const requestList = []
|
|
156
96
|
|
|
157
97
|
// 3.
|
|
158
|
-
for (
|
|
98
|
+
for (let request of requests) {
|
|
99
|
+
if (request === undefined) {
|
|
100
|
+
throw webidl.errors.conversionFailed({
|
|
101
|
+
prefix: 'Cache.addAll',
|
|
102
|
+
argument: 'Argument 1',
|
|
103
|
+
types: ['undefined is not allowed']
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
request = webidl.converters.RequestInfo(request)
|
|
108
|
+
|
|
159
109
|
if (typeof request === 'string') {
|
|
160
110
|
continue
|
|
161
111
|
}
|
|
@@ -494,7 +444,7 @@ class Cache {
|
|
|
494
444
|
* @see https://w3c.github.io/ServiceWorker/#dom-cache-keys
|
|
495
445
|
* @param {any} request
|
|
496
446
|
* @param {import('../../types/cache').CacheQueryOptions} options
|
|
497
|
-
* @returns {readonly Request[]}
|
|
447
|
+
* @returns {Promise<readonly Request[]>}
|
|
498
448
|
*/
|
|
499
449
|
async keys (request = undefined, options = {}) {
|
|
500
450
|
webidl.brandCheck(this, Cache)
|
|
@@ -553,12 +503,12 @@ class Cache {
|
|
|
553
503
|
|
|
554
504
|
// 5.4.2
|
|
555
505
|
for (const request of requests) {
|
|
556
|
-
const requestObject =
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
506
|
+
const requestObject = fromInnerRequest(
|
|
507
|
+
request,
|
|
508
|
+
new AbortController().signal,
|
|
509
|
+
'immutable',
|
|
510
|
+
{ settingsObject: request.client }
|
|
511
|
+
)
|
|
562
512
|
// 5.4.2.1
|
|
563
513
|
requestList.push(requestObject)
|
|
564
514
|
}
|
|
@@ -783,6 +733,72 @@ class Cache {
|
|
|
783
733
|
|
|
784
734
|
return true
|
|
785
735
|
}
|
|
736
|
+
|
|
737
|
+
#internalMatchAll (request, options, maxResponses = Infinity) {
|
|
738
|
+
// 1.
|
|
739
|
+
let r = null
|
|
740
|
+
|
|
741
|
+
// 2.
|
|
742
|
+
if (request !== undefined) {
|
|
743
|
+
if (request instanceof Request) {
|
|
744
|
+
// 2.1.1
|
|
745
|
+
r = request[kState]
|
|
746
|
+
|
|
747
|
+
// 2.1.2
|
|
748
|
+
if (r.method !== 'GET' && !options.ignoreMethod) {
|
|
749
|
+
return []
|
|
750
|
+
}
|
|
751
|
+
} else if (typeof request === 'string') {
|
|
752
|
+
// 2.2.1
|
|
753
|
+
r = new Request(request)[kState]
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// 5.
|
|
758
|
+
// 5.1
|
|
759
|
+
const responses = []
|
|
760
|
+
|
|
761
|
+
// 5.2
|
|
762
|
+
if (request === undefined) {
|
|
763
|
+
// 5.2.1
|
|
764
|
+
for (const requestResponse of this.#relevantRequestResponseList) {
|
|
765
|
+
responses.push(requestResponse[1])
|
|
766
|
+
}
|
|
767
|
+
} else { // 5.3
|
|
768
|
+
// 5.3.1
|
|
769
|
+
const requestResponses = this.#queryCache(r, options)
|
|
770
|
+
|
|
771
|
+
// 5.3.2
|
|
772
|
+
for (const requestResponse of requestResponses) {
|
|
773
|
+
responses.push(requestResponse[1])
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// 5.4
|
|
778
|
+
// We don't implement CORs so we don't need to loop over the responses, yay!
|
|
779
|
+
|
|
780
|
+
// 5.5.1
|
|
781
|
+
const responseList = []
|
|
782
|
+
|
|
783
|
+
// 5.5.2
|
|
784
|
+
for (const response of responses) {
|
|
785
|
+
// 5.5.2.1
|
|
786
|
+
const responseObject = new Response(kConstruct)
|
|
787
|
+
responseObject[kState] = response
|
|
788
|
+
responseObject[kHeaders] = new Headers(kConstruct)
|
|
789
|
+
responseObject[kHeaders][kHeadersList] = response.headersList
|
|
790
|
+
responseObject[kHeaders][kGuard] = 'immutable'
|
|
791
|
+
|
|
792
|
+
responseList.push(responseObject.clone())
|
|
793
|
+
|
|
794
|
+
if (responseList.length >= maxResponses) {
|
|
795
|
+
break
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// 6.
|
|
800
|
+
return Object.freeze(responseList)
|
|
801
|
+
}
|
|
786
802
|
}
|
|
787
803
|
|
|
788
804
|
Object.defineProperties(Cache.prototype, {
|
package/lib/client.js
CHANGED
|
@@ -9,6 +9,7 @@ const net = require('net')
|
|
|
9
9
|
const http = require('http')
|
|
10
10
|
const { pipeline } = require('stream')
|
|
11
11
|
const util = require('./core/util')
|
|
12
|
+
const { channels } = require('./core/diagnostics')
|
|
12
13
|
const timers = require('./timers')
|
|
13
14
|
const Request = require('./core/request')
|
|
14
15
|
const DispatcherBase = require('./dispatcher-base')
|
|
@@ -108,21 +109,6 @@ const FastBuffer = Buffer[Symbol.species]
|
|
|
108
109
|
|
|
109
110
|
const kClosedResolve = Symbol('kClosedResolve')
|
|
110
111
|
|
|
111
|
-
const channels = {}
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const diagnosticsChannel = require('diagnostics_channel')
|
|
115
|
-
channels.sendHeaders = diagnosticsChannel.channel('undici:client:sendHeaders')
|
|
116
|
-
channels.beforeConnect = diagnosticsChannel.channel('undici:client:beforeConnect')
|
|
117
|
-
channels.connectError = diagnosticsChannel.channel('undici:client:connectError')
|
|
118
|
-
channels.connected = diagnosticsChannel.channel('undici:client:connected')
|
|
119
|
-
} catch {
|
|
120
|
-
channels.sendHeaders = { hasSubscribers: false }
|
|
121
|
-
channels.beforeConnect = { hasSubscribers: false }
|
|
122
|
-
channels.connectError = { hasSubscribers: false }
|
|
123
|
-
channels.connected = { hasSubscribers: false }
|
|
124
|
-
}
|
|
125
|
-
|
|
126
112
|
/**
|
|
127
113
|
* @type {import('../types/client').default}
|
|
128
114
|
*/
|
|
@@ -1191,6 +1177,7 @@ async function connect (client) {
|
|
|
1191
1177
|
hostname,
|
|
1192
1178
|
protocol,
|
|
1193
1179
|
port,
|
|
1180
|
+
version: client[kHTTPConnVersion],
|
|
1194
1181
|
servername: client[kServerName],
|
|
1195
1182
|
localAddress: client[kLocalAddress]
|
|
1196
1183
|
},
|
|
@@ -1284,6 +1271,7 @@ async function connect (client) {
|
|
|
1284
1271
|
hostname,
|
|
1285
1272
|
protocol,
|
|
1286
1273
|
port,
|
|
1274
|
+
version: client[kHTTPConnVersion],
|
|
1287
1275
|
servername: client[kServerName],
|
|
1288
1276
|
localAddress: client[kLocalAddress]
|
|
1289
1277
|
},
|
|
@@ -1306,6 +1294,7 @@ async function connect (client) {
|
|
|
1306
1294
|
hostname,
|
|
1307
1295
|
protocol,
|
|
1308
1296
|
port,
|
|
1297
|
+
version: client[kHTTPConnVersion],
|
|
1309
1298
|
servername: client[kServerName],
|
|
1310
1299
|
localAddress: client[kLocalAddress]
|
|
1311
1300
|
},
|
|
@@ -1658,19 +1647,6 @@ function writeH2 (client, session, request) {
|
|
|
1658
1647
|
return false
|
|
1659
1648
|
}
|
|
1660
1649
|
|
|
1661
|
-
try {
|
|
1662
|
-
// TODO(HTTP/2): Should we call onConnect immediately or on stream ready event?
|
|
1663
|
-
request.onConnect((err) => {
|
|
1664
|
-
if (request.aborted || request.completed) {
|
|
1665
|
-
return
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
errorRequest(client, request, err || new RequestAbortedError())
|
|
1669
|
-
})
|
|
1670
|
-
} catch (err) {
|
|
1671
|
-
errorRequest(client, request, err)
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
1650
|
if (request.aborted) {
|
|
1675
1651
|
return false
|
|
1676
1652
|
}
|
|
@@ -1682,9 +1658,34 @@ function writeH2 (client, session, request) {
|
|
|
1682
1658
|
headers[HTTP2_HEADER_AUTHORITY] = host || client[kHost]
|
|
1683
1659
|
headers[HTTP2_HEADER_METHOD] = method
|
|
1684
1660
|
|
|
1661
|
+
try {
|
|
1662
|
+
// We are already connected, streams are pending.
|
|
1663
|
+
// We can call on connect, and wait for abort
|
|
1664
|
+
request.onConnect((err) => {
|
|
1665
|
+
if (request.aborted || request.completed) {
|
|
1666
|
+
return
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
err = err || new RequestAbortedError()
|
|
1670
|
+
|
|
1671
|
+
if (stream != null) {
|
|
1672
|
+
util.destroy(stream, err)
|
|
1673
|
+
|
|
1674
|
+
h2State.openStreams -= 1
|
|
1675
|
+
if (h2State.openStreams === 0) {
|
|
1676
|
+
session.unref()
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
errorRequest(client, request, err)
|
|
1681
|
+
})
|
|
1682
|
+
} catch (err) {
|
|
1683
|
+
errorRequest(client, request, err)
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1685
1686
|
if (method === 'CONNECT') {
|
|
1686
1687
|
session.ref()
|
|
1687
|
-
//
|
|
1688
|
+
// We are already connected, streams are pending, first request
|
|
1688
1689
|
// will create a new stream. We trigger a request to create the stream and wait until
|
|
1689
1690
|
// `ready` event is triggered
|
|
1690
1691
|
// We disabled endStream to allow the user to write to the stream
|
|
@@ -1768,7 +1769,7 @@ function writeH2 (client, session, request) {
|
|
|
1768
1769
|
|
|
1769
1770
|
session.ref()
|
|
1770
1771
|
|
|
1771
|
-
const shouldEndStream = method === 'GET' || method === 'HEAD'
|
|
1772
|
+
const shouldEndStream = method === 'GET' || method === 'HEAD' || body === null
|
|
1772
1773
|
if (expectContinue) {
|
|
1773
1774
|
headers[HTTP2_HEADER_EXPECT] = '100-continue'
|
|
1774
1775
|
stream = session.request(headers, { endStream: shouldEndStream, signal })
|