@nxtedition/nxt-undici 7.3.13 → 7.3.15
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 +1 -0
- package/lib/interceptor/proxy.js +4 -3
- package/lib/interceptor/redirect.js +1 -2
- package/lib/interceptor/response-error.js +10 -1
- package/lib/interceptor/response-retry.js +12 -2
- package/lib/interceptor/response-verify.js +0 -3
- package/lib/utils.js +4 -4
- 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
package/lib/interceptor/proxy.js
CHANGED
|
@@ -105,7 +105,9 @@ function reduceHeaders({ headers, proxyName, httpVersion, socket }, fn, acc) {
|
|
|
105
105
|
socket.remoteAddress && `for=${printIp(socket.remoteAddress, socket.remotePort)}`,
|
|
106
106
|
`proto=${socket.encrypted ? 'https' : 'http'}`,
|
|
107
107
|
forwardedHost && `host="${forwardedHost}"`,
|
|
108
|
-
]
|
|
108
|
+
]
|
|
109
|
+
.filter(Boolean)
|
|
110
|
+
.join(';'),
|
|
109
111
|
)
|
|
110
112
|
} else if (forwarded) {
|
|
111
113
|
// The forwarded header should not be included in response.
|
|
@@ -171,8 +173,7 @@ export default () => (dispatch) => (opts, handler) => {
|
|
|
171
173
|
// the request message does not contain a payload body and the method
|
|
172
174
|
// semantics do not anticipate such a body.
|
|
173
175
|
// undici will error if provided an unexpected content-length: 0 header.
|
|
174
|
-
}
|
|
175
|
-
if (key[0] === ':') {
|
|
176
|
+
} else if (key[0] === ':') {
|
|
176
177
|
// strip pseudo headers
|
|
177
178
|
} else if (key === 'expect') {
|
|
178
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)
|
|
@@ -176,7 +180,6 @@ class Handler extends DecoratorHandler {
|
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
if (this.#statusCode < 400) {
|
|
179
|
-
this.#retryCount = 0
|
|
180
183
|
return super.onData(chunk)
|
|
181
184
|
}
|
|
182
185
|
|
|
@@ -194,7 +197,6 @@ class Handler extends DecoratorHandler {
|
|
|
194
197
|
this.#trailers = trailers
|
|
195
198
|
|
|
196
199
|
if (this.#statusCode < 400) {
|
|
197
|
-
this.#retryCount = 0
|
|
198
200
|
return super.onComplete(trailers)
|
|
199
201
|
}
|
|
200
202
|
|
|
@@ -234,6 +236,14 @@ class Handler extends DecoratorHandler {
|
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
super.onComplete(this.#trailers)
|
|
239
|
+
} else {
|
|
240
|
+
// Headers already sent but retry failed (e.g. etag mismatch, missing
|
|
241
|
+
// content-range). The user is waiting for data/complete — send an error
|
|
242
|
+
// so the response stream doesn't hang.
|
|
243
|
+
if (!this.#errorSent) {
|
|
244
|
+
this.#errorSent = true
|
|
245
|
+
super.onError(new Error('Response retry failed'))
|
|
246
|
+
}
|
|
237
247
|
}
|
|
238
248
|
|
|
239
249
|
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
|
package/lib/utils.js
CHANGED
|
@@ -59,8 +59,8 @@ export function parseContentRange(range) {
|
|
|
59
59
|
return m
|
|
60
60
|
? {
|
|
61
61
|
start: parseInt(m[1], 10),
|
|
62
|
-
end: m[2] ? parseInt(m[2]) + 1 : null,
|
|
63
|
-
size: m[3] === '*' ? null : parseInt(m[3]),
|
|
62
|
+
end: m[2] ? parseInt(m[2], 10) + 1 : null,
|
|
63
|
+
size: m[3] === '*' ? null : parseInt(m[3], 10),
|
|
64
64
|
}
|
|
65
65
|
: null
|
|
66
66
|
}
|
|
@@ -83,8 +83,8 @@ export function parseRangeHeader(range) {
|
|
|
83
83
|
const m = range.match(/^bytes=(\d+)-(\d+)?$/)
|
|
84
84
|
return m
|
|
85
85
|
? {
|
|
86
|
-
start: parseInt(m[1]),
|
|
87
|
-
end: m[2] ? parseInt(m[2]) + 1 : null,
|
|
86
|
+
start: parseInt(m[1], 10),
|
|
87
|
+
end: m[2] ? parseInt(m[2], 10) + 1 : null,
|
|
88
88
|
size: null,
|
|
89
89
|
}
|
|
90
90
|
: null
|