undici 4.9.4 → 4.10.2
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 +12 -12
- package/docs/api/Agent.md +17 -17
- package/docs/api/BalancedPool.md +15 -15
- package/docs/api/Client.md +12 -14
- package/docs/api/Dispatcher.md +2 -2
- package/docs/api/MockAgent.md +3 -3
- package/docs/api/MockClient.md +5 -5
- package/docs/api/MockPool.md +6 -4
- package/docs/api/Pool.md +16 -16
- package/docs/api/ProxyAgent.md +3 -3
- package/docs/api/api-lifecycle.md +9 -9
- package/index.d.ts +1 -0
- package/lib/core/util.js +1 -1
- package/lib/fetch/formdata.js +29 -8
- package/lib/fetch/headers.js +2 -6
- package/lib/fetch/index.js +1 -1
- package/lib/fetch/response.js +4 -4
- package/lib/fetch/util.js +55 -3
- package/lib/mock/mock-utils.js +7 -1
- package/lib/proxy-agent.js +4 -9
- package/package.json +13 -1
- package/types/mock-interceptor.d.ts +1 -1
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ Arguments:
|
|
|
93
93
|
|
|
94
94
|
* **url** `string | URL | UrlObject`
|
|
95
95
|
* **options** [`RequestOptions`](./docs/api/Dispatcher.md#parameter-requestoptions)
|
|
96
|
-
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#
|
|
96
|
+
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
97
97
|
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
|
|
98
98
|
* **maxRedirections** `Integer` - Default: `0`
|
|
99
99
|
|
|
@@ -109,7 +109,7 @@ Arguments:
|
|
|
109
109
|
|
|
110
110
|
* **url** `string | URL | UrlObject`
|
|
111
111
|
* **options** [`StreamOptions`](./docs/api/Dispatcher.md#parameter-streamoptions)
|
|
112
|
-
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#
|
|
112
|
+
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
113
113
|
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
|
|
114
114
|
* **maxRedirections** `Integer` - Default: `0`
|
|
115
115
|
* **factory** `Dispatcher.stream.factory`
|
|
@@ -118,7 +118,7 @@ Returns a promise with the result of the `Dispatcher.stream` method.
|
|
|
118
118
|
|
|
119
119
|
Calls `options.dispatcher.stream(options, factory)`.
|
|
120
120
|
|
|
121
|
-
See [Dispatcher.stream](docs/api/Dispatcher.md#
|
|
121
|
+
See [Dispatcher.stream](docs/api/Dispatcher.md#dispatcherstreamoptions-factory-callback) for more details.
|
|
122
122
|
|
|
123
123
|
### `undici.pipeline([url, options, ]handler): Duplex`
|
|
124
124
|
|
|
@@ -126,7 +126,7 @@ Arguments:
|
|
|
126
126
|
|
|
127
127
|
* **url** `string | URL | UrlObject`
|
|
128
128
|
* **options** [`PipelineOptions`](docs/api/Dispatcher.md#parameter-pipelineoptions)
|
|
129
|
-
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#
|
|
129
|
+
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
130
130
|
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
|
|
131
131
|
* **maxRedirections** `Integer` - Default: `0`
|
|
132
132
|
* **handler** `Dispatcher.pipeline.handler`
|
|
@@ -135,7 +135,7 @@ Returns: `stream.Duplex`
|
|
|
135
135
|
|
|
136
136
|
Calls `options.dispatch.pipeline(options, handler)`.
|
|
137
137
|
|
|
138
|
-
See [Dispatcher.pipeline](docs/api/Dispatcher.md#
|
|
138
|
+
See [Dispatcher.pipeline](docs/api/Dispatcher.md#dispatcherpipelineoptions-handler) for more details.
|
|
139
139
|
|
|
140
140
|
### `undici.connect([url, options]): Promise`
|
|
141
141
|
|
|
@@ -145,7 +145,7 @@ Arguments:
|
|
|
145
145
|
|
|
146
146
|
* **url** `string | URL | UrlObject`
|
|
147
147
|
* **options** [`ConnectOptions`](docs/api/Dispatcher.md#parameter-connectoptions)
|
|
148
|
-
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#
|
|
148
|
+
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
149
149
|
* **maxRedirections** `Integer` - Default: `0`
|
|
150
150
|
* **callback** `(err: Error | null, data: ConnectData | null) => void` (optional)
|
|
151
151
|
|
|
@@ -153,7 +153,7 @@ Returns a promise with the result of the `Dispatcher.connect` method.
|
|
|
153
153
|
|
|
154
154
|
Calls `options.dispatch.connect(options)`.
|
|
155
155
|
|
|
156
|
-
See [Dispatcher.connect](docs/api/Dispatcher.md#
|
|
156
|
+
See [Dispatcher.connect](docs/api/Dispatcher.md#dispatcherconnectoptions-callback) for more details.
|
|
157
157
|
|
|
158
158
|
### `undici.fetch(input[, init]): Promise`
|
|
159
159
|
|
|
@@ -162,7 +162,7 @@ Implements [fetch](https://fetch.spec.whatwg.org/#fetch-method).
|
|
|
162
162
|
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
|
|
163
163
|
* https://fetch.spec.whatwg.org/#fetch-method
|
|
164
164
|
|
|
165
|
-
Only supported on Node 16+.
|
|
165
|
+
Only supported on Node 16.5+.
|
|
166
166
|
|
|
167
167
|
This is [experimental](https://nodejs.org/api/documentation.html#documentation_stability_index) and is not yet fully compliant with the Fetch Standard. We plan to ship breaking changes to this feature until it is out of experimental.
|
|
168
168
|
|
|
@@ -170,7 +170,7 @@ Basic usage example:
|
|
|
170
170
|
|
|
171
171
|
```js
|
|
172
172
|
import {fetch} from 'undici';
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
async function fetchJson() {
|
|
175
175
|
const res = await fetch('https://example.com')
|
|
176
176
|
const json = await res.json()
|
|
@@ -180,7 +180,7 @@ Basic usage example:
|
|
|
180
180
|
|
|
181
181
|
#### `response.body`
|
|
182
182
|
|
|
183
|
-
Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html) which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`.
|
|
183
|
+
Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html) which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`.
|
|
184
184
|
|
|
185
185
|
```js
|
|
186
186
|
import {fetch} from 'undici';
|
|
@@ -208,7 +208,7 @@ garbage collection in Node is less aggressive and deterministic (due to the lack
|
|
|
208
208
|
of clear idle periods that browser have through the rendering refresh rate)
|
|
209
209
|
which means that leaving the release of connection resources to the garbage collector
|
|
210
210
|
can lead to excessive connection usage, reduced performance (due to less connection re-use),
|
|
211
|
-
and even stalls or deadlocks when running out of connections. Therefore, it is highly
|
|
211
|
+
and even stalls or deadlocks when running out of connections. Therefore, it is highly
|
|
212
212
|
recommended to always either consume or cancel the response body.
|
|
213
213
|
|
|
214
214
|
```js
|
|
@@ -234,7 +234,7 @@ Arguments:
|
|
|
234
234
|
|
|
235
235
|
* **url** `string | URL | UrlObject`
|
|
236
236
|
* **options** [`UpgradeOptions`](docs/api/Dispatcher.md#parameter-upgradeoptions)
|
|
237
|
-
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#
|
|
237
|
+
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
238
238
|
* **maxRedirections** `Integer` - Default: `0`
|
|
239
239
|
* **callback** `(error: Error | null, data: UpgradeData) => void` (optional)
|
|
240
240
|
|
package/docs/api/Agent.md
CHANGED
|
@@ -16,64 +16,64 @@ Returns: `Agent`
|
|
|
16
16
|
|
|
17
17
|
### Parameter: `AgentOptions`
|
|
18
18
|
|
|
19
|
-
Extends: [`ClientOptions`](
|
|
19
|
+
Extends: [`ClientOptions`](Pool.md#parameter-pooloptions)
|
|
20
20
|
|
|
21
|
-
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`
|
|
21
|
+
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`
|
|
22
22
|
* **maxRedirections** `Integer` - Default: `0`. The number of HTTP redirection to follow unless otherwise specified in `DispatchOptions`.
|
|
23
23
|
|
|
24
24
|
## Instance Properties
|
|
25
25
|
|
|
26
26
|
### `Agent.closed`
|
|
27
27
|
|
|
28
|
-
Implements [Client.closed](
|
|
28
|
+
Implements [Client.closed](Client.md#clientclosed)
|
|
29
29
|
|
|
30
30
|
### `Agent.destroyed`
|
|
31
31
|
|
|
32
|
-
Implements [Client.destroyed](
|
|
32
|
+
Implements [Client.destroyed](Client.md#clientdestroyed)
|
|
33
33
|
|
|
34
34
|
## Instance Methods
|
|
35
35
|
|
|
36
36
|
### `Agent.close([callback])`
|
|
37
37
|
|
|
38
|
-
Implements [`Dispatcher.close([callback])`](
|
|
38
|
+
Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
|
|
39
39
|
|
|
40
40
|
### `Agent.destroy([error, callback])`
|
|
41
41
|
|
|
42
|
-
Implements [`Dispatcher.destroy([error, callback])`](
|
|
42
|
+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
43
43
|
|
|
44
|
-
### `Agent.dispatch(options,
|
|
44
|
+
### `Agent.dispatch(options, handler: AgentDispatchOptions)`
|
|
45
45
|
|
|
46
|
-
Implements [`Dispatcher.dispatch(options,
|
|
46
|
+
Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
47
47
|
|
|
48
48
|
#### Parameter: `AgentDispatchOptions`
|
|
49
49
|
|
|
50
|
-
Extends: [`DispatchOptions
|
|
50
|
+
Extends: [`DispatchOptions`](Dispatcher.md#parameter-dispatchoptions)
|
|
51
51
|
|
|
52
52
|
* **origin** `string | URL`
|
|
53
53
|
* **maxRedirections** `Integer`.
|
|
54
54
|
|
|
55
|
-
Implements [`Dispatcher.destroy([error, callback])`](
|
|
55
|
+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
56
56
|
|
|
57
57
|
### `Agent.connect(options[, callback])`
|
|
58
58
|
|
|
59
|
-
See [`Dispatcher.connect(options[, callback])`](
|
|
59
|
+
See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
|
|
60
60
|
|
|
61
|
-
### `Agent.dispatch(options,
|
|
61
|
+
### `Agent.dispatch(options, handler)`
|
|
62
62
|
|
|
63
|
-
Implements [`Dispatcher.dispatch(options,
|
|
63
|
+
Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
64
64
|
|
|
65
65
|
### `Agent.pipeline(options, handler)`
|
|
66
66
|
|
|
67
|
-
See [`Dispatcher.pipeline(options, handler)`](
|
|
67
|
+
See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
|
|
68
68
|
|
|
69
69
|
### `Agent.request(options[, callback])`
|
|
70
70
|
|
|
71
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
71
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
72
72
|
|
|
73
73
|
### `Agent.stream(options, factory[, callback])`
|
|
74
74
|
|
|
75
|
-
See [`Dispatcher.stream(options, factory[, callback])`](
|
|
75
|
+
See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
|
|
76
76
|
|
|
77
77
|
### `Agent.upgrade(options[, callback])`
|
|
78
78
|
|
|
79
|
-
See [`Dispatcher.upgrade(options[, callback])`](
|
|
79
|
+
See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
|
package/docs/api/BalancedPool.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Extends: `undici.Dispatcher`
|
|
4
4
|
|
|
5
|
-
A pool of [Pool](
|
|
5
|
+
A pool of [Pool](Pool.md) instances connected to multiple upstreams.
|
|
6
6
|
|
|
7
7
|
Requests are not guaranteed to be dispatched in order of invocation.
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ Arguments:
|
|
|
17
17
|
|
|
18
18
|
The `PoolOptions` are passed to each of the `Pool` instances being created.
|
|
19
19
|
|
|
20
|
-
See: [`PoolOptions`](
|
|
20
|
+
See: [`PoolOptions`](Pool.md#parameter-pooloptions)
|
|
21
21
|
|
|
22
22
|
## Instance Properties
|
|
23
23
|
|
|
@@ -27,11 +27,11 @@ Returns an array of upstreams that were previously added.
|
|
|
27
27
|
|
|
28
28
|
### `BalancedPool.closed`
|
|
29
29
|
|
|
30
|
-
Implements [Client.closed](
|
|
30
|
+
Implements [Client.closed](Client.md#clientclosed)
|
|
31
31
|
|
|
32
32
|
### `BalancedPool.destroyed`
|
|
33
33
|
|
|
34
|
-
Implements [Client.destroyed](
|
|
34
|
+
Implements [Client.destroyed](Client.md#clientdestroyed)
|
|
35
35
|
|
|
36
36
|
## Instance Methods
|
|
37
37
|
|
|
@@ -49,46 +49,46 @@ Removes an upstream that was previously addded.
|
|
|
49
49
|
|
|
50
50
|
### `BalancedPool.close([callback])`
|
|
51
51
|
|
|
52
|
-
Implements [`Dispatcher.close([callback])`](
|
|
52
|
+
Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
|
|
53
53
|
|
|
54
54
|
### `BalancedPool.destroy([error, callback])`
|
|
55
55
|
|
|
56
|
-
Implements [`Dispatcher.destroy([error, callback])`](
|
|
56
|
+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
57
57
|
|
|
58
58
|
### `BalancedPool.connect(options[, callback])`
|
|
59
59
|
|
|
60
|
-
See [`Dispatcher.connect(options[, callback])`](
|
|
60
|
+
See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
|
|
61
61
|
|
|
62
62
|
### `BalancedPool.dispatch(options, handlers)`
|
|
63
63
|
|
|
64
|
-
Implements [`Dispatcher.dispatch(options, handlers)`](
|
|
64
|
+
Implements [`Dispatcher.dispatch(options, handlers)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
65
65
|
|
|
66
66
|
### `BalancedPool.pipeline(options, handler)`
|
|
67
67
|
|
|
68
|
-
See [`Dispatcher.pipeline(options, handler)`](
|
|
68
|
+
See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
|
|
69
69
|
|
|
70
70
|
### `BalancedPool.request(options[, callback])`
|
|
71
71
|
|
|
72
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
72
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
73
73
|
|
|
74
74
|
### `BalancedPool.stream(options, factory[, callback])`
|
|
75
75
|
|
|
76
|
-
See [`Dispatcher.stream(options, factory[, callback])`](
|
|
76
|
+
See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
|
|
77
77
|
|
|
78
78
|
### `BalancedPool.upgrade(options[, callback])`
|
|
79
79
|
|
|
80
|
-
See [`Dispatcher.upgrade(options[, callback])`](
|
|
80
|
+
See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
|
|
81
81
|
|
|
82
82
|
## Instance Events
|
|
83
83
|
|
|
84
84
|
### Event: `'connect'`
|
|
85
85
|
|
|
86
|
-
See [Dispatcher Event: `'connect'`](
|
|
86
|
+
See [Dispatcher Event: `'connect'`](Dispatcher.md#event-connect).
|
|
87
87
|
|
|
88
88
|
### Event: `'disconnect'`
|
|
89
89
|
|
|
90
|
-
See [Dispatcher Event: `'disconnect'`](
|
|
90
|
+
See [Dispatcher Event: `'disconnect'`](Dispatcher.md#event-disconnect).
|
|
91
91
|
|
|
92
92
|
### Event: `'drain'`
|
|
93
93
|
|
|
94
|
-
See [Dispatcher Event: `'drain'`](
|
|
94
|
+
See [Dispatcher Event: `'drain'`](Dispatcher.md#event-drain).
|
package/docs/api/Client.md
CHANGED
|
@@ -77,39 +77,37 @@ const client = new Client('https://localhost:3000', {
|
|
|
77
77
|
|
|
78
78
|
### `Client.close([callback])`
|
|
79
79
|
|
|
80
|
-
Implements [`Dispatcher.close([callback])`](
|
|
80
|
+
Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
|
|
81
81
|
|
|
82
82
|
### `Client.destroy([error, callback])`
|
|
83
83
|
|
|
84
|
-
Implements [`Dispatcher.destroy([error, callback])`](
|
|
84
|
+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
85
85
|
|
|
86
86
|
Waits until socket is closed before invoking the callback (or returning a promise if no callback is provided).
|
|
87
87
|
|
|
88
|
-
Implements [`Dispatcher.destroy([error, callback])`](docs/api/Dispatcher.md#dispatcher-callback-).
|
|
89
|
-
|
|
90
88
|
### `Client.connect(options[, callback])`
|
|
91
89
|
|
|
92
|
-
See [`Dispatcher.connect(options[, callback])`](
|
|
90
|
+
See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
|
|
93
91
|
|
|
94
92
|
### `Client.dispatch(options, handlers)`
|
|
95
93
|
|
|
96
|
-
Implements [`Dispatcher.dispatch(options, handlers)`](
|
|
94
|
+
Implements [`Dispatcher.dispatch(options, handlers)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
97
95
|
|
|
98
96
|
### `Client.pipeline(options, handler)`
|
|
99
97
|
|
|
100
|
-
See [`Dispatcher.pipeline(options, handler)`](
|
|
98
|
+
See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
|
|
101
99
|
|
|
102
100
|
### `Client.request(options[, callback])`
|
|
103
101
|
|
|
104
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
102
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
105
103
|
|
|
106
104
|
### `Client.stream(options, factory[, callback])`
|
|
107
105
|
|
|
108
|
-
See [`Dispatcher.stream(options, factory[, callback])`](
|
|
106
|
+
See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
|
|
109
107
|
|
|
110
108
|
### `Client.upgrade(options[, callback])`
|
|
111
109
|
|
|
112
|
-
See [`Dispatcher.upgrade(options[, callback])`](
|
|
110
|
+
See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
|
|
113
111
|
|
|
114
112
|
## Instance Properties
|
|
115
113
|
|
|
@@ -135,7 +133,7 @@ Property to get and set the pipelining factor.
|
|
|
135
133
|
|
|
136
134
|
### Event: `'connect'`
|
|
137
135
|
|
|
138
|
-
See [Dispatcher Event: `'connect'`](
|
|
136
|
+
See [Dispatcher Event: `'connect'`](Dispatcher.md#event-connect).
|
|
139
137
|
|
|
140
138
|
Parameters:
|
|
141
139
|
|
|
@@ -181,7 +179,7 @@ try {
|
|
|
181
179
|
|
|
182
180
|
### Event: `'disconnect'`
|
|
183
181
|
|
|
184
|
-
See [Dispatcher Event: `'disconnect'`](
|
|
182
|
+
See [Dispatcher Event: `'disconnect'`](Dispatcher.md#event-disconnect).
|
|
185
183
|
|
|
186
184
|
Parameters:
|
|
187
185
|
|
|
@@ -224,9 +222,9 @@ try {
|
|
|
224
222
|
|
|
225
223
|
### Event: `'drain'`
|
|
226
224
|
|
|
227
|
-
Emitted when pipeline is no longer
|
|
225
|
+
Emitted when pipeline is no longer busy.
|
|
228
226
|
|
|
229
|
-
See [Dispatcher Event: `'drain'`](
|
|
227
|
+
See [Dispatcher Event: `'drain'`](Dispatcher.md#event-drain).
|
|
230
228
|
|
|
231
229
|
#### Example - Client drain event
|
|
232
230
|
|
package/docs/api/Dispatcher.md
CHANGED
|
@@ -791,11 +791,11 @@ Emitted when dispatcher is no longer busy.
|
|
|
791
791
|
|
|
792
792
|
* `http.IncomingHttpHeaders | string[] | null`
|
|
793
793
|
|
|
794
|
-
Header arguments such as `options.headers` in [`Client.dispatch`](
|
|
794
|
+
Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in two forms; either as an object specified by the `http.IncomingHttpHeaders` type, or an array of strings. An array representation of a header list must have an even length or an `InvalidArgumentError` will be thrown.
|
|
795
795
|
|
|
796
796
|
Keys are lowercase and values are not modified.
|
|
797
797
|
|
|
798
|
-
Response headers will derive a `host` from the `url` of the [Client](#class-client) instance if no `host` header was previously specified.
|
|
798
|
+
Response headers will derive a `host` from the `url` of the [Client](Client.md#class-client) instance if no `host` header was previously specified.
|
|
799
799
|
|
|
800
800
|
### Example 1 - Object
|
|
801
801
|
|
package/docs/api/MockAgent.md
CHANGED
|
@@ -14,7 +14,7 @@ Returns: `MockAgent`
|
|
|
14
14
|
|
|
15
15
|
### Parameter: `MockAgentOptions`
|
|
16
16
|
|
|
17
|
-
Extends: [`AgentOptions`](
|
|
17
|
+
Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
|
|
18
18
|
|
|
19
19
|
* **agent** `Agent` (optional) - Default: `new Agent([options])` - a custom agent encapsulated by the MockAgent.
|
|
20
20
|
|
|
@@ -314,11 +314,11 @@ await mockAgent.close()
|
|
|
314
314
|
|
|
315
315
|
### `MockAgent.dispatch(options, handlers)`
|
|
316
316
|
|
|
317
|
-
Implements [`Agent.dispatch(options, handlers)`](
|
|
317
|
+
Implements [`Agent.dispatch(options, handlers)`](Agent.md#parameter-agentdispatchoptions).
|
|
318
318
|
|
|
319
319
|
### `MockAgent.request(options[, callback])`
|
|
320
320
|
|
|
321
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
321
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
322
322
|
|
|
323
323
|
#### Example - MockAgent request
|
|
324
324
|
|
package/docs/api/MockClient.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Extends: `undici.Client`
|
|
4
4
|
|
|
5
|
-
A mock client class that implements the same api as [MockPool](
|
|
5
|
+
A mock client class that implements the same api as [MockPool](MockPool.md).
|
|
6
6
|
|
|
7
7
|
## `new MockClient(origin, [options])`
|
|
8
8
|
|
|
@@ -36,19 +36,19 @@ const mockClient = mockAgent.get('http://localhost:3000')
|
|
|
36
36
|
|
|
37
37
|
### `MockClient.intercept(options)`
|
|
38
38
|
|
|
39
|
-
Implements: [`MockPool.intercept(options)`](
|
|
39
|
+
Implements: [`MockPool.intercept(options)`](MockPool.md#mockpoolinterceptoptions)
|
|
40
40
|
|
|
41
41
|
### `MockClient.close()`
|
|
42
42
|
|
|
43
|
-
Implements: [`MockPool.close()`](
|
|
43
|
+
Implements: [`MockPool.close()`](MockPool.md#mockpoolclose)
|
|
44
44
|
|
|
45
45
|
### `MockClient.dispatch(options, handlers)`
|
|
46
46
|
|
|
47
|
-
Implements [`Dispatcher.dispatch(options, handlers)`](
|
|
47
|
+
Implements [`Dispatcher.dispatch(options, handlers)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
48
48
|
|
|
49
49
|
### `MockClient.request(options[, callback])`
|
|
50
50
|
|
|
51
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
51
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
52
52
|
|
|
53
53
|
#### Example - MockClient request
|
|
54
54
|
|
package/docs/api/MockPool.md
CHANGED
|
@@ -62,12 +62,14 @@ Returns: `MockInterceptor` corresponding to the input options.
|
|
|
62
62
|
|
|
63
63
|
We can define the behaviour of an intercepted request with the following options.
|
|
64
64
|
|
|
65
|
-
* **reply** `(statusCode: number, replyData: string | object, responseOptions?: MockResponseOptions) => MockScope` - define a reply for a matching request. Default for `responseOptions` is `{}`.
|
|
65
|
+
* **reply** `(statusCode: number, replyData: string | Buffer | object, responseOptions?: MockResponseOptions) => MockScope` - define a reply for a matching request. Default for `responseOptions` is `{}`.
|
|
66
66
|
* **replyWithError** `(error: Error) => MockScope` - define an error for a matching request to throw.
|
|
67
67
|
* **defaultReplyHeaders** `(headers: Record<string, string>) => MockInterceptor` - define default headers to be included in subsequent replies. These are in addition to headers on a specific reply.
|
|
68
68
|
* **defaultReplyTrailers** `(trailers: Record<string, string>) => MockInterceptor` - define default trailers to be included in subsequent replies. These are in addition to trailers on a specific reply.
|
|
69
69
|
* **replyContentLength** `() => MockInterceptor` - define automatically calculated `content-length` headers to be included in subsequent replies.
|
|
70
70
|
|
|
71
|
+
The reply data of an intercepted request may either be a string, buffer, or JavaScript object. Objects are converted to JSON while strings and buffers are sent as-is.
|
|
72
|
+
|
|
71
73
|
By default, `reply` and `replyWithError` define the behaviour for the first matching request only. Subsequent requests will not be affected (this can be changed using the returned `MockScope`).
|
|
72
74
|
|
|
73
75
|
### Parameter: `MockResponseOptions`
|
|
@@ -297,7 +299,7 @@ mockPool.intercept({
|
|
|
297
299
|
}).defaultReplyTrailers({ foo: 'bar' })
|
|
298
300
|
.reply(200, 'foo')
|
|
299
301
|
|
|
300
|
-
const { trailers } = await request('http://localhost:3000/foo')
|
|
302
|
+
const { trailers } = await request('http://localhost:3000/foo')
|
|
301
303
|
|
|
302
304
|
console.log('trailers', trailers) // trailers { foo: 'bar' }
|
|
303
305
|
```
|
|
@@ -410,11 +412,11 @@ await mockPool.close()
|
|
|
410
412
|
|
|
411
413
|
### `MockPool.dispatch(options, handlers)`
|
|
412
414
|
|
|
413
|
-
Implements [`Dispatcher.dispatch(options, handlers)`](
|
|
415
|
+
Implements [`Dispatcher.dispatch(options, handlers)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
414
416
|
|
|
415
417
|
### `MockPool.request(options[, callback])`
|
|
416
418
|
|
|
417
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
419
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
418
420
|
|
|
419
421
|
#### Example - MockPool request
|
|
420
422
|
|
package/docs/api/Pool.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Extends: `undici.Dispatcher`
|
|
4
4
|
|
|
5
|
-
A pool of [Client](
|
|
5
|
+
A pool of [Client](Client.md) instances connected to the same upstream target.
|
|
6
6
|
|
|
7
7
|
Requests are not guaranteed to be dispatched in order of invocation.
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ Arguments:
|
|
|
15
15
|
|
|
16
16
|
### Parameter: `PoolOptions`
|
|
17
17
|
|
|
18
|
-
Extends: [`ClientOptions`](
|
|
18
|
+
Extends: [`ClientOptions`](Client.md#parameter-clientoptions)
|
|
19
19
|
|
|
20
20
|
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)`
|
|
21
21
|
* **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances.
|
|
@@ -24,56 +24,56 @@ Extends: [`ClientOptions`](docs/api/Client.md#parameter-clientoptions)
|
|
|
24
24
|
|
|
25
25
|
### `Pool.closed`
|
|
26
26
|
|
|
27
|
-
Implements [Client.closed](
|
|
27
|
+
Implements [Client.closed](Client.md#clientclosed)
|
|
28
28
|
|
|
29
29
|
### `Pool.destroyed`
|
|
30
30
|
|
|
31
|
-
Implements [Client.destroyed](
|
|
31
|
+
Implements [Client.destroyed](Client.md#clientdestroyed)
|
|
32
32
|
|
|
33
33
|
## Instance Methods
|
|
34
34
|
|
|
35
35
|
### `Pool.close([callback])`
|
|
36
36
|
|
|
37
|
-
Implements [`Dispatcher.close([callback])`](
|
|
37
|
+
Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
|
|
38
38
|
|
|
39
39
|
### `Pool.destroy([error, callback])`
|
|
40
40
|
|
|
41
|
-
Implements [`Dispatcher.destroy([error, callback])`](
|
|
41
|
+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
42
42
|
|
|
43
43
|
### `Pool.connect(options[, callback])`
|
|
44
44
|
|
|
45
|
-
See [`Dispatcher.connect(options[, callback])`](
|
|
45
|
+
See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
|
|
46
46
|
|
|
47
|
-
### `Pool.dispatch(options,
|
|
47
|
+
### `Pool.dispatch(options, handler)`
|
|
48
48
|
|
|
49
|
-
Implements [`Dispatcher.dispatch(options,
|
|
49
|
+
Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
50
50
|
|
|
51
51
|
### `Pool.pipeline(options, handler)`
|
|
52
52
|
|
|
53
|
-
See [`Dispatcher.pipeline(options, handler)`](
|
|
53
|
+
See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
|
|
54
54
|
|
|
55
55
|
### `Pool.request(options[, callback])`
|
|
56
56
|
|
|
57
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
57
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
58
58
|
|
|
59
59
|
### `Pool.stream(options, factory[, callback])`
|
|
60
60
|
|
|
61
|
-
See [`Dispatcher.stream(options, factory[, callback])`](
|
|
61
|
+
See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
|
|
62
62
|
|
|
63
63
|
### `Pool.upgrade(options[, callback])`
|
|
64
64
|
|
|
65
|
-
See [`Dispatcher.upgrade(options[, callback])`](
|
|
65
|
+
See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
|
|
66
66
|
|
|
67
67
|
## Instance Events
|
|
68
68
|
|
|
69
69
|
### Event: `'connect'`
|
|
70
70
|
|
|
71
|
-
See [Dispatcher Event: `'connect'`](
|
|
71
|
+
See [Dispatcher Event: `'connect'`](Dispatcher.md#event-connect).
|
|
72
72
|
|
|
73
73
|
### Event: `'disconnect'`
|
|
74
74
|
|
|
75
|
-
See [Dispatcher Event: `'disconnect'`](
|
|
75
|
+
See [Dispatcher Event: `'disconnect'`](Dispatcher.md#event-disconnect).
|
|
76
76
|
|
|
77
77
|
### Event: `'drain'`
|
|
78
78
|
|
|
79
|
-
See [Dispatcher Event: `'drain'`](
|
|
79
|
+
See [Dispatcher Event: `'drain'`](Dispatcher.md#event-drain).
|
package/docs/api/ProxyAgent.md
CHANGED
|
@@ -14,7 +14,7 @@ Returns: `ProxyAgent`
|
|
|
14
14
|
|
|
15
15
|
### Parameter: `ProxyAgentOptions`
|
|
16
16
|
|
|
17
|
-
Extends: [`AgentOptions`](
|
|
17
|
+
Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
|
|
18
18
|
|
|
19
19
|
* **uri** `string` (required) - It can be passed either by a string or a object containing `uri` as string.
|
|
20
20
|
|
|
@@ -93,8 +93,8 @@ await proxyAgent.close()
|
|
|
93
93
|
|
|
94
94
|
### `ProxyAgent.dispatch(options, handlers)`
|
|
95
95
|
|
|
96
|
-
Implements [`Agent.dispatch(options, handlers)`](
|
|
96
|
+
Implements [`Agent.dispatch(options, handlers)`](Agent.md#parameter-agentdispatchoptions).
|
|
97
97
|
|
|
98
98
|
### `ProxyAgent.request(options[, callback])`
|
|
99
99
|
|
|
100
|
-
See [`Dispatcher.request(options [, callback])`](
|
|
100
|
+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Client Lifecycle
|
|
2
2
|
|
|
3
|
-
An Undici [Client](
|
|
3
|
+
An Undici [Client](Client.md) can be best described as a state machine. The following list is a summary of the various state transitions the `Client` will go through in its lifecycle. This document also contains detailed breakdowns of each state.
|
|
4
4
|
|
|
5
5
|
> This diagram is not a perfect representation of the undici Client. Since the Client class is not actually implemented as a state-machine, actual execution may deviate slightly from what is described below. Consider this as a general resource for understanding the inner workings of the Undici client rather than some kind of formal specification.
|
|
6
6
|
|
|
@@ -29,25 +29,25 @@ An Undici [Client](docs/api/Client.md) can be best described as a state machine.
|
|
|
29
29
|
|
|
30
30
|
### idle
|
|
31
31
|
|
|
32
|
-
The **idle** state is the initial state of a `Client` instance. While an `origin` is required for instantiating a `Client` instance, the underlying socket connection will not be established until a request is queued using [`Client.dispatch()`](
|
|
32
|
+
The **idle** state is the initial state of a `Client` instance. While an `origin` is required for instantiating a `Client` instance, the underlying socket connection will not be established until a request is queued using [`Client.dispatch()`](Client.md#clientdispatchoptions-handlers). By calling `Client.dispatch()` directly or using one of the multiple implementations ([`Client.connect()`](Client.md#clientconnectoptions-callback), [`Client.pipeline()`](Client.md#clientpipelineoptions-handler), [`Client.request()`](Client.md#clientrequestoptions-callback), [`Client.stream()`](Client.md#clientstreamoptions-factory-callback), and [`Client.upgrade()`](Client.md#clientupgradeoptions-callback)), the `Client` instance will transition from **idle** to [**pending**](#pending) and then most likely directly to [**processing**](#processing).
|
|
33
33
|
|
|
34
|
-
Calling [`Client.close()`](
|
|
34
|
+
Calling [`Client.close()`](Client.md#clientclosecallback) or [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](#destroyed) state since the `Client` instance will have no queued requests in this state.
|
|
35
35
|
|
|
36
36
|
### pending
|
|
37
37
|
|
|
38
|
-
The **pending** state signifies a non-processing `Client`. Upon entering this state, the `Client` establishes a socket connection and emits the [`'connect'`](
|
|
38
|
+
The **pending** state signifies a non-processing `Client`. Upon entering this state, the `Client` establishes a socket connection and emits the [`'connect'`](Client.md#event-connect) event signalling a connection was successfully established with the `origin` provided during `Client` instantiation. The internal queue is initially empty, and requests can start queueing.
|
|
39
39
|
|
|
40
|
-
Calling [`Client.close()`](
|
|
40
|
+
Calling [`Client.close()`](Client.md#clientclosecallback) with queued requests, transitions the `Client` to the [**processing**](#processing) state. Without queued requests, it transitions to the [**destroyed**](#destroyed) state.
|
|
41
41
|
|
|
42
|
-
Calling [`Client.destroy()`](
|
|
42
|
+
Calling [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](#destroyed) state regardless of existing requests.
|
|
43
43
|
|
|
44
44
|
### processing
|
|
45
45
|
|
|
46
|
-
The **processing** state is a state machine within itself. It initializes to the [**processing.running**](#running) state. The [`Client.dispatch()`](
|
|
46
|
+
The **processing** state is a state machine within itself. It initializes to the [**processing.running**](#running) state. The [`Client.dispatch()`](Client.md#clientdispatchoptions-handlers), [`Client.close()`](Client.md#clientclosecallback), and [`Client.destroy()`](Client.md#clientdestroyerror-callback) can be called at any time while the `Client` is in this state. `Client.dispatch()` will add more requests to the queue while existing requests continue to be processed. `Client.close()` will transition to the [**processing.closing**](#closing) state. And `Client.destroy()` will transition to [**destroyed**](#destroyed).
|
|
47
47
|
|
|
48
48
|
#### running
|
|
49
49
|
|
|
50
|
-
In the **processing.running** sub-state, queued requests are being processed in a FIFO order. If a request body requires draining, the *needDrain* event transitions to the [**processing.busy**](#busy) sub-state. The *close* event transitions the Client to the [**process.closing**](#closing) sub-state. If all queued requests are processed and neither [`Client.close()`](
|
|
50
|
+
In the **processing.running** sub-state, queued requests are being processed in a FIFO order. If a request body requires draining, the *needDrain* event transitions to the [**processing.busy**](#busy) sub-state. The *close* event transitions the Client to the [**process.closing**](#closing) sub-state. If all queued requests are processed and neither [`Client.close()`](Client.md#clientclosecallback) nor [`Client.destroy()`](Client.md#clientdestroyerror-callback) are called, then the [**processing**](#processing) machine will trigger a *keepalive* event transitioning the `Client` back to the [**pending**](#pending) state. During this time, the `Client` is waiting for the socket connection to timeout, and once it does, it triggers the *timeout* event and transitions to the [**idle**](#idle) state.
|
|
51
51
|
|
|
52
52
|
#### busy
|
|
53
53
|
|
|
@@ -55,7 +55,7 @@ This sub-state is only entered when a request body is an instance of [Stream](ht
|
|
|
55
55
|
|
|
56
56
|
#### closing
|
|
57
57
|
|
|
58
|
-
This sub-state is only entered when a `Client` instance has queued requests and the [`Client.close()`](
|
|
58
|
+
This sub-state is only entered when a `Client` instance has queued requests and the [`Client.close()`](Client.md#clientclosecallback) method is called. In this state, the `Client` instance continues to process requests as usual, with the one exception that no additional requests can be queued. Once all of the queued requests are processed, the `Client` will trigger the *done* event gracefully entering the [**destroyed**](#destroyed) state without an error.
|
|
59
59
|
|
|
60
60
|
### destroyed
|
|
61
61
|
|
package/index.d.ts
CHANGED
package/lib/core/util.js
CHANGED
package/lib/fetch/formdata.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { isBlobLike, toUSVString } = require('./util')
|
|
4
4
|
const { kState } = require('./symbols')
|
|
5
5
|
const { File } = require('./file')
|
|
6
|
-
const { HTMLFormElement, toUSVString } = require('./util')
|
|
7
6
|
|
|
8
7
|
class FormData {
|
|
9
8
|
constructor (...args) {
|
|
10
|
-
if (args.length > 0 && !(args[0]
|
|
9
|
+
if (args.length > 0 && !(args[0]?.constructor?.name === 'HTMLFormElement')) {
|
|
11
10
|
throw new TypeError(
|
|
12
11
|
"Failed to construct 'FormData': parameter 1 is not of type 'HTMLFormElement'"
|
|
13
12
|
)
|
|
@@ -25,7 +24,7 @@ class FormData {
|
|
|
25
24
|
`Failed to execute 'append' on 'FormData': 2 arguments required, but only ${args.length} present.`
|
|
26
25
|
)
|
|
27
26
|
}
|
|
28
|
-
if (args.length === 3 && !(args[1]
|
|
27
|
+
if (args.length === 3 && !isBlobLike(args[1])) {
|
|
29
28
|
throw new TypeError(
|
|
30
29
|
"Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'"
|
|
31
30
|
)
|
|
@@ -34,7 +33,7 @@ class FormData {
|
|
|
34
33
|
const filename = args.length === 3 ? toUSVString(args[2]) : undefined
|
|
35
34
|
|
|
36
35
|
// 1. Let value be value if given; otherwise blobValue.
|
|
37
|
-
const value = args[1]
|
|
36
|
+
const value = isBlobLike(args[1]) ? args[1] : toUSVString(args[1])
|
|
38
37
|
|
|
39
38
|
// 2. Let entry be the result of creating an entry with
|
|
40
39
|
// name, value, and filename if given.
|
|
@@ -135,7 +134,7 @@ class FormData {
|
|
|
135
134
|
`Failed to execute 'set' on 'FormData': 2 arguments required, but only ${args.length} present.`
|
|
136
135
|
)
|
|
137
136
|
}
|
|
138
|
-
if (args.length === 3 && !(args[1]
|
|
137
|
+
if (args.length === 3 && !isBlobLike(args[1])) {
|
|
139
138
|
throw new TypeError(
|
|
140
139
|
"Failed to execute 'set' on 'FormData': parameter 2 is not of type 'Blob'"
|
|
141
140
|
)
|
|
@@ -147,7 +146,7 @@ class FormData {
|
|
|
147
146
|
// are:
|
|
148
147
|
|
|
149
148
|
// 1. Let value be value if given; otherwise blobValue.
|
|
150
|
-
const value = args[1]
|
|
149
|
+
const value = isBlobLike(args[1]) ? args[1] : toUSVString(args[1])
|
|
151
150
|
|
|
152
151
|
// 2. Let entry be the result of creating an entry with name, value, and
|
|
153
152
|
// filename if given.
|
|
@@ -168,6 +167,28 @@ class FormData {
|
|
|
168
167
|
}
|
|
169
168
|
}
|
|
170
169
|
|
|
170
|
+
get [Symbol.toStringTag] () {
|
|
171
|
+
return 'FormData'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
* entries () {
|
|
175
|
+
for (const pair of this) {
|
|
176
|
+
yield pair
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
* keys () {
|
|
181
|
+
for (const [key] of this) {
|
|
182
|
+
yield key
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
* values () {
|
|
187
|
+
for (const [, value] of this) {
|
|
188
|
+
yield value
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
171
192
|
* [Symbol.iterator] () {
|
|
172
193
|
// The value pairs to iterate over are this’s entry list’s entries with
|
|
173
194
|
// the key being the name and the value being the value.
|
|
@@ -192,7 +213,7 @@ function makeEntry (name, value, filename) {
|
|
|
192
213
|
|
|
193
214
|
// 3. If value is a Blob object and not a File object, then set value to a new File
|
|
194
215
|
// object, representing the same bytes, whose name attribute value is "blob".
|
|
195
|
-
if (value
|
|
216
|
+
if (isBlobLike(value) && !(value instanceof File)) {
|
|
196
217
|
value = new File([value], 'blob')
|
|
197
218
|
}
|
|
198
219
|
|
package/lib/fetch/headers.js
CHANGED
|
@@ -6,10 +6,6 @@ const { validateHeaderName, validateHeaderValue } = require('http')
|
|
|
6
6
|
const { kHeadersList } = require('../core/symbols')
|
|
7
7
|
const { kGuard } = require('./symbols')
|
|
8
8
|
const { kEnumerableProperty } = require('../core/util')
|
|
9
|
-
const {
|
|
10
|
-
InvalidHTTPTokenError,
|
|
11
|
-
HTTPInvalidHeaderValueError
|
|
12
|
-
} = require('../core/errors')
|
|
13
9
|
const {
|
|
14
10
|
forbiddenHeaderNames,
|
|
15
11
|
forbiddenResponseHeaderNames
|
|
@@ -34,7 +30,7 @@ function binarySearch (arr, val) {
|
|
|
34
30
|
|
|
35
31
|
function normalizeAndValidateHeaderName (name) {
|
|
36
32
|
if (name === undefined) {
|
|
37
|
-
throw new
|
|
33
|
+
throw new TypeError(`Header name ${name}`)
|
|
38
34
|
}
|
|
39
35
|
const normalizedHeaderName = name.toLocaleLowerCase()
|
|
40
36
|
validateHeaderName(normalizedHeaderName)
|
|
@@ -43,7 +39,7 @@ function normalizeAndValidateHeaderName (name) {
|
|
|
43
39
|
|
|
44
40
|
function normalizeAndValidateHeaderValue (name, value) {
|
|
45
41
|
if (value === undefined) {
|
|
46
|
-
throw new
|
|
42
|
+
throw new TypeError(value, name)
|
|
47
43
|
}
|
|
48
44
|
const normalizedHeaderValue = `${value}`.replace(
|
|
49
45
|
/^[\n\t\r\x20]+|[\n\t\r\x20]+$/g,
|
package/lib/fetch/index.js
CHANGED
|
@@ -737,7 +737,7 @@ function fetchFinale (fetchParams, response) {
|
|
|
737
737
|
|
|
738
738
|
// TODO (spec): The spec doesn't specify this but we need to
|
|
739
739
|
// terminate fetch if we have an error response.
|
|
740
|
-
if (response.
|
|
740
|
+
if (response.type === 'error') {
|
|
741
741
|
context.terminate({ reason: response.error })
|
|
742
742
|
}
|
|
743
743
|
}
|
package/lib/fetch/response.js
CHANGED
|
@@ -105,7 +105,7 @@ class Response {
|
|
|
105
105
|
|
|
106
106
|
// 1. If init["status"] is not in the range 200 to 599, inclusive, then
|
|
107
107
|
// throw a RangeError.
|
|
108
|
-
if ('status' in init) {
|
|
108
|
+
if ('status' in init && init.status !== undefined) {
|
|
109
109
|
if (!Number.isFinite(init.status)) {
|
|
110
110
|
throw new TypeError()
|
|
111
111
|
}
|
|
@@ -117,7 +117,7 @@ class Response {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
if ('statusText' in init) {
|
|
120
|
+
if ('statusText' in init && init.statusText !== undefined) {
|
|
121
121
|
// 2. If init["statusText"] does not match the reason-phrase token
|
|
122
122
|
// production, then throw a TypeError.
|
|
123
123
|
// See, https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2:
|
|
@@ -139,12 +139,12 @@ class Response {
|
|
|
139
139
|
this[kHeaders][kRealm] = this[kRealm]
|
|
140
140
|
|
|
141
141
|
// 5. Set this’s response’s status to init["status"].
|
|
142
|
-
if ('status' in init) {
|
|
142
|
+
if ('status' in init && init.status !== undefined) {
|
|
143
143
|
this[kState].status = init.status
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// 6. Set this’s response’s status message to init["statusText"].
|
|
147
|
-
if ('statusText' in init) {
|
|
147
|
+
if ('statusText' in init && init.statusText !== undefined) {
|
|
148
148
|
this[kState].statusText = String(init.statusText)
|
|
149
149
|
}
|
|
150
150
|
|
package/lib/fetch/util.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { redirectStatus } = require('./constants')
|
|
4
4
|
const { performance } = require('perf_hooks')
|
|
5
|
+
const { Blob } = require('buffer')
|
|
5
6
|
const nodeUtil = require('util')
|
|
6
7
|
|
|
7
8
|
let ReadableStream
|
|
@@ -68,6 +69,18 @@ function requestBadPort (request) {
|
|
|
68
69
|
return 'allowed'
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
// based on https://github.com/node-fetch/fetch-blob/blob/8ab587d34080de94140b54f07168451e7d0b655e/index.js#L229-L241 (MIT License)
|
|
73
|
+
function isBlobLike (object) {
|
|
74
|
+
return object instanceof Blob || (
|
|
75
|
+
object &&
|
|
76
|
+
typeof object === 'object' &&
|
|
77
|
+
typeof object.constructor === 'function' &&
|
|
78
|
+
(typeof object.stream === 'function' ||
|
|
79
|
+
typeof object.arrayBuffer === 'function') &&
|
|
80
|
+
/^(Blob|File)$/.test(object[Symbol.toStringTag])
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
71
84
|
// Check whether |statusText| is a ByteString and
|
|
72
85
|
// matches the Reason-Phrase token production.
|
|
73
86
|
// RFC 2616: https://tools.ietf.org/html/rfc2616
|
|
@@ -229,7 +242,47 @@ function appendFetchMetadata (httpRequest) {
|
|
|
229
242
|
|
|
230
243
|
// https://fetch.spec.whatwg.org/#append-a-request-origin-header
|
|
231
244
|
function appendRequestOriginHeader (request) {
|
|
232
|
-
//
|
|
245
|
+
// 1. Let serializedOrigin be the result of byte-serializing a request origin with request.
|
|
246
|
+
let serializedOrigin = request.origin
|
|
247
|
+
|
|
248
|
+
// 2. If request’s response tainting is "cors" or request’s mode is "websocket", then append (`Origin`, serializedOrigin) to request’s header list.
|
|
249
|
+
if (request.responseTainting === 'cors' || request.mode === 'websocket') {
|
|
250
|
+
if (serializedOrigin) {
|
|
251
|
+
request.headersList.append('Origin', serializedOrigin)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then:
|
|
256
|
+
else if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
257
|
+
// 1. Switch on request’s referrer policy:
|
|
258
|
+
switch (request.referrerPolicy) {
|
|
259
|
+
case 'no-referrer':
|
|
260
|
+
// Set serializedOrigin to `null`.
|
|
261
|
+
serializedOrigin = null
|
|
262
|
+
break
|
|
263
|
+
case 'no-referrer-when-downgrade':
|
|
264
|
+
case 'strict-origin':
|
|
265
|
+
case 'strict-origin-when-cross-origin':
|
|
266
|
+
// If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`.
|
|
267
|
+
if (/^https:/.test(request.origin) && !/^https:/.test(requestCurrentURL(request))) {
|
|
268
|
+
serializedOrigin = null
|
|
269
|
+
}
|
|
270
|
+
break
|
|
271
|
+
case 'same-origin':
|
|
272
|
+
// If request’s origin is not same origin with request’s current URL’s origin, then set serializedOrigin to `null`.
|
|
273
|
+
if (request.origin !== requestCurrentURL(request).origin) {
|
|
274
|
+
serializedOrigin = null
|
|
275
|
+
}
|
|
276
|
+
break
|
|
277
|
+
default:
|
|
278
|
+
// Do nothing.
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (serializedOrigin) {
|
|
282
|
+
// 2. Append (`Origin`, serializedOrigin) to request’s header list.
|
|
283
|
+
request.headersList.append('Origin', serializedOrigin)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
233
286
|
}
|
|
234
287
|
|
|
235
288
|
function coarsenedSharedCurrentTime (crossOriginIsolatedCapability) {
|
|
@@ -284,10 +337,8 @@ function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) {
|
|
|
284
337
|
class ServiceWorkerGlobalScope {} // dummy
|
|
285
338
|
class Window {} // dummy
|
|
286
339
|
class EnvironmentSettingsObject {} // dummy
|
|
287
|
-
class HTMLFormElement {} // dummy
|
|
288
340
|
|
|
289
341
|
module.exports = {
|
|
290
|
-
HTMLFormElement,
|
|
291
342
|
ServiceWorkerGlobalScope,
|
|
292
343
|
Window,
|
|
293
344
|
EnvironmentSettingsObject,
|
|
@@ -311,5 +362,6 @@ module.exports = {
|
|
|
311
362
|
requestCurrentURL,
|
|
312
363
|
responseURL,
|
|
313
364
|
responseLocationURL,
|
|
365
|
+
isBlobLike,
|
|
314
366
|
isValidReasonPhrase
|
|
315
367
|
}
|
package/lib/mock/mock-utils.js
CHANGED
|
@@ -47,7 +47,13 @@ function matchKey (mockDispatch, { path, method, body, headers }) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function getResponseData (data) {
|
|
50
|
-
|
|
50
|
+
if (Buffer.isBuffer(data)) {
|
|
51
|
+
return data
|
|
52
|
+
} else if (typeof data === 'object') {
|
|
53
|
+
return JSON.stringify(data)
|
|
54
|
+
} else {
|
|
55
|
+
return data.toString()
|
|
56
|
+
}
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
function getMockDispatch (mockDispatches, key) {
|
package/lib/proxy-agent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { kProxy } = require('./core/symbols')
|
|
4
4
|
const url = require('url')
|
|
5
5
|
const Agent = require('./agent')
|
|
6
6
|
const Dispatcher = require('./dispatcher')
|
|
@@ -12,11 +12,7 @@ class ProxyAgent extends Dispatcher {
|
|
|
12
12
|
constructor (opts) {
|
|
13
13
|
super(opts)
|
|
14
14
|
this[kProxy] = buildProxyOptions(opts)
|
|
15
|
-
|
|
16
|
-
const agent = new Agent(opts)
|
|
17
|
-
this[kAgent] = agent
|
|
18
|
-
|
|
19
|
-
this[kClients] = agent[kClients]
|
|
15
|
+
this[kAgent] = new Agent(opts)
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
dispatch (opts, handler) {
|
|
@@ -29,7 +25,7 @@ class ProxyAgent extends Dispatcher {
|
|
|
29
25
|
headers: {
|
|
30
26
|
...opts.headers,
|
|
31
27
|
host
|
|
32
|
-
}
|
|
28
|
+
}
|
|
33
29
|
},
|
|
34
30
|
handler
|
|
35
31
|
)
|
|
@@ -37,11 +33,10 @@ class ProxyAgent extends Dispatcher {
|
|
|
37
33
|
|
|
38
34
|
async close () {
|
|
39
35
|
await this[kAgent].close()
|
|
40
|
-
this[kClients].clear()
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
38
|
|
|
44
|
-
function buildProxyOptions(opts) {
|
|
39
|
+
function buildProxyOptions (opts) {
|
|
45
40
|
if (typeof opts === 'string') {
|
|
46
41
|
opts = { uri: opts }
|
|
47
42
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.2",
|
|
4
4
|
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
|
5
5
|
"homepage": "https://undici.nodejs.org",
|
|
6
6
|
"bugs": {
|
|
@@ -19,6 +19,17 @@
|
|
|
19
19
|
"author": true
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"fetch",
|
|
24
|
+
"http",
|
|
25
|
+
"https",
|
|
26
|
+
"promise",
|
|
27
|
+
"request",
|
|
28
|
+
"curl",
|
|
29
|
+
"wget",
|
|
30
|
+
"xhr",
|
|
31
|
+
"whatwg"
|
|
32
|
+
],
|
|
22
33
|
"main": "index.js",
|
|
23
34
|
"types": "index.d.ts",
|
|
24
35
|
"files": [
|
|
@@ -63,6 +74,7 @@
|
|
|
63
74
|
"cronometro": "^0.8.0",
|
|
64
75
|
"delay": "^5.0.0",
|
|
65
76
|
"docsify-cli": "^4.4.3",
|
|
77
|
+
"formdata-node": "^4.3.1",
|
|
66
78
|
"https-pem": "^2.0.0",
|
|
67
79
|
"husky": "^7.0.2",
|
|
68
80
|
"jest": "^27.2.0",
|
|
@@ -21,7 +21,7 @@ declare class MockScope<TData extends object = object> {
|
|
|
21
21
|
declare class MockInterceptor {
|
|
22
22
|
constructor(options: MockInterceptor.Options, mockDispatches: MockInterceptor.MockDispatch[]);
|
|
23
23
|
/** Mock an undici request with the defined reply. */
|
|
24
|
-
reply<TData extends object = object>(statusCode: number, data: TData | string, responseOptions?: MockInterceptor.MockResponseOptions): MockScope<TData>;
|
|
24
|
+
reply<TData extends object = object>(statusCode: number, data: TData | Buffer| string , responseOptions?: MockInterceptor.MockResponseOptions): MockScope<TData>;
|
|
25
25
|
/** Mock an undici request by throwing the defined reply error. */
|
|
26
26
|
replyWithError<TError extends Error = Error>(error: TError): MockScope;
|
|
27
27
|
/** Set default reply headers on the interceptor for subsequent mocked replies. */
|