@nxtedition/nxt-undici 7.3.14 → 7.3.16
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/lib/interceptor/dns.js +13 -8
- package/lib/interceptor/log.js +10 -9
- package/lib/interceptor/proxy.js +1 -2
- package/lib/interceptor/redirect.js +1 -2
- package/lib/interceptor/response-error.js +10 -1
- package/lib/interceptor/response-retry.js +21 -0
- package/lib/interceptor/response-verify.js +0 -3
- package/package.json +1 -1
package/lib/interceptor/dns.js
CHANGED
|
@@ -45,14 +45,19 @@ export default () => (dispatch) => {
|
|
|
45
45
|
resolve([err, null])
|
|
46
46
|
} else {
|
|
47
47
|
const now = getFastNow()
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
const prev = cache.get(hostname)
|
|
49
|
+
const prevByAddr = prev ? new Map(prev.map((r) => [r.address, r])) : null
|
|
50
|
+
const val = records.map(({ address }) => {
|
|
51
|
+
const old = prevByAddr?.get(address)
|
|
52
|
+
return {
|
|
53
|
+
address,
|
|
54
|
+
expires: now + (ttl ?? 1e3),
|
|
55
|
+
pending: 0,
|
|
56
|
+
errored: old ? old.errored : 0,
|
|
57
|
+
counter: 0,
|
|
58
|
+
timeout: old ? old.timeout : 0,
|
|
59
|
+
}
|
|
60
|
+
})
|
|
56
61
|
|
|
57
62
|
cache.set(hostname, val)
|
|
58
63
|
|
package/lib/interceptor/log.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { DecoratorHandler } from '../utils.js'
|
|
2
2
|
|
|
3
|
+
const kGlobalIndex = Symbol('globalIndex')
|
|
4
|
+
const kGlobalArray = Symbol('globalArray')
|
|
5
|
+
|
|
3
6
|
class Handler extends DecoratorHandler {
|
|
4
7
|
#opts
|
|
5
8
|
#logger
|
|
@@ -19,9 +22,6 @@ class Handler extends DecoratorHandler {
|
|
|
19
22
|
#statusCode
|
|
20
23
|
#headers
|
|
21
24
|
|
|
22
|
-
#globalIndex = -1
|
|
23
|
-
#globalArray = (globalThis.__undici_requests ??= [])
|
|
24
|
-
|
|
25
25
|
constructor(logOpts, opts, { handler }) {
|
|
26
26
|
super(handler)
|
|
27
27
|
|
|
@@ -35,7 +35,8 @@ class Handler extends DecoratorHandler {
|
|
|
35
35
|
this.#logger.debug('upstream request started')
|
|
36
36
|
this.#timing.created = this.#created + performance.timeOrigin
|
|
37
37
|
|
|
38
|
-
this
|
|
38
|
+
this[kGlobalArray] = globalThis.__undici_requests ??= []
|
|
39
|
+
this[kGlobalIndex] = this[kGlobalArray].push(this) - 1
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
onConnect(abort) {
|
|
@@ -151,13 +152,13 @@ class Handler extends DecoratorHandler {
|
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
onDone() {
|
|
154
|
-
if (this
|
|
155
|
-
const tmp = this
|
|
155
|
+
if (this[kGlobalIndex] !== -1) {
|
|
156
|
+
const tmp = this[kGlobalArray].pop()
|
|
156
157
|
if (tmp !== this) {
|
|
157
|
-
this
|
|
158
|
-
tmp
|
|
158
|
+
this[kGlobalArray][this[kGlobalIndex]] = tmp
|
|
159
|
+
tmp[kGlobalIndex] = this[kGlobalIndex]
|
|
159
160
|
}
|
|
160
|
-
this
|
|
161
|
+
this[kGlobalIndex] = -1
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
}
|
package/lib/interceptor/proxy.js
CHANGED
|
@@ -173,8 +173,7 @@ export default () => (dispatch) => (opts, handler) => {
|
|
|
173
173
|
// the request message does not contain a payload body and the method
|
|
174
174
|
// semantics do not anticipate such a body.
|
|
175
175
|
// undici will error if provided an unexpected content-length: 0 header.
|
|
176
|
-
}
|
|
177
|
-
if (key[0] === ':') {
|
|
176
|
+
} else if (key[0] === ':') {
|
|
178
177
|
// strip pseudo headers
|
|
179
178
|
} else if (key === 'expect') {
|
|
180
179
|
// undici doesn't support expect header.
|
|
@@ -176,11 +176,10 @@ function shouldRemoveHeader(header, removeContent, unknownOrigin) {
|
|
|
176
176
|
|
|
177
177
|
// https://tools.ietf.org/html/rfc7231#section-6.4
|
|
178
178
|
function cleanRequestHeaders(headers, removeContent, unknownOrigin) {
|
|
179
|
-
|
|
179
|
+
const ret = {}
|
|
180
180
|
if (headers && typeof headers === 'object') {
|
|
181
181
|
for (const key of Object.keys(headers)) {
|
|
182
182
|
if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) {
|
|
183
|
-
ret ??= {}
|
|
184
183
|
ret[key] = headers[key]
|
|
185
184
|
}
|
|
186
185
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { DecoratorHandler, decorateError } from '../utils.js'
|
|
2
2
|
|
|
3
|
+
const MAX_ERROR_BODY_SIZE = 256 * 1024
|
|
4
|
+
|
|
3
5
|
class Handler extends DecoratorHandler {
|
|
4
6
|
#statusCode = 0
|
|
5
7
|
#decoder
|
|
6
8
|
#headers
|
|
7
9
|
#trailers
|
|
8
10
|
#body = ''
|
|
11
|
+
#bodySize = 0
|
|
9
12
|
#opts
|
|
10
13
|
|
|
11
14
|
constructor(opts, { handler }) {
|
|
@@ -19,6 +22,7 @@ class Handler extends DecoratorHandler {
|
|
|
19
22
|
this.#decoder = null
|
|
20
23
|
this.#headers = null
|
|
21
24
|
this.#body = ''
|
|
25
|
+
this.#bodySize = 0
|
|
22
26
|
|
|
23
27
|
super.onConnect(abort)
|
|
24
28
|
}
|
|
@@ -45,7 +49,12 @@ class Handler extends DecoratorHandler {
|
|
|
45
49
|
return super.onData(chunk)
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
if (this.#decoder) {
|
|
53
|
+
this.#bodySize += chunk.byteLength
|
|
54
|
+
if (this.#bodySize <= MAX_ERROR_BODY_SIZE) {
|
|
55
|
+
this.#body += this.#decoder.decode(chunk, { stream: true })
|
|
56
|
+
}
|
|
57
|
+
}
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
onComplete(trailers) {
|
|
@@ -85,6 +85,10 @@ class Handler extends DecoratorHandler {
|
|
|
85
85
|
this.#statusCode = statusCode
|
|
86
86
|
this.#headers = headers
|
|
87
87
|
|
|
88
|
+
if (statusCode < 200) {
|
|
89
|
+
return super.onHeaders(statusCode, headers, resume)
|
|
90
|
+
}
|
|
91
|
+
|
|
88
92
|
if (!this.#headersSent) {
|
|
89
93
|
assert(this.#etag == null)
|
|
90
94
|
assert(this.#pos == null)
|
|
@@ -173,6 +177,11 @@ class Handler extends DecoratorHandler {
|
|
|
173
177
|
onData(chunk) {
|
|
174
178
|
if (this.#pos != null) {
|
|
175
179
|
this.#pos += chunk.byteLength
|
|
180
|
+
|
|
181
|
+
if (this.#end != null && this.#pos > this.#end) {
|
|
182
|
+
this.#maybeError(new Error('Response body exceeded Content-Range'))
|
|
183
|
+
return false
|
|
184
|
+
}
|
|
176
185
|
}
|
|
177
186
|
|
|
178
187
|
if (this.#statusCode < 400) {
|
|
@@ -193,6 +202,10 @@ class Handler extends DecoratorHandler {
|
|
|
193
202
|
this.#trailers = trailers
|
|
194
203
|
|
|
195
204
|
if (this.#statusCode < 400) {
|
|
205
|
+
if (this.#end != null && this.#pos !== this.#end) {
|
|
206
|
+
this.#maybeError(new Error('Response body length mismatch with Content-Range'))
|
|
207
|
+
return
|
|
208
|
+
}
|
|
196
209
|
return super.onComplete(trailers)
|
|
197
210
|
}
|
|
198
211
|
|
|
@@ -232,6 +245,14 @@ class Handler extends DecoratorHandler {
|
|
|
232
245
|
}
|
|
233
246
|
|
|
234
247
|
super.onComplete(this.#trailers)
|
|
248
|
+
} else {
|
|
249
|
+
// Headers already sent but retry failed (e.g. etag mismatch, missing
|
|
250
|
+
// content-range). The user is waiting for data/complete — send an error
|
|
251
|
+
// so the response stream doesn't hang.
|
|
252
|
+
if (!this.#errorSent) {
|
|
253
|
+
this.#errorSent = true
|
|
254
|
+
super.onError(new Error('Response retry failed'))
|
|
255
|
+
}
|
|
235
256
|
}
|
|
236
257
|
|
|
237
258
|
this.#maybeAbort(err)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import crypto from 'node:crypto'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
2
|
import { DecoratorHandler } from '../utils.js'
|
|
4
3
|
|
|
5
4
|
class Handler extends DecoratorHandler {
|
|
@@ -16,8 +15,6 @@ class Handler extends DecoratorHandler {
|
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
onConnect(abort) {
|
|
19
|
-
assert(!this.#pos)
|
|
20
|
-
|
|
21
18
|
this.#contentMD5 = null
|
|
22
19
|
this.#contentLength = null
|
|
23
20
|
this.#hasher = null
|