undici 7.0.0 → 7.1.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 +2 -0
- package/docs/docs/api/Client.md +11 -2
- package/docs/docs/api/ProxyAgent.md +88 -0
- package/index.js +4 -3
- package/lib/dispatcher/client-h2.js +0 -10
- package/lib/handler/decorator-handler.js +23 -27
- package/lib/interceptor/dns.js +8 -8
- package/lib/interceptor/dump.js +29 -41
- package/lib/interceptor/response-error.js +17 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -434,6 +434,8 @@ and `undici.Agent`) which will enable the family autoselection algorithm when es
|
|
|
434
434
|
* [__Matthew Aitken__](https://github.com/KhafraDev), <https://www.npmjs.com/~khaf>
|
|
435
435
|
* [__Robert Nagy__](https://github.com/ronag), <https://www.npmjs.com/~ronag>
|
|
436
436
|
* [__Szymon Marczak__](https://github.com/szmarczak), <https://www.npmjs.com/~szmarczak>
|
|
437
|
+
|
|
438
|
+
## Past Collaborators
|
|
437
439
|
* [__Tomas Della Vedova__](https://github.com/delvedor), <https://www.npmjs.com/~delvedor>
|
|
438
440
|
|
|
439
441
|
### Releasers
|
package/docs/docs/api/Client.md
CHANGED
|
@@ -17,8 +17,6 @@ Returns: `Client`
|
|
|
17
17
|
|
|
18
18
|
### Parameter: `ClientOptions`
|
|
19
19
|
|
|
20
|
-
> ⚠️ Warning: The `H2` support is experimental.
|
|
21
|
-
|
|
22
20
|
* **bodyTimeout** `number | null` (optional) - Default: `300e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds. Please note the `timeout` will be reset if you keep writing data to the socket everytime.
|
|
23
21
|
* **headersTimeout** `number | null` (optional) - Default: `300e3` - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
|
|
24
22
|
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
|
|
@@ -34,6 +32,17 @@ Returns: `Client`
|
|
|
34
32
|
* **allowH2**: `boolean` - Default: `false`. Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
|
|
35
33
|
* **maxConcurrentStreams**: `number` - Default: `100`. Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame.
|
|
36
34
|
|
|
35
|
+
> **Notes about HTTP/2**
|
|
36
|
+
> - It only works under TLS connections. h2c is not supported.
|
|
37
|
+
> - The server must support HTTP/2 and choose it as the protocol during the ALPN negotiation.
|
|
38
|
+
> - The server must not have a bigger priority for HTTP/1.1 than HTTP/2.
|
|
39
|
+
> - Pseudo headers are automatically attached to the request. If you try to set them, they will be overwritten.
|
|
40
|
+
> - The `:path` header is automatically set to the request path.
|
|
41
|
+
> - The `:method` header is automatically set to the request method.
|
|
42
|
+
> - The `:scheme` header is automatically set to the request scheme.
|
|
43
|
+
> - The `:authority` header is automatically set to the request `host[:port]`.
|
|
44
|
+
> - `PUSH` frames are yet not supported.
|
|
45
|
+
|
|
37
46
|
#### Parameter: `ConnectOptions`
|
|
38
47
|
|
|
39
48
|
Every Tls option, see [here](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
|
|
@@ -128,3 +128,91 @@ Implements [`Agent.dispatch(options, handlers)`](/docs/docs/api/Agent.md#paramet
|
|
|
128
128
|
### `ProxyAgent.request(options[, callback])`
|
|
129
129
|
|
|
130
130
|
See [`Dispatcher.request(options [, callback])`](/docs/docs/api/Dispatcher.md#dispatcherrequestoptions-callback).
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
#### Example - ProxyAgent with Fetch
|
|
134
|
+
|
|
135
|
+
This example demonstrates how to use `fetch` with a proxy via `ProxyAgent`. It is particularly useful for scenarios requiring proxy tunneling.
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
import { ProxyAgent, fetch } from 'undici';
|
|
139
|
+
|
|
140
|
+
// Define the ProxyAgent
|
|
141
|
+
const proxyAgent = new ProxyAgent('http://localhost:8000');
|
|
142
|
+
|
|
143
|
+
// Make a GET request through the proxy
|
|
144
|
+
const response = await fetch('http://localhost:3000/foo', {
|
|
145
|
+
dispatcher: proxyAgent,
|
|
146
|
+
method: 'GET',
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
console.log('Response status:', response.status);
|
|
150
|
+
console.log('Response data:', await response.text());
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
#### Example - ProxyAgent with a Custom Proxy Server
|
|
156
|
+
|
|
157
|
+
This example shows how to create a custom proxy server and use it with `ProxyAgent`.
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
import * as http from 'node:http';
|
|
161
|
+
import { createProxy } from 'proxy';
|
|
162
|
+
import { ProxyAgent, fetch } from 'undici';
|
|
163
|
+
|
|
164
|
+
// Create a proxy server
|
|
165
|
+
const proxyServer = createProxy(http.createServer());
|
|
166
|
+
proxyServer.listen(8000, () => {
|
|
167
|
+
console.log('Proxy server running on port 8000');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Define and use the ProxyAgent
|
|
171
|
+
const proxyAgent = new ProxyAgent('http://localhost:8000');
|
|
172
|
+
|
|
173
|
+
const response = await fetch('http://example.com', {
|
|
174
|
+
dispatcher: proxyAgent,
|
|
175
|
+
method: 'GET',
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
console.log('Response status:', response.status);
|
|
179
|
+
console.log('Response data:', await response.text());
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
#### Example - ProxyAgent with HTTPS Tunneling
|
|
185
|
+
|
|
186
|
+
This example demonstrates how to perform HTTPS tunneling using a proxy.
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
import { ProxyAgent, fetch } from 'undici';
|
|
190
|
+
|
|
191
|
+
// Define a ProxyAgent for HTTPS proxy
|
|
192
|
+
const proxyAgent = new ProxyAgent('https://secure.proxy.server');
|
|
193
|
+
|
|
194
|
+
// Make a request to an HTTPS endpoint via the proxy
|
|
195
|
+
const response = await fetch('https://secure.endpoint.com/api/data', {
|
|
196
|
+
dispatcher: proxyAgent,
|
|
197
|
+
method: 'GET',
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
console.log('Response status:', response.status);
|
|
201
|
+
console.log('Response data:', await response.json());
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### Example - ProxyAgent as a Global Dispatcher
|
|
205
|
+
|
|
206
|
+
`ProxyAgent` can be configured as a global dispatcher, making it available for all requests without explicitly passing it. This simplifies code and is useful when a single proxy configuration applies to all requests.
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
import { ProxyAgent, setGlobalDispatcher, fetch } from 'undici';
|
|
210
|
+
|
|
211
|
+
// Define and configure the ProxyAgent
|
|
212
|
+
const proxyAgent = new ProxyAgent('http://localhost:8000');
|
|
213
|
+
setGlobalDispatcher(proxyAgent);
|
|
214
|
+
|
|
215
|
+
// Make requests without specifying the dispatcher
|
|
216
|
+
const response = await fetch('http://example.com');
|
|
217
|
+
console.log('Response status:', response.status);
|
|
218
|
+
console.log('Response data:', await response.text());
|
package/index.js
CHANGED
|
@@ -53,9 +53,10 @@ try {
|
|
|
53
53
|
const SqliteCacheStore = require('./lib/cache/sqlite-cache-store')
|
|
54
54
|
module.exports.cacheStores.SqliteCacheStore = SqliteCacheStore
|
|
55
55
|
} catch (err) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
// Most likely node:sqlite was not present, since SqliteCacheStore is
|
|
57
|
+
// optional, don't throw. Don't check specific error codes here because while
|
|
58
|
+
// ERR_UNKNOWN_BUILTIN_MODULE is expected, users have seen other codes like
|
|
59
|
+
// MODULE_NOT_FOUND
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
module.exports.buildConnector = buildConnector
|
|
@@ -35,9 +35,6 @@ const kOpenStreams = Symbol('open streams')
|
|
|
35
35
|
|
|
36
36
|
let extractBody
|
|
37
37
|
|
|
38
|
-
// Experimental
|
|
39
|
-
let h2ExperimentalWarned = false
|
|
40
|
-
|
|
41
38
|
/** @type {import('http2')} */
|
|
42
39
|
let http2
|
|
43
40
|
try {
|
|
@@ -82,13 +79,6 @@ function parseH2Headers (headers) {
|
|
|
82
79
|
async function connectH2 (client, socket) {
|
|
83
80
|
client[kSocket] = socket
|
|
84
81
|
|
|
85
|
-
if (!h2ExperimentalWarned) {
|
|
86
|
-
h2ExperimentalWarned = true
|
|
87
|
-
process.emitWarning('H2 support is experimental, expect them to change at any time.', {
|
|
88
|
-
code: 'UNDICI-H2'
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
|
|
92
82
|
const session = http2.connect(client[kUrl], {
|
|
93
83
|
createConnection: () => socket,
|
|
94
84
|
peerMaxConcurrentStreams: client[kMaxConcurrentStreams],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const assert = require('node:assert')
|
|
4
|
+
const WrapHandler = require('./wrap-handler')
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @deprecated
|
|
@@ -9,63 +10,58 @@ module.exports = class DecoratorHandler {
|
|
|
9
10
|
#handler
|
|
10
11
|
#onCompleteCalled = false
|
|
11
12
|
#onErrorCalled = false
|
|
13
|
+
#onResponseStartCalled = false
|
|
12
14
|
|
|
13
15
|
constructor (handler) {
|
|
14
16
|
if (typeof handler !== 'object' || handler === null) {
|
|
15
17
|
throw new TypeError('handler must be an object')
|
|
16
18
|
}
|
|
17
|
-
this.#handler = handler
|
|
19
|
+
this.#handler = WrapHandler.wrap(handler)
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
onRequestStart (...args) {
|
|
23
|
+
this.#handler.onRequestStart?.(...args)
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
this.#onErrorCalled = true
|
|
26
|
-
return this.#handler.onError?.(...args)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
onUpgrade (...args) {
|
|
26
|
+
onRequestUpgrade (...args) {
|
|
30
27
|
assert(!this.#onCompleteCalled)
|
|
31
28
|
assert(!this.#onErrorCalled)
|
|
32
29
|
|
|
33
|
-
return this.#handler.
|
|
30
|
+
return this.#handler.onRequestUpgrade?.(...args)
|
|
34
31
|
}
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
onResponseStart (...args) {
|
|
37
34
|
assert(!this.#onCompleteCalled)
|
|
38
35
|
assert(!this.#onErrorCalled)
|
|
36
|
+
assert(!this.#onResponseStartCalled)
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
onHeaders (...args) {
|
|
44
|
-
assert(!this.#onCompleteCalled)
|
|
45
|
-
assert(!this.#onErrorCalled)
|
|
38
|
+
this.#onResponseStartCalled = true
|
|
46
39
|
|
|
47
|
-
return this.#handler.
|
|
40
|
+
return this.#handler.onResponseStart?.(...args)
|
|
48
41
|
}
|
|
49
42
|
|
|
50
|
-
|
|
43
|
+
onResponseData (...args) {
|
|
51
44
|
assert(!this.#onCompleteCalled)
|
|
52
45
|
assert(!this.#onErrorCalled)
|
|
53
46
|
|
|
54
|
-
return this.#handler.
|
|
47
|
+
return this.#handler.onResponseData?.(...args)
|
|
55
48
|
}
|
|
56
49
|
|
|
57
|
-
|
|
50
|
+
onResponseEnd (...args) {
|
|
58
51
|
assert(!this.#onCompleteCalled)
|
|
59
52
|
assert(!this.#onErrorCalled)
|
|
60
53
|
|
|
61
54
|
this.#onCompleteCalled = true
|
|
62
|
-
return this.#handler.
|
|
55
|
+
return this.#handler.onResponseEnd?.(...args)
|
|
63
56
|
}
|
|
64
57
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return this.#handler.onBodySent?.(...args)
|
|
58
|
+
onResponseError (...args) {
|
|
59
|
+
this.#onErrorCalled = true
|
|
60
|
+
return this.#handler.onResponseError?.(...args)
|
|
70
61
|
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @deprecated
|
|
65
|
+
*/
|
|
66
|
+
onBodySent () {}
|
|
71
67
|
}
|
package/lib/interceptor/dns.js
CHANGED
|
@@ -222,19 +222,18 @@ class DNSDispatchHandler extends DecoratorHandler {
|
|
|
222
222
|
#state = null
|
|
223
223
|
#opts = null
|
|
224
224
|
#dispatch = null
|
|
225
|
-
#handler = null
|
|
226
225
|
#origin = null
|
|
226
|
+
#controller = null
|
|
227
227
|
|
|
228
228
|
constructor (state, { origin, handler, dispatch }, opts) {
|
|
229
229
|
super(handler)
|
|
230
230
|
this.#origin = origin
|
|
231
|
-
this.#handler = handler
|
|
232
231
|
this.#opts = { ...opts }
|
|
233
232
|
this.#state = state
|
|
234
233
|
this.#dispatch = dispatch
|
|
235
234
|
}
|
|
236
235
|
|
|
237
|
-
|
|
236
|
+
onResponseError (controller, err) {
|
|
238
237
|
switch (err.code) {
|
|
239
238
|
case 'ETIMEDOUT':
|
|
240
239
|
case 'ECONNREFUSED': {
|
|
@@ -242,7 +241,8 @@ class DNSDispatchHandler extends DecoratorHandler {
|
|
|
242
241
|
// We delete the record and retry
|
|
243
242
|
this.#state.runLookup(this.#origin, this.#opts, (err, newOrigin) => {
|
|
244
243
|
if (err) {
|
|
245
|
-
|
|
244
|
+
super.onResponseError(controller, err)
|
|
245
|
+
return
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
const dispatchOpts = {
|
|
@@ -253,18 +253,18 @@ class DNSDispatchHandler extends DecoratorHandler {
|
|
|
253
253
|
this.#dispatch(dispatchOpts, this)
|
|
254
254
|
})
|
|
255
255
|
|
|
256
|
-
// if dual-stack disabled, we error out
|
|
257
256
|
return
|
|
258
257
|
}
|
|
259
258
|
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
// if dual-stack disabled, we error out
|
|
260
|
+
super.onResponseError(controller, err)
|
|
261
|
+
break
|
|
262
262
|
}
|
|
263
263
|
case 'ENOTFOUND':
|
|
264
264
|
this.#state.deleteRecord(this.#origin)
|
|
265
265
|
// eslint-disable-next-line no-fallthrough
|
|
266
266
|
default:
|
|
267
|
-
|
|
267
|
+
super.onResponseError(controller, err)
|
|
268
268
|
break
|
|
269
269
|
}
|
|
270
270
|
}
|
package/lib/interceptor/dump.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const util = require('../core/util')
|
|
4
3
|
const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
|
|
5
4
|
const DecoratorHandler = require('../handler/decorator-handler')
|
|
6
5
|
|
|
7
6
|
class DumpHandler extends DecoratorHandler {
|
|
8
7
|
#maxSize = 1024 * 1024
|
|
9
|
-
#abort = null
|
|
10
8
|
#dumped = false
|
|
11
|
-
#aborted = false
|
|
12
9
|
#size = 0
|
|
13
|
-
#
|
|
14
|
-
|
|
10
|
+
#controller = null
|
|
11
|
+
aborted = false
|
|
12
|
+
reason = false
|
|
15
13
|
|
|
16
|
-
constructor ({ maxSize }, handler) {
|
|
14
|
+
constructor ({ maxSize, signal }, handler) {
|
|
17
15
|
if (maxSize != null && (!Number.isFinite(maxSize) || maxSize < 1)) {
|
|
18
16
|
throw new InvalidArgumentError('maxSize must be a number greater than 0')
|
|
19
17
|
}
|
|
@@ -21,23 +19,22 @@ class DumpHandler extends DecoratorHandler {
|
|
|
21
19
|
super(handler)
|
|
22
20
|
|
|
23
21
|
this.#maxSize = maxSize ?? this.#maxSize
|
|
24
|
-
this.#handler = handler
|
|
22
|
+
// this.#handler = handler
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
this
|
|
29
|
-
|
|
30
|
-
this.#handler.onConnect(this.#customAbort.bind(this))
|
|
25
|
+
#abort (reason) {
|
|
26
|
+
this.aborted = true
|
|
27
|
+
this.reason = reason
|
|
31
28
|
}
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.#
|
|
30
|
+
onRequestStart (controller, context) {
|
|
31
|
+
controller.abort = this.#abort.bind(this)
|
|
32
|
+
this.#controller = controller
|
|
33
|
+
|
|
34
|
+
return super.onRequestStart(controller, context)
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
onHeaders (statusCode, rawHeaders, resume, statusMessage) {
|
|
40
|
-
const headers = util.parseHeaders(rawHeaders)
|
|
37
|
+
onResponseStart (controller, statusCode, headers, statusMessage) {
|
|
41
38
|
const contentLength = headers['content-length']
|
|
42
39
|
|
|
43
40
|
if (contentLength != null && contentLength > this.#maxSize) {
|
|
@@ -48,55 +45,50 @@ class DumpHandler extends DecoratorHandler {
|
|
|
48
45
|
)
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
if (this
|
|
48
|
+
if (this.aborted === true) {
|
|
52
49
|
return true
|
|
53
50
|
}
|
|
54
51
|
|
|
55
|
-
return
|
|
56
|
-
statusCode,
|
|
57
|
-
rawHeaders,
|
|
58
|
-
resume,
|
|
59
|
-
statusMessage
|
|
60
|
-
)
|
|
52
|
+
return super.onResponseStart(controller, statusCode, headers, statusMessage)
|
|
61
53
|
}
|
|
62
54
|
|
|
63
|
-
|
|
55
|
+
onResponseError (controller, err) {
|
|
64
56
|
if (this.#dumped) {
|
|
65
57
|
return
|
|
66
58
|
}
|
|
67
59
|
|
|
68
|
-
err = this.#reason ?? err
|
|
60
|
+
err = this.#controller.reason ?? err
|
|
69
61
|
|
|
70
|
-
|
|
62
|
+
super.onResponseError(controller, err)
|
|
71
63
|
}
|
|
72
64
|
|
|
73
|
-
|
|
65
|
+
onResponseData (controller, chunk) {
|
|
74
66
|
this.#size = this.#size + chunk.length
|
|
75
67
|
|
|
76
68
|
if (this.#size >= this.#maxSize) {
|
|
77
69
|
this.#dumped = true
|
|
78
70
|
|
|
79
|
-
if (this
|
|
80
|
-
|
|
71
|
+
if (this.aborted === true) {
|
|
72
|
+
super.onResponseError(controller, this.reason)
|
|
81
73
|
} else {
|
|
82
|
-
|
|
74
|
+
super.onResponseEnd(controller, {})
|
|
83
75
|
}
|
|
84
76
|
}
|
|
85
77
|
|
|
86
78
|
return true
|
|
87
79
|
}
|
|
88
80
|
|
|
89
|
-
|
|
81
|
+
onResponseEnd (controller, trailers) {
|
|
90
82
|
if (this.#dumped) {
|
|
91
83
|
return
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
if (this.#aborted) {
|
|
95
|
-
|
|
86
|
+
if (this.#controller.aborted === true) {
|
|
87
|
+
super.onResponseError(controller, this.reason)
|
|
96
88
|
return
|
|
97
89
|
}
|
|
98
90
|
|
|
99
|
-
|
|
91
|
+
super.onResponseEnd(controller, trailers)
|
|
100
92
|
}
|
|
101
93
|
}
|
|
102
94
|
|
|
@@ -107,13 +99,9 @@ function createDumpInterceptor (
|
|
|
107
99
|
) {
|
|
108
100
|
return dispatch => {
|
|
109
101
|
return function Intercept (opts, handler) {
|
|
110
|
-
const { dumpMaxSize = defaultMaxSize } =
|
|
111
|
-
opts
|
|
102
|
+
const { dumpMaxSize = defaultMaxSize } = opts
|
|
112
103
|
|
|
113
|
-
const dumpHandler = new DumpHandler(
|
|
114
|
-
{ maxSize: dumpMaxSize },
|
|
115
|
-
handler
|
|
116
|
-
)
|
|
104
|
+
const dumpHandler = new DumpHandler({ maxSize: dumpMaxSize, signal: opts.signal }, handler)
|
|
117
105
|
|
|
118
106
|
return dispatch(opts, dumpHandler)
|
|
119
107
|
}
|
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { parseHeaders } = require('../core/util')
|
|
3
|
+
// const { parseHeaders } = require('../core/util')
|
|
4
4
|
const DecoratorHandler = require('../handler/decorator-handler')
|
|
5
5
|
const { ResponseError } = require('../core/errors')
|
|
6
6
|
|
|
7
7
|
class ResponseErrorHandler extends DecoratorHandler {
|
|
8
|
-
#handler
|
|
9
8
|
#statusCode
|
|
10
9
|
#contentType
|
|
11
10
|
#decoder
|
|
12
11
|
#headers
|
|
13
12
|
#body
|
|
14
13
|
|
|
15
|
-
constructor (
|
|
14
|
+
constructor (_opts, { handler }) {
|
|
16
15
|
super(handler)
|
|
17
|
-
this.#handler = handler
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
#checkContentType (contentType) {
|
|
19
|
+
return this.#contentType.indexOf(contentType) === 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onRequestStart (controller, context) {
|
|
21
23
|
this.#statusCode = 0
|
|
22
24
|
this.#contentType = null
|
|
23
25
|
this.#decoder = null
|
|
24
26
|
this.#headers = null
|
|
25
27
|
this.#body = ''
|
|
26
28
|
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#checkContentType (contentType) {
|
|
31
|
-
return this.#contentType.indexOf(contentType) === 0
|
|
29
|
+
return super.onRequestStart(controller, context)
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
onResponseStart (controller, statusCode, headers, statusMessage) {
|
|
35
33
|
this.#statusCode = statusCode
|
|
36
34
|
this.#headers = headers
|
|
37
35
|
this.#contentType = headers['content-type']
|
|
38
36
|
|
|
39
37
|
if (this.#statusCode < 400) {
|
|
40
|
-
return
|
|
38
|
+
return super.onResponseStart(controller, statusCode, headers, statusMessage)
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
if (this.#checkContentType('application/json') || this.#checkContentType('text/plain')) {
|
|
@@ -45,15 +43,15 @@ class ResponseErrorHandler extends DecoratorHandler {
|
|
|
45
43
|
}
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
onResponseData (controller, chunk) {
|
|
49
47
|
if (this.#statusCode < 400) {
|
|
50
|
-
return
|
|
48
|
+
return super.onResponseData(controller, chunk)
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
this.#body += this.#decoder?.decode(chunk, { stream: true }) ?? ''
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
|
|
54
|
+
onResponseEnd (controller, trailers) {
|
|
57
55
|
if (this.#statusCode >= 400) {
|
|
58
56
|
this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? ''
|
|
59
57
|
|
|
@@ -77,14 +75,14 @@ class ResponseErrorHandler extends DecoratorHandler {
|
|
|
77
75
|
Error.stackTraceLimit = stackTraceLimit
|
|
78
76
|
}
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
super.onResponseError(controller, err)
|
|
81
79
|
} else {
|
|
82
|
-
|
|
80
|
+
super.onResponseEnd(controller, trailers)
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
onResponseError (err) {
|
|
85
|
+
super.onResponseError(err)
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
|