@nxtedition/nxt-undici 7.3.11 → 7.3.13
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 +10 -5
- package/lib/interceptor/dns.js +1 -1
- package/lib/interceptor/log.js +2 -2
- package/lib/interceptor/lookup.js +17 -13
- package/lib/interceptor/redirect.js +5 -1
- package/lib/interceptor/response-verify.js +2 -2
- package/lib/sqlite-cache-store.js +14 -3
- package/lib/utils.js +0 -1
- package/package.json +1 -1
package/lib/interceptor/cache.js
CHANGED
|
@@ -113,7 +113,7 @@ class CacheHandler extends DecoratorHandler {
|
|
|
113
113
|
|
|
114
114
|
const ttl = cacheControlDirectives.immutable
|
|
115
115
|
? 31556952
|
|
116
|
-
: Number(cacheControlDirectives['s-
|
|
116
|
+
: Number(cacheControlDirectives['s-maxage'] ?? cacheControlDirectives['max-age'])
|
|
117
117
|
if (!ttl || !Number.isFinite(ttl) || ttl <= 0) {
|
|
118
118
|
return super.onHeaders(statusCode, headers, resume)
|
|
119
119
|
}
|
|
@@ -186,7 +186,11 @@ export default () => (dispatch) => (opts, handler) => {
|
|
|
186
186
|
return dispatch(opts, handler)
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
const
|
|
189
|
+
const rawCacheControl = opts?.headers?.['cache-control']
|
|
190
|
+
const cacheControlDirectives = parseCacheControl(rawCacheControl) ?? {}
|
|
191
|
+
// cache-control-parser does not recognise 'only-if-cached', so check the raw string.
|
|
192
|
+
const onlyIfCached =
|
|
193
|
+
typeof rawCacheControl === 'string' && rawCacheControl.includes('only-if-cached')
|
|
190
194
|
|
|
191
195
|
if (cacheControlDirectives['no-transform']) {
|
|
192
196
|
// Do nothing. We don't transform requests...
|
|
@@ -213,19 +217,20 @@ export default () => (dispatch) => (opts, handler) => {
|
|
|
213
217
|
} catch (err) {
|
|
214
218
|
if (err.message === 'database is locked') {
|
|
215
219
|
// Database is busy. We don't bother trying again...
|
|
216
|
-
opts.logger?.debug({ err }, 'failed to
|
|
220
|
+
opts.logger?.debug({ err }, 'failed to get cache entry')
|
|
217
221
|
} else {
|
|
218
|
-
opts.logger?.error({ err }, 'failed to
|
|
222
|
+
opts.logger?.error({ err }, 'failed to get cache entry')
|
|
219
223
|
}
|
|
220
224
|
}
|
|
221
225
|
|
|
222
|
-
if (!entry && !
|
|
226
|
+
if (!entry && !onlyIfCached) {
|
|
223
227
|
return dispatch(
|
|
224
228
|
opts,
|
|
225
229
|
cacheControlDirectives['no-store']
|
|
226
230
|
? handler
|
|
227
231
|
: new CacheHandler(undici.util.cache.makeCacheKey(opts), {
|
|
228
232
|
maxEntrySize: opts.cache.maxEntrySize,
|
|
233
|
+
maxEntryTTL: opts.cache.maxEntryTTL,
|
|
229
234
|
store,
|
|
230
235
|
logger: opts.logger,
|
|
231
236
|
handler,
|
package/lib/interceptor/dns.js
CHANGED
package/lib/interceptor/log.js
CHANGED
|
@@ -89,7 +89,7 @@ class Handler extends DecoratorHandler {
|
|
|
89
89
|
return super.onData(chunk)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
onComplete() {
|
|
92
|
+
onComplete(trailers) {
|
|
93
93
|
this.#timing.end = performance.now() - this.#created
|
|
94
94
|
|
|
95
95
|
const data = {
|
|
@@ -117,7 +117,7 @@ class Handler extends DecoratorHandler {
|
|
|
117
117
|
|
|
118
118
|
this.onDone()
|
|
119
119
|
|
|
120
|
-
super.onComplete()
|
|
120
|
+
super.onComplete(trailers)
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
onError(err) {
|
|
@@ -5,23 +5,27 @@ export default () => (dispatch) => async (opts, handler) => {
|
|
|
5
5
|
return dispatch(opts, handler)
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
try {
|
|
9
|
+
const origin = await new Promise((resolve, reject) => {
|
|
10
|
+
const thenable = lookup(opts.origin, { signal: opts.signal ?? undefined }, (err, val) => {
|
|
11
|
+
if (err) {
|
|
12
|
+
reject(err)
|
|
13
|
+
} else {
|
|
14
|
+
resolve(val)
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
if (thenable != null) {
|
|
19
|
+
Promise.resolve(thenable).then(resolve, reject)
|
|
14
20
|
}
|
|
15
21
|
})
|
|
16
22
|
|
|
17
|
-
if (
|
|
18
|
-
|
|
23
|
+
if (!origin) {
|
|
24
|
+
throw new Error('invalid origin: ' + origin)
|
|
19
25
|
}
|
|
20
|
-
})
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
return dispatch({ ...opts, origin }, handler)
|
|
28
|
+
} catch (err) {
|
|
29
|
+
handler.onError(err)
|
|
24
30
|
}
|
|
25
|
-
|
|
26
|
-
return dispatch({ ...opts, origin }, handler)
|
|
27
31
|
}
|
|
@@ -69,6 +69,7 @@ class Handler extends DecoratorHandler {
|
|
|
69
69
|
if (!this.#opts.follow(this.#location, this.#count, this.#opts)) {
|
|
70
70
|
assert(!this.#headersSent)
|
|
71
71
|
this.#headersSent = true
|
|
72
|
+
this.#location = null
|
|
72
73
|
return super.onHeaders(statusCode, headers, resume)
|
|
73
74
|
}
|
|
74
75
|
} else {
|
|
@@ -144,7 +145,10 @@ class Handler extends DecoratorHandler {
|
|
|
144
145
|
this.#location = null
|
|
145
146
|
|
|
146
147
|
try {
|
|
147
|
-
this.#dispatch(this.#opts, this)
|
|
148
|
+
const result = this.#dispatch(this.#opts, this)
|
|
149
|
+
if (result != null && typeof result.catch === 'function') {
|
|
150
|
+
result.catch((err) => this.onError(err))
|
|
151
|
+
}
|
|
148
152
|
} catch (err) {
|
|
149
153
|
this.onError(err)
|
|
150
154
|
}
|
|
@@ -41,7 +41,7 @@ class Handler extends DecoratorHandler {
|
|
|
41
41
|
return super.onData(chunk)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
onComplete() {
|
|
44
|
+
onComplete(trailers) {
|
|
45
45
|
const contentMD5 = this.#hasher?.digest('base64')
|
|
46
46
|
|
|
47
47
|
if (this.#contentLength != null && this.#pos !== Number(this.#contentLength)) {
|
|
@@ -59,7 +59,7 @@ class Handler extends DecoratorHandler {
|
|
|
59
59
|
}),
|
|
60
60
|
)
|
|
61
61
|
} else {
|
|
62
|
-
super.onComplete()
|
|
62
|
+
super.onComplete(trailers)
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -268,9 +268,9 @@ export class SqliteCacheStore {
|
|
|
268
268
|
try {
|
|
269
269
|
const startTime = performance.now()
|
|
270
270
|
for (let retryCount = 0; true; retryCount++) {
|
|
271
|
-
this.#db.exec('BEGIN')
|
|
272
271
|
let n = 0
|
|
273
272
|
try {
|
|
273
|
+
this.#db.exec('BEGIN')
|
|
274
274
|
while (n < this.#insertBatch.length) {
|
|
275
275
|
const {
|
|
276
276
|
url,
|
|
@@ -314,11 +314,22 @@ export class SqliteCacheStore {
|
|
|
314
314
|
} catch (err) {
|
|
315
315
|
// ROLLBACK is required: a failed statement leaves the connection with
|
|
316
316
|
// an open transaction; without it the next BEGIN would throw.
|
|
317
|
-
|
|
317
|
+
// On SQLITE_FULL, SQLite automatically rolls back the transaction, so
|
|
318
|
+
// the explicit ROLLBACK may fail with "no transaction is active" — ignore it.
|
|
319
|
+
try {
|
|
320
|
+
this.#db.exec('ROLLBACK')
|
|
321
|
+
} catch {
|
|
322
|
+
// already rolled back automatically
|
|
323
|
+
// TODO (fix): Check that the error is what we expect (something like "no transaction is active")...
|
|
324
|
+
}
|
|
325
|
+
|
|
318
326
|
if (err?.errcode === 13 /* SQLITE_FULL */ && retryCount < 3) {
|
|
319
327
|
this.#evictQuery.run(256)
|
|
320
328
|
} else {
|
|
321
|
-
|
|
329
|
+
// If BEGIN failed (n=0) clear the whole batch to avoid an infinite
|
|
330
|
+
// retry loop. If an INSERT/COMMIT failed, only clear the entries
|
|
331
|
+
// that were part of the attempted transaction.
|
|
332
|
+
this.#insertBatch.splice(0, n || this.#insertBatch.length)
|
|
322
333
|
throw err
|
|
323
334
|
}
|
|
324
335
|
}
|
package/lib/utils.js
CHANGED