aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/undici/lib/handler/cache-revalidation-handler.js
diff options
context:
space:
mode:
Diffstat (limited to 'vanilla/node_modules/undici/lib/handler/cache-revalidation-handler.js')
-rw-r--r--vanilla/node_modules/undici/lib/handler/cache-revalidation-handler.js124
1 files changed, 124 insertions, 0 deletions
diff --git a/vanilla/node_modules/undici/lib/handler/cache-revalidation-handler.js b/vanilla/node_modules/undici/lib/handler/cache-revalidation-handler.js
new file mode 100644
index 0000000..393d16d
--- /dev/null
+++ b/vanilla/node_modules/undici/lib/handler/cache-revalidation-handler.js
@@ -0,0 +1,124 @@
+'use strict'
+
+const assert = require('node:assert')
+
+/**
+ * This takes care of revalidation requests we send to the origin. If we get
+ * a response indicating that what we have is cached (via a HTTP 304), we can
+ * continue using the cached value. Otherwise, we'll receive the new response
+ * here, which we then just pass on to the next handler (most likely a
+ * CacheHandler). Note that this assumes the proper headers were already
+ * included in the request to tell the origin that we want to revalidate the
+ * response (i.e. if-modified-since or if-none-match).
+ *
+ * @see https://www.rfc-editor.org/rfc/rfc9111.html#name-validation
+ *
+ * @implements {import('../../types/dispatcher.d.ts').default.DispatchHandler}
+ */
+class CacheRevalidationHandler {
+ #successful = false
+
+ /**
+ * @type {((boolean, any) => void) | null}
+ */
+ #callback
+
+ /**
+ * @type {(import('../../types/dispatcher.d.ts').default.DispatchHandler)}
+ */
+ #handler
+
+ #context
+
+ /**
+ * @type {boolean}
+ */
+ #allowErrorStatusCodes
+
+ /**
+ * @param {(boolean) => void} callback Function to call if the cached value is valid
+ * @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler
+ * @param {boolean} allowErrorStatusCodes
+ */
+ constructor (callback, handler, allowErrorStatusCodes) {
+ if (typeof callback !== 'function') {
+ throw new TypeError('callback must be a function')
+ }
+
+ this.#callback = callback
+ this.#handler = handler
+ this.#allowErrorStatusCodes = allowErrorStatusCodes
+ }
+
+ onRequestStart (_, context) {
+ this.#successful = false
+ this.#context = context
+ }
+
+ onRequestUpgrade (controller, statusCode, headers, socket) {
+ this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
+ }
+
+ onResponseStart (
+ controller,
+ statusCode,
+ headers,
+ statusMessage
+ ) {
+ assert(this.#callback != null)
+
+ // https://www.rfc-editor.org/rfc/rfc9111.html#name-handling-a-validation-respo
+ // https://datatracker.ietf.org/doc/html/rfc5861#section-4
+ this.#successful = statusCode === 304 ||
+ (this.#allowErrorStatusCodes && statusCode >= 500 && statusCode <= 504)
+ this.#callback(this.#successful, this.#context)
+ this.#callback = null
+
+ if (this.#successful) {
+ return true
+ }
+
+ this.#handler.onRequestStart?.(controller, this.#context)
+ this.#handler.onResponseStart?.(
+ controller,
+ statusCode,
+ headers,
+ statusMessage
+ )
+ }
+
+ onResponseData (controller, chunk) {
+ if (this.#successful) {
+ return
+ }
+
+ return this.#handler.onResponseData?.(controller, chunk)
+ }
+
+ onResponseEnd (controller, trailers) {
+ if (this.#successful) {
+ return
+ }
+
+ this.#handler.onResponseEnd?.(controller, trailers)
+ }
+
+ onResponseError (controller, err) {
+ if (this.#successful) {
+ return
+ }
+
+ if (this.#callback) {
+ this.#callback(false)
+ this.#callback = null
+ }
+
+ if (typeof this.#handler.onResponseError === 'function') {
+ this.#handler.onResponseError(controller, err)
+ } else {
+ throw err
+ }
+ }
+}
+
+module.exports = CacheRevalidationHandler