@nxtedition/nxt-undici 6.1.6 → 6.2.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/lib/interceptor/cache.js +35 -2
- package/lib/interceptor/dns.js +23 -5
- package/lib/utils.js +10 -3
- package/package.json +1 -1
package/lib/interceptor/cache.js
CHANGED
|
@@ -95,7 +95,6 @@ class CacheHandler extends DecoratorHandler {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
const cachedAt = Date.now()
|
|
98
|
-
|
|
99
98
|
this.#value = {
|
|
100
99
|
body: [],
|
|
101
100
|
size: 0,
|
|
@@ -104,7 +103,7 @@ class CacheHandler extends DecoratorHandler {
|
|
|
104
103
|
statusMessage: '',
|
|
105
104
|
headers,
|
|
106
105
|
cacheControlDirectives,
|
|
107
|
-
etag: headers.etag,
|
|
106
|
+
etag: typeof headers.etag === 'string' && isEtagUsable(headers.etag) ? headers.etag : '',
|
|
108
107
|
vary,
|
|
109
108
|
cachedAt,
|
|
110
109
|
staleAt: 0,
|
|
@@ -213,3 +212,37 @@ export default () => (dispatch) => (opts, handler) => {
|
|
|
213
212
|
abort(err)
|
|
214
213
|
}
|
|
215
214
|
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Note: this deviates from the spec a little. Empty etags ("", W/"") are valid,
|
|
218
|
+
* however, including them in cached resposnes serves little to no purpose.
|
|
219
|
+
*
|
|
220
|
+
* @see https://www.rfc-editor.org/rfc/rfc9110.html#name-etag
|
|
221
|
+
*
|
|
222
|
+
* @param {string} etag
|
|
223
|
+
* @returns {boolean}
|
|
224
|
+
*/
|
|
225
|
+
function isEtagUsable(etag) {
|
|
226
|
+
if (etag.length <= 2) {
|
|
227
|
+
// Shortest an etag can be is two chars (just ""). This is where we deviate
|
|
228
|
+
// from the spec requiring a min of 3 chars however
|
|
229
|
+
return false
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (etag[0] === '"' && etag[etag.length - 1] === '"') {
|
|
233
|
+
// ETag: ""asd123"" or ETag: "W/"asd123"", kinda undefined behavior in the
|
|
234
|
+
// spec. Some servers will accept these while others don't.
|
|
235
|
+
// ETag: "asd123"
|
|
236
|
+
return !(etag[1] === '"' || etag.startsWith('"W/'))
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (etag.startsWith('W/"') && etag[etag.length - 1] === '"') {
|
|
240
|
+
// ETag: W/"", also where we deviate from the spec & require a min of 3
|
|
241
|
+
// chars
|
|
242
|
+
// ETag: for W/"", W/"asd123"
|
|
243
|
+
return etag.length !== 4
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Anything else
|
|
247
|
+
return false
|
|
248
|
+
}
|
package/lib/interceptor/dns.js
CHANGED
|
@@ -28,11 +28,28 @@ class Handler extends DecoratorHandler {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
class DefaultCache {
|
|
32
|
+
#map = new Map()
|
|
33
|
+
|
|
34
|
+
set(hostname, records) {
|
|
35
|
+
this.#map.set(hostname, records)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get(hostname) {
|
|
39
|
+
return this.#map.get(hostname)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
delete(hostname) {
|
|
43
|
+
this.#map.delete(hostname)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const DEFAULT_CACHE = new DefaultCache()
|
|
48
|
+
|
|
31
49
|
export default () => (dispatch) => {
|
|
32
|
-
const cache = new Map()
|
|
33
50
|
const promises = new Map()
|
|
34
51
|
|
|
35
|
-
function resolve(hostname, { resolve4, logger }) {
|
|
52
|
+
function resolve(hostname, { cache, resolve4, logger }) {
|
|
36
53
|
let promise = promises.get(hostname)
|
|
37
54
|
if (!promise) {
|
|
38
55
|
logger?.debug({ dns: { hostname } }, 'lookup started')
|
|
@@ -51,7 +68,7 @@ export default () => (dispatch) => {
|
|
|
51
68
|
counter: 0,
|
|
52
69
|
}))
|
|
53
70
|
|
|
54
|
-
logger?.debug({ err, dns: { records } }, 'lookup completed')
|
|
71
|
+
logger?.debug({ err, dns: { hostname, records } }, 'lookup completed')
|
|
55
72
|
|
|
56
73
|
cache.set(hostname, val)
|
|
57
74
|
|
|
@@ -79,6 +96,7 @@ export default () => (dispatch) => {
|
|
|
79
96
|
|
|
80
97
|
try {
|
|
81
98
|
const { host, hostname } = origin
|
|
99
|
+
const cache = opts.dns.cache ?? DEFAULT_CACHE
|
|
82
100
|
|
|
83
101
|
const now = getFastNow()
|
|
84
102
|
|
|
@@ -88,7 +106,7 @@ export default () => (dispatch) => {
|
|
|
88
106
|
const logger = opts.dns.logger ?? opts.logger
|
|
89
107
|
|
|
90
108
|
if (records == null || records.every((x) => x.expires < now)) {
|
|
91
|
-
const [err, val] = await resolve(hostname, { resolve4, logger })
|
|
109
|
+
const [err, val] = await resolve(hostname, { cache, resolve4, logger })
|
|
92
110
|
|
|
93
111
|
if (err) {
|
|
94
112
|
throw err
|
|
@@ -98,7 +116,7 @@ export default () => (dispatch) => {
|
|
|
98
116
|
|
|
99
117
|
records = val
|
|
100
118
|
} else if (records.some((x) => x.expires < now + 1e3)) {
|
|
101
|
-
resolve(hostname, { resolve4, logger })
|
|
119
|
+
resolve(hostname, { cache, resolve4, logger })
|
|
102
120
|
}
|
|
103
121
|
|
|
104
122
|
records.sort(
|
package/lib/utils.js
CHANGED
|
@@ -202,6 +202,7 @@ export class DecoratorHandler {
|
|
|
202
202
|
#aborted = false
|
|
203
203
|
#errored = false
|
|
204
204
|
#completed = false
|
|
205
|
+
#abort
|
|
205
206
|
|
|
206
207
|
constructor(handler) {
|
|
207
208
|
if (typeof handler !== 'object' || handler === null) {
|
|
@@ -214,23 +215,26 @@ export class DecoratorHandler {
|
|
|
214
215
|
this.#aborted = false
|
|
215
216
|
this.#errored = false
|
|
216
217
|
this.#completed = false
|
|
218
|
+
this.#abort = abort
|
|
217
219
|
|
|
218
220
|
return this.#handler.onConnect?.((reason) => {
|
|
219
221
|
if (!this.#aborted && !this.#completed && !this.#errored) {
|
|
220
222
|
this.#aborted = true
|
|
221
|
-
abort(reason)
|
|
223
|
+
this.#abort(reason)
|
|
222
224
|
}
|
|
223
225
|
})
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
onUpgrade(statusCode, headers, socket) {
|
|
227
229
|
if (!this.#aborted && !this.#errored) {
|
|
230
|
+
assert(!this.#completed)
|
|
228
231
|
return this.#handler.onUpgrade?.(statusCode, headers, socket)
|
|
229
232
|
}
|
|
230
233
|
}
|
|
231
234
|
|
|
232
235
|
onHeaders(statusCode, headers, resume) {
|
|
233
236
|
if (!this.#aborted && !this.#errored) {
|
|
237
|
+
assert(!this.#completed)
|
|
234
238
|
return this.#handler.onHeaders?.(statusCode, headers, resume)
|
|
235
239
|
}
|
|
236
240
|
}
|
|
@@ -243,9 +247,12 @@ export class DecoratorHandler {
|
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
onComplete(trailers) {
|
|
246
|
-
if (!this.#aborted && !this.#completed) {
|
|
250
|
+
if (!this.#aborted && !this.#completed && !this.#errored) {
|
|
251
|
+
<<<<<<< HEAD
|
|
252
|
+
this.#abort = null
|
|
253
|
+
=======
|
|
254
|
+
>>>>>>> 23823e3 (fix: decoerator)
|
|
247
255
|
this.#completed = true
|
|
248
|
-
assert(!this.#errored)
|
|
249
256
|
return this.#handler.onComplete?.(trailers)
|
|
250
257
|
}
|
|
251
258
|
}
|