@nocobase/plugin-idp-oauth 2.1.0-alpha.17 → 2.1.0-alpha.18
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/build.config.ts +1 -1
- package/dist/externalVersion.js +4 -4
- package/dist/node_modules/light-my-request/package.json +1 -1
- package/dist/node_modules/undici/LICENSE +21 -0
- package/dist/node_modules/undici/README.md +741 -0
- package/dist/node_modules/undici/docs/docs/api/Agent.md +84 -0
- package/dist/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
- package/dist/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
- package/dist/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
- package/dist/node_modules/undici/docs/docs/api/Client.md +285 -0
- package/dist/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
- package/dist/node_modules/undici/docs/docs/api/Connector.md +115 -0
- package/dist/node_modules/undici/docs/docs/api/ContentType.md +57 -0
- package/dist/node_modules/undici/docs/docs/api/Cookies.md +101 -0
- package/dist/node_modules/undici/docs/docs/api/Debug.md +62 -0
- package/dist/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +315 -0
- package/dist/node_modules/undici/docs/docs/api/Dispatcher.md +1392 -0
- package/dist/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
- package/dist/node_modules/undici/docs/docs/api/Errors.md +49 -0
- package/dist/node_modules/undici/docs/docs/api/EventSource.md +45 -0
- package/dist/node_modules/undici/docs/docs/api/Fetch.md +60 -0
- package/dist/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
- package/dist/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
- package/dist/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
- package/dist/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
- package/dist/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
- package/dist/node_modules/undici/docs/docs/api/MockClient.md +81 -0
- package/dist/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
- package/dist/node_modules/undici/docs/docs/api/MockPool.md +555 -0
- package/dist/node_modules/undici/docs/docs/api/Pool.md +84 -0
- package/dist/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
- package/dist/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
- package/dist/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
- package/dist/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
- package/dist/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
- package/dist/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
- package/dist/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
- package/dist/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +274 -0
- package/dist/node_modules/undici/docs/docs/api/Util.md +25 -0
- package/dist/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
- package/dist/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
- package/dist/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
- package/dist/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
- package/dist/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
- package/dist/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
- package/dist/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
- package/dist/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
- package/dist/node_modules/undici/index-fetch.js +65 -0
- package/dist/node_modules/undici/index.d.ts +3 -0
- package/dist/node_modules/undici/index.js +234 -0
- package/dist/node_modules/undici/lib/api/abort-signal.js +59 -0
- package/dist/node_modules/undici/lib/api/api-connect.js +110 -0
- package/dist/node_modules/undici/lib/api/api-pipeline.js +252 -0
- package/dist/node_modules/undici/lib/api/api-request.js +214 -0
- package/dist/node_modules/undici/lib/api/api-stream.js +209 -0
- package/dist/node_modules/undici/lib/api/api-upgrade.js +111 -0
- package/dist/node_modules/undici/lib/api/index.js +7 -0
- package/dist/node_modules/undici/lib/api/readable.js +580 -0
- package/dist/node_modules/undici/lib/cache/memory-cache-store.js +234 -0
- package/dist/node_modules/undici/lib/cache/sqlite-cache-store.js +461 -0
- package/dist/node_modules/undici/lib/core/connect.js +137 -0
- package/dist/node_modules/undici/lib/core/constants.js +143 -0
- package/dist/node_modules/undici/lib/core/diagnostics.js +227 -0
- package/dist/node_modules/undici/lib/core/errors.js +477 -0
- package/dist/node_modules/undici/lib/core/request.js +438 -0
- package/dist/node_modules/undici/lib/core/socks5-client.js +407 -0
- package/dist/node_modules/undici/lib/core/socks5-utils.js +203 -0
- package/dist/node_modules/undici/lib/core/symbols.js +75 -0
- package/dist/node_modules/undici/lib/core/tree.js +160 -0
- package/dist/node_modules/undici/lib/core/util.js +992 -0
- package/dist/node_modules/undici/lib/dispatcher/agent.js +158 -0
- package/dist/node_modules/undici/lib/dispatcher/balanced-pool.js +219 -0
- package/dist/node_modules/undici/lib/dispatcher/client-h1.js +1610 -0
- package/dist/node_modules/undici/lib/dispatcher/client-h2.js +995 -0
- package/dist/node_modules/undici/lib/dispatcher/client.js +659 -0
- package/dist/node_modules/undici/lib/dispatcher/dispatcher-base.js +165 -0
- package/dist/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
- package/dist/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
- package/dist/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
- package/dist/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
- package/dist/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
- package/dist/node_modules/undici/lib/dispatcher/pool.js +118 -0
- package/dist/node_modules/undici/lib/dispatcher/proxy-agent.js +318 -0
- package/dist/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
- package/dist/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
- package/dist/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +249 -0
- package/dist/node_modules/undici/lib/encoding/index.js +33 -0
- package/dist/node_modules/undici/lib/global.js +50 -0
- package/dist/node_modules/undici/lib/handler/cache-handler.js +578 -0
- package/dist/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
- package/dist/node_modules/undici/lib/handler/decorator-handler.js +67 -0
- package/dist/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
- package/dist/node_modules/undici/lib/handler/redirect-handler.js +238 -0
- package/dist/node_modules/undici/lib/handler/retry-handler.js +394 -0
- package/dist/node_modules/undici/lib/handler/unwrap-handler.js +100 -0
- package/dist/node_modules/undici/lib/handler/wrap-handler.js +105 -0
- package/dist/node_modules/undici/lib/interceptor/cache.js +495 -0
- package/dist/node_modules/undici/lib/interceptor/decompress.js +259 -0
- package/dist/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
- package/dist/node_modules/undici/lib/interceptor/dns.js +571 -0
- package/dist/node_modules/undici/lib/interceptor/dump.js +112 -0
- package/dist/node_modules/undici/lib/interceptor/redirect.js +21 -0
- package/dist/node_modules/undici/lib/interceptor/response-error.js +95 -0
- package/dist/node_modules/undici/lib/interceptor/retry.js +19 -0
- package/dist/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/dist/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
- package/dist/node_modules/undici/lib/llhttp/constants.js +531 -0
- package/dist/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
- package/dist/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
- package/dist/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
- package/dist/node_modules/undici/lib/llhttp/utils.js +12 -0
- package/dist/node_modules/undici/lib/mock/mock-agent.js +232 -0
- package/dist/node_modules/undici/lib/mock/mock-call-history.js +248 -0
- package/dist/node_modules/undici/lib/mock/mock-client.js +68 -0
- package/dist/node_modules/undici/lib/mock/mock-errors.js +29 -0
- package/dist/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
- package/dist/node_modules/undici/lib/mock/mock-pool.js +68 -0
- package/dist/node_modules/undici/lib/mock/mock-symbols.js +32 -0
- package/dist/node_modules/undici/lib/mock/mock-utils.js +486 -0
- package/dist/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
- package/dist/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
- package/dist/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
- package/dist/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
- package/dist/node_modules/undici/lib/util/cache.js +407 -0
- package/dist/node_modules/undici/lib/util/date.js +653 -0
- package/dist/node_modules/undici/lib/util/promise.js +28 -0
- package/dist/node_modules/undici/lib/util/runtime-features.js +124 -0
- package/dist/node_modules/undici/lib/util/stats.js +32 -0
- package/dist/node_modules/undici/lib/util/timers.js +425 -0
- package/dist/node_modules/undici/lib/web/cache/cache.js +864 -0
- package/dist/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
- package/dist/node_modules/undici/lib/web/cache/util.js +45 -0
- package/dist/node_modules/undici/lib/web/cookies/constants.js +12 -0
- package/dist/node_modules/undici/lib/web/cookies/index.js +199 -0
- package/dist/node_modules/undici/lib/web/cookies/parse.js +322 -0
- package/dist/node_modules/undici/lib/web/cookies/util.js +282 -0
- package/dist/node_modules/undici/lib/web/eventsource/eventsource-stream.js +399 -0
- package/dist/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
- package/dist/node_modules/undici/lib/web/eventsource/util.js +29 -0
- package/dist/node_modules/undici/lib/web/fetch/LICENSE +21 -0
- package/dist/node_modules/undici/lib/web/fetch/body.js +509 -0
- package/dist/node_modules/undici/lib/web/fetch/constants.js +131 -0
- package/dist/node_modules/undici/lib/web/fetch/data-url.js +596 -0
- package/dist/node_modules/undici/lib/web/fetch/formdata-parser.js +575 -0
- package/dist/node_modules/undici/lib/web/fetch/formdata.js +259 -0
- package/dist/node_modules/undici/lib/web/fetch/global.js +40 -0
- package/dist/node_modules/undici/lib/web/fetch/headers.js +719 -0
- package/dist/node_modules/undici/lib/web/fetch/index.js +2397 -0
- package/dist/node_modules/undici/lib/web/fetch/request.js +1115 -0
- package/dist/node_modules/undici/lib/web/fetch/response.js +641 -0
- package/dist/node_modules/undici/lib/web/fetch/util.js +1520 -0
- package/dist/node_modules/undici/lib/web/infra/index.js +229 -0
- package/dist/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
- package/dist/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
- package/dist/node_modules/undici/lib/web/webidl/index.js +1006 -0
- package/dist/node_modules/undici/lib/web/websocket/connection.js +329 -0
- package/dist/node_modules/undici/lib/web/websocket/constants.js +126 -0
- package/dist/node_modules/undici/lib/web/websocket/events.js +331 -0
- package/dist/node_modules/undici/lib/web/websocket/frame.js +133 -0
- package/dist/node_modules/undici/lib/web/websocket/permessage-deflate.js +118 -0
- package/dist/node_modules/undici/lib/web/websocket/receiver.js +450 -0
- package/dist/node_modules/undici/lib/web/websocket/sender.js +109 -0
- package/dist/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
- package/dist/node_modules/undici/lib/web/websocket/stream/websocketstream.js +497 -0
- package/dist/node_modules/undici/lib/web/websocket/util.js +347 -0
- package/dist/node_modules/undici/lib/web/websocket/websocket.js +751 -0
- package/dist/node_modules/undici/package.json +152 -0
- package/dist/node_modules/undici/scripts/strip-comments.js +10 -0
- package/dist/node_modules/undici/types/README.md +6 -0
- package/dist/node_modules/undici/types/agent.d.ts +32 -0
- package/dist/node_modules/undici/types/api.d.ts +43 -0
- package/dist/node_modules/undici/types/balanced-pool.d.ts +30 -0
- package/dist/node_modules/undici/types/cache-interceptor.d.ts +179 -0
- package/dist/node_modules/undici/types/cache.d.ts +36 -0
- package/dist/node_modules/undici/types/client-stats.d.ts +15 -0
- package/dist/node_modules/undici/types/client.d.ts +123 -0
- package/dist/node_modules/undici/types/connector.d.ts +36 -0
- package/dist/node_modules/undici/types/content-type.d.ts +21 -0
- package/dist/node_modules/undici/types/cookies.d.ts +30 -0
- package/dist/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
- package/dist/node_modules/undici/types/dispatcher.d.ts +273 -0
- package/dist/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
- package/dist/node_modules/undici/types/errors.d.ts +177 -0
- package/dist/node_modules/undici/types/eventsource.d.ts +66 -0
- package/dist/node_modules/undici/types/fetch.d.ts +231 -0
- package/dist/node_modules/undici/types/formdata.d.ts +114 -0
- package/dist/node_modules/undici/types/global-dispatcher.d.ts +9 -0
- package/dist/node_modules/undici/types/global-origin.d.ts +7 -0
- package/dist/node_modules/undici/types/h2c-client.d.ts +73 -0
- package/dist/node_modules/undici/types/handlers.d.ts +14 -0
- package/dist/node_modules/undici/types/header.d.ts +160 -0
- package/dist/node_modules/undici/types/index.d.ts +91 -0
- package/dist/node_modules/undici/types/interceptors.d.ts +80 -0
- package/dist/node_modules/undici/types/mock-agent.d.ts +68 -0
- package/dist/node_modules/undici/types/mock-call-history.d.ts +111 -0
- package/dist/node_modules/undici/types/mock-client.d.ts +27 -0
- package/dist/node_modules/undici/types/mock-errors.d.ts +12 -0
- package/dist/node_modules/undici/types/mock-interceptor.d.ts +94 -0
- package/dist/node_modules/undici/types/mock-pool.d.ts +27 -0
- package/dist/node_modules/undici/types/patch.d.ts +29 -0
- package/dist/node_modules/undici/types/pool-stats.d.ts +19 -0
- package/dist/node_modules/undici/types/pool.d.ts +41 -0
- package/dist/node_modules/undici/types/proxy-agent.d.ts +29 -0
- package/dist/node_modules/undici/types/readable.d.ts +68 -0
- package/dist/node_modules/undici/types/retry-agent.d.ts +8 -0
- package/dist/node_modules/undici/types/retry-handler.d.ts +125 -0
- package/dist/node_modules/undici/types/round-robin-pool.d.ts +41 -0
- package/dist/node_modules/undici/types/snapshot-agent.d.ts +109 -0
- package/dist/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
- package/dist/node_modules/undici/types/util.d.ts +18 -0
- package/dist/node_modules/undici/types/utility.d.ts +7 -0
- package/dist/node_modules/undici/types/webidl.d.ts +347 -0
- package/dist/node_modules/undici/types/websocket.d.ts +188 -0
- package/package.json +2 -2
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const util = require('../core/util')
|
|
4
|
+
const {
|
|
5
|
+
parseCacheControlHeader,
|
|
6
|
+
parseVaryHeader,
|
|
7
|
+
isEtagUsable
|
|
8
|
+
} = require('../util/cache')
|
|
9
|
+
const { parseHttpDate } = require('../util/date.js')
|
|
10
|
+
|
|
11
|
+
function noop () {}
|
|
12
|
+
|
|
13
|
+
// Status codes that we can use some heuristics on to cache
|
|
14
|
+
const HEURISTICALLY_CACHEABLE_STATUS_CODES = [
|
|
15
|
+
200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
// Status codes which semantic is not handled by the cache
|
|
19
|
+
// https://datatracker.ietf.org/doc/html/rfc9111#section-3
|
|
20
|
+
// This list should not grow beyond 206 unless the RFC is updated
|
|
21
|
+
// by a newer one including more. Please introduce another list if
|
|
22
|
+
// implementing caching of responses with the 'must-understand' directive.
|
|
23
|
+
const NOT_UNDERSTOOD_STATUS_CODES = [
|
|
24
|
+
206
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const MAX_RESPONSE_AGE = 2147483647000
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {import('../../types/dispatcher.d.ts').default.DispatchHandler} DispatchHandler
|
|
31
|
+
*
|
|
32
|
+
* @implements {DispatchHandler}
|
|
33
|
+
*/
|
|
34
|
+
class CacheHandler {
|
|
35
|
+
/**
|
|
36
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheKey}
|
|
37
|
+
*/
|
|
38
|
+
#cacheKey
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheHandlerOptions['type']}
|
|
42
|
+
*/
|
|
43
|
+
#cacheType
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @type {number | undefined}
|
|
47
|
+
*/
|
|
48
|
+
#cacheByDefault
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheStore}
|
|
52
|
+
*/
|
|
53
|
+
#store
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @type {import('../../types/dispatcher.d.ts').default.DispatchHandler}
|
|
57
|
+
*/
|
|
58
|
+
#handler
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @type {import('node:stream').Writable | undefined}
|
|
62
|
+
*/
|
|
63
|
+
#writeStream
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheHandlerOptions} opts
|
|
67
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} cacheKey
|
|
68
|
+
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandler} handler
|
|
69
|
+
*/
|
|
70
|
+
constructor ({ store, type, cacheByDefault }, cacheKey, handler) {
|
|
71
|
+
this.#store = store
|
|
72
|
+
this.#cacheType = type
|
|
73
|
+
this.#cacheByDefault = cacheByDefault
|
|
74
|
+
this.#cacheKey = cacheKey
|
|
75
|
+
this.#handler = handler
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onRequestStart (controller, context) {
|
|
79
|
+
this.#writeStream?.destroy()
|
|
80
|
+
this.#writeStream = undefined
|
|
81
|
+
this.#handler.onRequestStart?.(controller, context)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onRequestUpgrade (controller, statusCode, headers, socket) {
|
|
85
|
+
this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {import('../../types/dispatcher.d.ts').default.DispatchController} controller
|
|
90
|
+
* @param {number} statusCode
|
|
91
|
+
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
92
|
+
* @param {string} statusMessage
|
|
93
|
+
*/
|
|
94
|
+
onResponseStart (
|
|
95
|
+
controller,
|
|
96
|
+
statusCode,
|
|
97
|
+
resHeaders,
|
|
98
|
+
statusMessage
|
|
99
|
+
) {
|
|
100
|
+
const downstreamOnHeaders = () =>
|
|
101
|
+
this.#handler.onResponseStart?.(
|
|
102
|
+
controller,
|
|
103
|
+
statusCode,
|
|
104
|
+
resHeaders,
|
|
105
|
+
statusMessage
|
|
106
|
+
)
|
|
107
|
+
const handler = this
|
|
108
|
+
|
|
109
|
+
if (
|
|
110
|
+
!util.safeHTTPMethods.includes(this.#cacheKey.method) &&
|
|
111
|
+
statusCode >= 200 &&
|
|
112
|
+
statusCode <= 399
|
|
113
|
+
) {
|
|
114
|
+
// Successful response to an unsafe method, delete it from cache
|
|
115
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#name-invalidating-stored-response
|
|
116
|
+
try {
|
|
117
|
+
this.#store.delete(this.#cacheKey)?.catch?.(noop)
|
|
118
|
+
} catch {
|
|
119
|
+
// Fail silently
|
|
120
|
+
}
|
|
121
|
+
return downstreamOnHeaders()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const cacheControlHeader = resHeaders['cache-control']
|
|
125
|
+
const heuristicallyCacheable = resHeaders['last-modified'] && HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode)
|
|
126
|
+
if (
|
|
127
|
+
!cacheControlHeader &&
|
|
128
|
+
!resHeaders['expires'] &&
|
|
129
|
+
!heuristicallyCacheable &&
|
|
130
|
+
!this.#cacheByDefault
|
|
131
|
+
) {
|
|
132
|
+
// Don't have anything to tell us this response is cachable and we're not
|
|
133
|
+
// caching by default
|
|
134
|
+
return downstreamOnHeaders()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}
|
|
138
|
+
if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) {
|
|
139
|
+
return downstreamOnHeaders()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const now = Date.now()
|
|
143
|
+
const resAge = resHeaders.age ? getAge(resHeaders.age) : undefined
|
|
144
|
+
if (resAge && resAge >= MAX_RESPONSE_AGE) {
|
|
145
|
+
// Response considered stale
|
|
146
|
+
return downstreamOnHeaders()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const resDate = typeof resHeaders.date === 'string'
|
|
150
|
+
? parseHttpDate(resHeaders.date)
|
|
151
|
+
: undefined
|
|
152
|
+
|
|
153
|
+
const staleAt =
|
|
154
|
+
determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives) ??
|
|
155
|
+
this.#cacheByDefault
|
|
156
|
+
if (staleAt === undefined || (resAge && resAge > staleAt)) {
|
|
157
|
+
return downstreamOnHeaders()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const baseTime = resDate ? resDate.getTime() : now
|
|
161
|
+
const absoluteStaleAt = staleAt + baseTime
|
|
162
|
+
if (now >= absoluteStaleAt) {
|
|
163
|
+
// Response is already stale
|
|
164
|
+
return downstreamOnHeaders()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let varyDirectives
|
|
168
|
+
if (this.#cacheKey.headers && resHeaders.vary) {
|
|
169
|
+
varyDirectives = parseVaryHeader(resHeaders.vary, this.#cacheKey.headers)
|
|
170
|
+
if (!varyDirectives) {
|
|
171
|
+
// Parse error
|
|
172
|
+
return downstreamOnHeaders()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const deleteAt = determineDeleteAt(baseTime, cacheControlDirectives, absoluteStaleAt)
|
|
177
|
+
const strippedHeaders = stripNecessaryHeaders(resHeaders, cacheControlDirectives)
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheValue}
|
|
181
|
+
*/
|
|
182
|
+
const value = {
|
|
183
|
+
statusCode,
|
|
184
|
+
statusMessage,
|
|
185
|
+
headers: strippedHeaders,
|
|
186
|
+
vary: varyDirectives,
|
|
187
|
+
cacheControlDirectives,
|
|
188
|
+
cachedAt: resAge ? now - resAge : now,
|
|
189
|
+
staleAt: absoluteStaleAt,
|
|
190
|
+
deleteAt
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Not modified, re-use the cached value
|
|
194
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#name-handling-304-not-modified
|
|
195
|
+
if (statusCode === 304) {
|
|
196
|
+
const handle304 = (cachedValue) => {
|
|
197
|
+
if (!cachedValue) {
|
|
198
|
+
// Do not create a new cache entry, as a 304 won't have a body - so cannot be cached.
|
|
199
|
+
return downstreamOnHeaders()
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Re-use the cached value: statuscode, statusmessage, headers and body
|
|
203
|
+
value.statusCode = cachedValue.statusCode
|
|
204
|
+
value.statusMessage = cachedValue.statusMessage
|
|
205
|
+
value.etag = cachedValue.etag
|
|
206
|
+
value.headers = { ...cachedValue.headers, ...strippedHeaders }
|
|
207
|
+
|
|
208
|
+
downstreamOnHeaders()
|
|
209
|
+
|
|
210
|
+
this.#writeStream = this.#store.createWriteStream(this.#cacheKey, value)
|
|
211
|
+
|
|
212
|
+
if (!this.#writeStream || !cachedValue?.body) {
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (typeof cachedValue.body.values === 'function') {
|
|
217
|
+
const bodyIterator = cachedValue.body.values()
|
|
218
|
+
|
|
219
|
+
const streamCachedBody = () => {
|
|
220
|
+
for (const chunk of bodyIterator) {
|
|
221
|
+
const full = this.#writeStream.write(chunk) === false
|
|
222
|
+
this.#handler.onResponseData?.(controller, chunk)
|
|
223
|
+
// when stream is full stop writing until we get a 'drain' event
|
|
224
|
+
if (full) {
|
|
225
|
+
break
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
this.#writeStream
|
|
231
|
+
.on('error', function () {
|
|
232
|
+
handler.#writeStream = undefined
|
|
233
|
+
handler.#store.delete(handler.#cacheKey)
|
|
234
|
+
})
|
|
235
|
+
.on('drain', () => {
|
|
236
|
+
streamCachedBody()
|
|
237
|
+
})
|
|
238
|
+
.on('close', function () {
|
|
239
|
+
if (handler.#writeStream === this) {
|
|
240
|
+
handler.#writeStream = undefined
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
streamCachedBody()
|
|
245
|
+
} else if (typeof cachedValue.body.on === 'function') {
|
|
246
|
+
// Readable stream body (e.g. from async/remote cache stores)
|
|
247
|
+
cachedValue.body
|
|
248
|
+
.on('data', (chunk) => {
|
|
249
|
+
this.#writeStream.write(chunk)
|
|
250
|
+
this.#handler.onResponseData?.(controller, chunk)
|
|
251
|
+
})
|
|
252
|
+
.on('end', () => {
|
|
253
|
+
this.#writeStream.end()
|
|
254
|
+
})
|
|
255
|
+
.on('error', () => {
|
|
256
|
+
this.#writeStream = undefined
|
|
257
|
+
this.#store.delete(this.#cacheKey)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
this.#writeStream
|
|
261
|
+
.on('error', function () {
|
|
262
|
+
handler.#writeStream = undefined
|
|
263
|
+
handler.#store.delete(handler.#cacheKey)
|
|
264
|
+
})
|
|
265
|
+
.on('close', function () {
|
|
266
|
+
if (handler.#writeStream === this) {
|
|
267
|
+
handler.#writeStream = undefined
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheValue}
|
|
275
|
+
*/
|
|
276
|
+
const result = this.#store.get(this.#cacheKey)
|
|
277
|
+
if (result && typeof result.then === 'function') {
|
|
278
|
+
result.then(handle304)
|
|
279
|
+
} else {
|
|
280
|
+
handle304(result)
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
if (typeof resHeaders.etag === 'string' && isEtagUsable(resHeaders.etag)) {
|
|
284
|
+
value.etag = resHeaders.etag
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
this.#writeStream = this.#store.createWriteStream(this.#cacheKey, value)
|
|
288
|
+
|
|
289
|
+
if (!this.#writeStream) {
|
|
290
|
+
return downstreamOnHeaders()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
this.#writeStream
|
|
294
|
+
.on('drain', () => controller.resume())
|
|
295
|
+
.on('error', function () {
|
|
296
|
+
// TODO (fix): Make error somehow observable?
|
|
297
|
+
handler.#writeStream = undefined
|
|
298
|
+
|
|
299
|
+
// Delete the value in case the cache store is holding onto state from
|
|
300
|
+
// the call to createWriteStream
|
|
301
|
+
handler.#store.delete(handler.#cacheKey)
|
|
302
|
+
})
|
|
303
|
+
.on('close', function () {
|
|
304
|
+
if (handler.#writeStream === this) {
|
|
305
|
+
handler.#writeStream = undefined
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// TODO (fix): Should we resume even if was paused downstream?
|
|
309
|
+
controller.resume()
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
downstreamOnHeaders()
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
onResponseData (controller, chunk) {
|
|
317
|
+
if (this.#writeStream?.write(chunk) === false) {
|
|
318
|
+
controller.pause()
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this.#handler.onResponseData?.(controller, chunk)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
onResponseEnd (controller, trailers) {
|
|
325
|
+
this.#writeStream?.end()
|
|
326
|
+
this.#handler.onResponseEnd?.(controller, trailers)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
onResponseError (controller, err) {
|
|
330
|
+
this.#writeStream?.destroy(err)
|
|
331
|
+
this.#writeStream = undefined
|
|
332
|
+
this.#handler.onResponseError?.(controller, err)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @see https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen
|
|
338
|
+
*
|
|
339
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
|
|
340
|
+
* @param {number} statusCode
|
|
341
|
+
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
342
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
343
|
+
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} [reqHeaders]
|
|
344
|
+
*/
|
|
345
|
+
function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) {
|
|
346
|
+
// Status code must be final and understood.
|
|
347
|
+
if (statusCode < 200 || NOT_UNDERSTOOD_STATUS_CODES.includes(statusCode)) {
|
|
348
|
+
return false
|
|
349
|
+
}
|
|
350
|
+
// Responses with neither status codes that are heuristically cacheable, nor "explicit enough" caching
|
|
351
|
+
// directives, are not cacheable. "Explicit enough": see https://www.rfc-editor.org/rfc/rfc9111.html#section-3
|
|
352
|
+
if (!HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode) && !resHeaders['expires'] &&
|
|
353
|
+
!cacheControlDirectives.public &&
|
|
354
|
+
cacheControlDirectives['max-age'] === undefined &&
|
|
355
|
+
// RFC 9111: a private response directive, if the cache is not shared
|
|
356
|
+
!(cacheControlDirectives.private && cacheType === 'private') &&
|
|
357
|
+
!(cacheControlDirectives['s-maxage'] !== undefined && cacheType === 'shared')
|
|
358
|
+
) {
|
|
359
|
+
return false
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (cacheControlDirectives['no-store']) {
|
|
363
|
+
return false
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (cacheType === 'shared' && cacheControlDirectives.private === true) {
|
|
367
|
+
return false
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#section-4.1-5
|
|
371
|
+
if (resHeaders.vary?.includes('*')) {
|
|
372
|
+
return false
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen
|
|
376
|
+
if (reqHeaders?.authorization) {
|
|
377
|
+
if (
|
|
378
|
+
!cacheControlDirectives.public &&
|
|
379
|
+
!cacheControlDirectives['s-maxage'] &&
|
|
380
|
+
!cacheControlDirectives['must-revalidate']
|
|
381
|
+
) {
|
|
382
|
+
return false
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (typeof reqHeaders.authorization !== 'string') {
|
|
386
|
+
return false
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (
|
|
390
|
+
Array.isArray(cacheControlDirectives['no-cache']) &&
|
|
391
|
+
cacheControlDirectives['no-cache'].includes('authorization')
|
|
392
|
+
) {
|
|
393
|
+
return false
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (
|
|
397
|
+
Array.isArray(cacheControlDirectives['private']) &&
|
|
398
|
+
cacheControlDirectives['private'].includes('authorization')
|
|
399
|
+
) {
|
|
400
|
+
return false
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return true
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @param {string | string[]} ageHeader
|
|
409
|
+
* @returns {number | undefined}
|
|
410
|
+
*/
|
|
411
|
+
function getAge (ageHeader) {
|
|
412
|
+
const age = parseInt(Array.isArray(ageHeader) ? ageHeader[0] : ageHeader)
|
|
413
|
+
|
|
414
|
+
return isNaN(age) ? undefined : age * 1000
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
|
|
419
|
+
* @param {number} now
|
|
420
|
+
* @param {number | undefined} age
|
|
421
|
+
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
422
|
+
* @param {Date | undefined} responseDate
|
|
423
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
424
|
+
*
|
|
425
|
+
* @returns {number | undefined} time that the value is stale at in seconds or undefined if it shouldn't be cached
|
|
426
|
+
*/
|
|
427
|
+
function determineStaleAt (cacheType, now, age, resHeaders, responseDate, cacheControlDirectives) {
|
|
428
|
+
if (cacheType === 'shared') {
|
|
429
|
+
// Prioritize s-maxage since we're a shared cache
|
|
430
|
+
// s-maxage > max-age > Expire
|
|
431
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.10-3
|
|
432
|
+
const sMaxAge = cacheControlDirectives['s-maxage']
|
|
433
|
+
if (sMaxAge !== undefined) {
|
|
434
|
+
return sMaxAge > 0 ? sMaxAge * 1000 : undefined
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const maxAge = cacheControlDirectives['max-age']
|
|
439
|
+
if (maxAge !== undefined) {
|
|
440
|
+
return maxAge > 0 ? maxAge * 1000 : undefined
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (typeof resHeaders.expires === 'string') {
|
|
444
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.3
|
|
445
|
+
const expiresDate = parseHttpDate(resHeaders.expires)
|
|
446
|
+
if (expiresDate) {
|
|
447
|
+
if (now >= expiresDate.getTime()) {
|
|
448
|
+
return undefined
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (responseDate) {
|
|
452
|
+
if (responseDate >= expiresDate) {
|
|
453
|
+
return undefined
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (age !== undefined && age > (expiresDate - responseDate)) {
|
|
457
|
+
return undefined
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return expiresDate.getTime() - now
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (typeof resHeaders['last-modified'] === 'string') {
|
|
466
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#name-calculating-heuristic-fresh
|
|
467
|
+
const lastModified = new Date(resHeaders['last-modified'])
|
|
468
|
+
if (isValidDate(lastModified)) {
|
|
469
|
+
if (lastModified.getTime() >= now) {
|
|
470
|
+
return undefined
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const responseAge = now - lastModified.getTime()
|
|
474
|
+
|
|
475
|
+
return responseAge * 0.1
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (cacheControlDirectives.immutable) {
|
|
480
|
+
// https://www.rfc-editor.org/rfc/rfc8246.html#section-2.2
|
|
481
|
+
return 31536000
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return undefined
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* @param {number} now
|
|
489
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
490
|
+
* @param {number} staleAt
|
|
491
|
+
*/
|
|
492
|
+
function determineDeleteAt (now, cacheControlDirectives, staleAt) {
|
|
493
|
+
let staleWhileRevalidate = -Infinity
|
|
494
|
+
let staleIfError = -Infinity
|
|
495
|
+
let immutable = -Infinity
|
|
496
|
+
|
|
497
|
+
if (cacheControlDirectives['stale-while-revalidate']) {
|
|
498
|
+
staleWhileRevalidate = staleAt + (cacheControlDirectives['stale-while-revalidate'] * 1000)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (cacheControlDirectives['stale-if-error']) {
|
|
502
|
+
staleIfError = staleAt + (cacheControlDirectives['stale-if-error'] * 1000)
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (cacheControlDirectives.immutable && staleWhileRevalidate === -Infinity && staleIfError === -Infinity) {
|
|
506
|
+
immutable = now + 31536000000
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// When no stale directives or immutable flag, add a revalidation buffer
|
|
510
|
+
// equal to the freshness lifetime so the entry survives past staleAt long
|
|
511
|
+
// enough to be revalidated instead of silently disappearing.
|
|
512
|
+
if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity && immutable === -Infinity) {
|
|
513
|
+
const freshnessLifetime = staleAt - now
|
|
514
|
+
return staleAt + freshnessLifetime
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return Math.max(staleAt, staleWhileRevalidate, staleIfError, immutable)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Strips headers required to be removed in cached responses
|
|
522
|
+
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
523
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
524
|
+
* @returns {Record<string, string | string []>}
|
|
525
|
+
*/
|
|
526
|
+
function stripNecessaryHeaders (resHeaders, cacheControlDirectives) {
|
|
527
|
+
const headersToRemove = [
|
|
528
|
+
'connection',
|
|
529
|
+
'proxy-authenticate',
|
|
530
|
+
'proxy-authentication-info',
|
|
531
|
+
'proxy-authorization',
|
|
532
|
+
'proxy-connection',
|
|
533
|
+
'te',
|
|
534
|
+
'transfer-encoding',
|
|
535
|
+
'upgrade',
|
|
536
|
+
// We'll add age back when serving it
|
|
537
|
+
'age'
|
|
538
|
+
]
|
|
539
|
+
|
|
540
|
+
if (resHeaders['connection']) {
|
|
541
|
+
if (Array.isArray(resHeaders['connection'])) {
|
|
542
|
+
// connection: a
|
|
543
|
+
// connection: b
|
|
544
|
+
headersToRemove.push(...resHeaders['connection'].map(header => header.trim()))
|
|
545
|
+
} else {
|
|
546
|
+
// connection: a, b
|
|
547
|
+
headersToRemove.push(...resHeaders['connection'].split(',').map(header => header.trim()))
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (Array.isArray(cacheControlDirectives['no-cache'])) {
|
|
552
|
+
headersToRemove.push(...cacheControlDirectives['no-cache'])
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (Array.isArray(cacheControlDirectives['private'])) {
|
|
556
|
+
headersToRemove.push(...cacheControlDirectives['private'])
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
let strippedHeaders
|
|
560
|
+
for (const headerName of headersToRemove) {
|
|
561
|
+
if (resHeaders[headerName]) {
|
|
562
|
+
strippedHeaders ??= { ...resHeaders }
|
|
563
|
+
delete strippedHeaders[headerName]
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return strippedHeaders ?? resHeaders
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* @param {Date} date
|
|
572
|
+
* @returns {boolean}
|
|
573
|
+
*/
|
|
574
|
+
function isValidDate (date) {
|
|
575
|
+
return date instanceof Date && Number.isFinite(date.valueOf())
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
module.exports = CacheHandler
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const assert = require('node:assert')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This takes care of revalidation requests we send to the origin. If we get
|
|
7
|
+
* a response indicating that what we have is cached (via a HTTP 304), we can
|
|
8
|
+
* continue using the cached value. Otherwise, we'll receive the new response
|
|
9
|
+
* here, which we then just pass on to the next handler (most likely a
|
|
10
|
+
* CacheHandler). Note that this assumes the proper headers were already
|
|
11
|
+
* included in the request to tell the origin that we want to revalidate the
|
|
12
|
+
* response (i.e. if-modified-since or if-none-match).
|
|
13
|
+
*
|
|
14
|
+
* @see https://www.rfc-editor.org/rfc/rfc9111.html#name-validation
|
|
15
|
+
*
|
|
16
|
+
* @implements {import('../../types/dispatcher.d.ts').default.DispatchHandler}
|
|
17
|
+
*/
|
|
18
|
+
class CacheRevalidationHandler {
|
|
19
|
+
#successful = false
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @type {((boolean, any) => void) | null}
|
|
23
|
+
*/
|
|
24
|
+
#callback
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @type {(import('../../types/dispatcher.d.ts').default.DispatchHandler)}
|
|
28
|
+
*/
|
|
29
|
+
#handler
|
|
30
|
+
|
|
31
|
+
#context
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @type {boolean}
|
|
35
|
+
*/
|
|
36
|
+
#allowErrorStatusCodes
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {(boolean) => void} callback Function to call if the cached value is valid
|
|
40
|
+
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler
|
|
41
|
+
* @param {boolean} allowErrorStatusCodes
|
|
42
|
+
*/
|
|
43
|
+
constructor (callback, handler, allowErrorStatusCodes) {
|
|
44
|
+
if (typeof callback !== 'function') {
|
|
45
|
+
throw new TypeError('callback must be a function')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.#callback = callback
|
|
49
|
+
this.#handler = handler
|
|
50
|
+
this.#allowErrorStatusCodes = allowErrorStatusCodes
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
onRequestStart (_, context) {
|
|
54
|
+
this.#successful = false
|
|
55
|
+
this.#context = context
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
onRequestUpgrade (controller, statusCode, headers, socket) {
|
|
59
|
+
this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onResponseStart (
|
|
63
|
+
controller,
|
|
64
|
+
statusCode,
|
|
65
|
+
headers,
|
|
66
|
+
statusMessage
|
|
67
|
+
) {
|
|
68
|
+
assert(this.#callback != null)
|
|
69
|
+
|
|
70
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#name-handling-a-validation-respo
|
|
71
|
+
// https://datatracker.ietf.org/doc/html/rfc5861#section-4
|
|
72
|
+
this.#successful = statusCode === 304 ||
|
|
73
|
+
(this.#allowErrorStatusCodes && statusCode >= 500 && statusCode <= 504)
|
|
74
|
+
this.#callback(this.#successful, this.#context)
|
|
75
|
+
this.#callback = null
|
|
76
|
+
|
|
77
|
+
if (this.#successful) {
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.#handler.onRequestStart?.(controller, this.#context)
|
|
82
|
+
this.#handler.onResponseStart?.(
|
|
83
|
+
controller,
|
|
84
|
+
statusCode,
|
|
85
|
+
headers,
|
|
86
|
+
statusMessage
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
onResponseData (controller, chunk) {
|
|
91
|
+
if (this.#successful) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return this.#handler.onResponseData?.(controller, chunk)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
onResponseEnd (controller, trailers) {
|
|
99
|
+
if (this.#successful) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.#handler.onResponseEnd?.(controller, trailers)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
onResponseError (controller, err) {
|
|
107
|
+
if (this.#successful) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.#callback) {
|
|
112
|
+
this.#callback(false)
|
|
113
|
+
this.#callback = null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (typeof this.#handler.onResponseError === 'function') {
|
|
117
|
+
this.#handler.onResponseError(controller, err)
|
|
118
|
+
} else {
|
|
119
|
+
throw err
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = CacheRevalidationHandler
|