UNPKG

@fly/cdn

Version:
164 lines 19 kB
/** * @module Middleware */ import cache from "@fly/v8env/lib/fly/cache"; /** * Cache HTTP responses with `cache-control` headers. * * Basic example: * ```typescript * import httpCache from "./src/middleware/http-cache"; * import backends from "./src/backends"; * * const glitch = backends.glitch("fly-example"); * * const origin = httpCache(glitch, { overrideMaxAge: 3600 }); * * fly.http.respondWith(origin); * ``` * * @param fetch * @param options */ export function httpCache(fetch, options) { return async function httpCacheFetch(req, init) { if (!options) options = {}; if (typeof req === "string") { req = new Request(req, init); init = undefined; } // check the cache let cacheable = true; for (const h of ["Authorization", "Cookie"]) { if (req.headers.get(h)) { console.warn(h + " headers are not supported in http-cache"); cacheable = false; } } let resp = cacheable ? await storage.match(req) : undefined; if (resp) { // got a hit resp.headers.set("Fly-Cache", "hit"); return resp; } resp = await fetch(req, init); // this should do nothing if the response can't be cached const cacheHappened = cacheable ? await storage.put(req, resp, options.overrideMaxAge) : false; if (cacheHappened) { resp.headers.set("Fly-Cache", "miss"); } return resp; }; } /** * Configurable HTTP caching middleware. This is extremely useful within a `pipeline`: * * ```typescript * const app = pipeline( * httpsUpgrader, * httpCaching.configure({overrideMaxAge: 3600}), * glitch("fly-example") * ) * */ httpCache.configure = (options) => { return (fetch) => httpCache(fetch, options); }; // copied from fly v8env const CachePolicy = require("http-cache-semantics"); /** * export: * match(req): res | null * add(req): void * put(req, res): void * @private */ const storage = { async match(req) { const hashed = hashData(req); const key = "httpcache:policy:" + hashed; // first try with no vary variant for (let i = 0; i < 5; i++) { const policyRaw = await cache.getString(key); console.debug("Got policy:", key, policyRaw); if (!policyRaw) { return undefined; } const policy = CachePolicy.fromObject(JSON.parse(policyRaw)); // if it fits i sits if (policy.satisfiesWithoutRevalidation(req)) { const headers = policy.responseHeaders(); const bodyKey = "httpcache:body:" + hashed; const body = await cache.get(bodyKey); console.debug("Got body", body.constructor.name, body.byteLength); return new Response(body, { status: policy._status, headers }); // }else if(policy._headers){ // TODO: try a new vary based key // policy._headers has the varies / vary values // key = hashData(req, policy._headers) // return undefined } else { return undefined; } } return undefined; // no matches found }, async add(req) { console.debug("cache add"); const res = await fetch(req); return await storage.put(req, res); }, async put(req, res, ttl) { const resHeaders = {}; const key = hashData(req); if (res.headers.get("vary")) { console.warn("Vary headers are not supported in http-cache"); return false; } for (const [name, value] of res.headers) { resHeaders[name] = value; } const cacheableRes = { status: res.status, headers: resHeaders }; const policy = new CachePolicy({ url: req.url, method: req.method, headers: req.headers || {} }, cacheableRes); if (typeof ttl === "number") { policy._rescc['max-age'] = ttl; // hack to make policy handle overridden ttl console.warn("ttl:", ttl, "storable:", policy.storable()); } ttl = typeof ttl === "number" ? ttl : Math.floor(policy.timeToLive() / 1000); if (policy.storable() && ttl > 0) { console.debug("Setting cache policy:", "httpcache:policy:" + key, ttl); await cache.set("httpcache:policy:" + key, JSON.stringify(policy.toObject()), ttl); const respBody = await res.arrayBuffer(); await cache.set("httpcache:body:" + key, respBody, ttl); return true; } return false; } }; function hashData(req) { let toHash = ``; const u = normalizeURL(req.url); toHash += u.toString(); toHash += req.method; // TODO: cacheable cookies // TODO: cache version for grand busting console.debug("hashData", toHash); return crypto.subtle.digestSync("sha-1", toHash, "hex"); } function normalizeURL(u) { const url = new URL(u); url.hash = ""; const sp = url.searchParams; sp.sort(); url.search = sp.toString(); return url; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1jYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2h0dHAtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFDSCxPQUFPLEtBQUssTUFBTSwwQkFBMEIsQ0FBQztBQVU3Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLFVBQVUsU0FBUyxDQUFDLEtBQW9CLEVBQUUsT0FBMEI7SUFDeEUsT0FBTyxLQUFLLFVBQVUsY0FBYyxDQUFDLEdBQWdCLEVBQUUsSUFBa0I7UUFDdkUsSUFBRyxDQUFDLE9BQU87WUFBRSxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQzFCLElBQUcsT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFDO1lBQ3pCLEdBQUcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDN0IsSUFBSSxHQUFHLFNBQVMsQ0FBQztTQUNsQjtRQUVELGtCQUFrQjtRQUNsQixJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUM7UUFDckIsS0FBSSxNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxRQUFRLENBQUMsRUFBQztZQUN6QyxJQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO2dCQUNwQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRywwQ0FBMEMsQ0FBQyxDQUFBO2dCQUM1RCxTQUFTLEdBQUcsS0FBSyxDQUFDO2FBQ25CO1NBQ0Y7UUFDRCxJQUFJLElBQUksR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRTVELElBQUcsSUFBSSxFQUFDO1lBQ04sWUFBWTtZQUNaLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNyQyxP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QyxDQUFBO0lBQ3RCLEdBQUcsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFBO0lBQ2IsTUFBTSxFQUFFLEdBQUcsR0FBRyxDQUFDLFlBQVksQ0FBQTtJQUMzQixFQUFFLENBQUMsSUFBSSxFQUFFLENBQUE7SUFDVCxHQUFHLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtJQUUxQixPQUFPLEdBQUcsQ0FBQTtBQUNaLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBtb2R1bGUgTWlkZGxld2FyZVxuICovXG5pbXBvcnQgY2FjaGUgZnJvbSBcIkBmbHkvdjhlbnYvbGliL2ZseS9jYWNoZVwiO1xuaW1wb3J0IHsgRmV0Y2hGdW5jdGlvbiB9IGZyb20gXCIuLi9mZXRjaFwiO1xuXG4vKipcbiAqIEhUVFAgY2FjaGluZyBvcHRpb25zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEhUVFBDYWNoZU9wdGlvbnN7XG4gIC8qKiBPdmVycmlkZXMgdGhlIGNhY2hlIFRUTCBmb3IgYWxsIGNhY2hlYWJsZSByZXF1ZXN0cyAqL1xuICBvdmVycmlkZU1heEFnZT86IG51bWJlclxufVxuLyoqXG4gKiBDYWNoZSBIVFRQIHJlc3BvbnNlcyB3aXRoIGBjYWNoZS1jb250cm9sYCBoZWFkZXJzLlxuICogXG4gKiBCYXNpYyBleGFtcGxlOlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IGh0dHBDYWNoZSBmcm9tIFwiLi9zcmMvbWlkZGxld2FyZS9odHRwLWNhY2hlXCI7XG4gKiBpbXBvcnQgYmFja2VuZHMgZnJvbSBcIi4vc3JjL2JhY2tlbmRzXCI7XG4gKiBcbiAqIGNvbnN0IGdsaXRjaCA9IGJhY2tlbmRzLmdsaXRjaChcImZseS1leGFtcGxlXCIpO1xuICogXG4gKiBjb25zdCBvcmlnaW4gPSBodHRwQ2FjaGUoZ2xpdGNoLCB7IG92ZXJyaWRlTWF4QWdlOiAzNjAwIH0pO1xuICogXG4gKiBmbHkuaHR0cC5yZXNwb25kV2l0aChvcmlnaW4pO1xuICogYGBgXG4gKiBcbiAqIEBwYXJhbSBmZXRjaCBcbiAqIEBwYXJhbSBvcHRpb25zIFxuICovXG5leHBvcnQgZnVuY3Rpb24gaHR0cENhY2hlKGZldGNoOiBGZXRjaEZ1bmN0aW9uLCBvcHRpb25zPzogSFRUUENhY2hlT3B0aW9ucyk6IEZldGNoRnVuY3Rpb257XG4gIHJldHVybiBhc3luYyBmdW5jdGlvbiBodHRwQ2FjaGVGZXRjaChyZXE6IFJlcXVlc3RJbmZvLCBpbml0PzogUmVxdWVzdEluaXQpOiBQcm9taXNlPFJlc3BvbnNlPntcbiAgICBpZighb3B0aW9ucykgb3B0aW9ucyA9IHt9O1xuICAgIGlmKHR5cGVvZiByZXEgPT09IFwic3RyaW5nXCIpe1xuICAgICAgcmVxID0gbmV3IFJlcXVlc3QocmVxLCBpbml0KTtcbiAgICAgIGluaXQgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gY2hlY2sgdGhlIGNhY2hlXG4gICAgbGV0IGNhY2hlYWJsZSA9IHRydWU7XG4gICAgZm9yKGNvbnN0IGggb2YgW1wiQXV0aG9yaXphdGlvblwiLCBcIkNvb2tpZVwiXSl7XG4gICAgICBpZihyZXEuaGVhZGVycy5nZXQoaCkpe1xuICAgICAgICBjb25zb2xlLndhcm4oaCArIFwiIGhlYWRlcnMgYXJlIG5vdCBzdXBwb3J0ZWQgaW4gaHR0cC1jYWNoZVwiKVxuICAgICAgICBjYWNoZWFibGUgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gICAgbGV0IHJlc3AgPSBjYWNoZWFibGUgPyBhd2FpdCBzdG9yYWdlLm1hdGNoKHJlcSkgOiB1bmRlZmluZWQ7XG5cbiAgICBpZihyZXNwKXtcbiAgICAgIC8vIGdvdCBhIGhpdFxuICAgICAgcmVzcC5oZWFkZXJzLnNldChcIkZseS1DYWNoZVwiLCBcImhpdFwiKTtcbiAgICAgIHJldHVybiByZXNwO1xuICAgIH1cblxuICAgIHJlc3AgPSBhd2FpdCBmZXRjaChyZXEsIGluaXQpO1xuXG4gICAgLy8gdGhpcyBzaG91bGQgZG8gbm90aGluZyBpZiB0aGUgcmVzcG9uc2UgY2FuJ3QgYmUgY2FjaGVkXG4gICAgY29uc3QgY2FjaGVIYXBwZW5lZCA9IGNhY2hlYWJsZSA/IGF3YWl0IHN0b3JhZ2UucHV0KHJlcSwgcmVzcCwgb3B0aW9ucy5vdmVycmlkZU1heEFnZSkgOiBmYWxzZTtcblxuICAgIGlmKGNhY2hlSGFwcGVuZWQpe1xuICAgICAgcmVzcC5oZWFkZXJzLnNldChcIkZseS1DYWNoZVwiLCBcIm1pc3NcIik7XG4gICAgfVxuICAgIHJldHVybiByZXNwO1xuICB9XG59XG5cbi8qKlxuICogQ29uZmlndXJhYmxlIEhUVFAgY2FjaGluZyBtaWRkbGV3YXJlLiBUaGlzIGlzIGV4dHJlbWVseSB1c2VmdWwgd2l0aGluIGEgYHBpcGVsaW5lYDpcbiAqIFxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgYXBwID0gcGlwZWxpbmUoXG4gKiAgICAgaHR0cHNVcGdyYWRlcixcbiAqICAgICBodHRwQ2FjaGluZy5jb25maWd1cmUoe292ZXJyaWRlTWF4QWdlOiAzNjAwfSksXG4gKiAgICAgZ2xpdGNoKFwiZmx5LWV4YW1wbGVcIilcbiAqIClcbiAqIFxuICovXG5odHRwQ2FjaGUuY29uZmlndXJlID0gKG9wdGlvbnM/OiBIVFRQQ2FjaGVPcHRpb25zKSA9PiB7XG4gIHJldHVybiAoZmV0Y2g6IEZldGNoRnVuY3Rpb24pID0+IGh0dHBDYWNoZShmZXRjaCwgb3B0aW9ucylcbn1cblxuLy8gY29waWVkIGZyb20gZmx5IHY4ZW52XG5jb25zdCBDYWNoZVBvbGljeSA9IHJlcXVpcmUoXCJodHRwLWNhY2hlLXNlbWFudGljc1wiKTtcbi8qKlxuICogZXhwb3J0OlxuICogXHRtYXRjaChyZXEpOiByZXMgfCBudWxsXG4gKiBcdGFkZChyZXEpOiB2b2lkXG4gKiBcdHB1dChyZXEsIHJlcyk6IHZvaWRcbiAqIEBwcml2YXRlXG4gKi9cblxuY29uc3Qgc3RvcmFnZSA9IHtcbiAgYXN5bmMgbWF0Y2gocmVxOiBSZXF1ZXN0KSB7XG4gICAgY29uc3QgaGFzaGVkID0gaGFzaERhdGEocmVxKVxuICAgIGNvbnN0IGtleSA9IFwiaHR0cGNhY2hlOnBvbGljeTpcIiArIGhhc2hlZCAvLyBmaXJzdCB0cnkgd2l0aCBubyB2YXJ5IHZhcmlhbnRcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IDU7IGkrKykge1xuICAgICAgY29uc3QgcG9saWN5UmF3ID0gYXdhaXQgY2FjaGUuZ2V0U3RyaW5nKGtleSlcbiAgICAgIGNvbnNvbGUuZGVidWcoXCJHb3QgcG9saWN5OlwiLCBrZXksIHBvbGljeVJhdylcbiAgICAgIGlmICghcG9saWN5UmF3KSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICAgIH1cbiAgICAgIGNvbnN0IHBvbGljeSA9IENhY2hlUG9saWN5LmZyb21PYmplY3QoSlNPTi5wYXJzZShwb2xpY3lSYXcpKVxuXG4gICAgICAvLyBpZiBpdCBmaXRzIGkgc2l0c1xuICAgICAgaWYgKHBvbGljeS5zYXRpc2ZpZXNXaXRob3V0UmV2YWxpZGF0aW9uKHJlcSkpIHtcbiAgICAgICAgY29uc3QgaGVhZGVycyA9IHBvbGljeS5yZXNwb25zZUhlYWRlcnMoKVxuICAgICAgICBjb25zdCBib2R5S2V5ID0gXCJodHRwY2FjaGU6Ym9keTpcIiArIGhhc2hlZFxuXG4gICAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCBjYWNoZS5nZXQoYm9keUtleSlcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcIkdvdCBib2R5XCIsIGJvZHkuY29uc3RydWN0b3IubmFtZSwgYm9keS5ieXRlTGVuZ3RoKVxuICAgICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKGJvZHksIHsgc3RhdHVzOiBwb2xpY3kuX3N0YXR1cywgaGVhZGVycyB9KVxuICAgICAgICAvLyB9ZWxzZSBpZihwb2xpY3kuX2hlYWRlcnMpe1xuICAgICAgICAvLyBUT0RPOiB0cnkgYSBuZXcgdmFyeSBiYXNlZCBrZXlcbiAgICAgICAgLy8gcG9saWN5Ll9oZWFkZXJzIGhhcyB0aGUgdmFyaWVzIC8gdmFyeSB2YWx1ZXNcbiAgICAgICAgLy8ga2V5ID0gaGFzaERhdGEocmVxLCBwb2xpY3kuX2hlYWRlcnMpXG4gICAgICAgIC8vIHJldHVybiB1bmRlZmluZWRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZCAvLyBubyBtYXRjaGVzIGZvdW5kXG4gIH0sXG4gIGFzeW5jIGFkZChyZXE6IFJlcXVlc3QpIHtcbiAgICBjb25zb2xlLmRlYnVnKFwiY2FjaGUgYWRkXCIpXG5cbiAgICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaChyZXEpXG4gICAgcmV0dXJuIGF3YWl0IHN0b3JhZ2UucHV0KHJlcSwgcmVzKVxuICB9LFxuICBhc3luYyBwdXQocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCB0dGw/OiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCByZXNIZWFkZXJzOiBhbnkgPSB7fVxuICAgIGNvbnN0IGtleSA9IGhhc2hEYXRhKHJlcSlcblxuICAgIGlmKHJlcy5oZWFkZXJzLmdldChcInZhcnlcIikpe1xuICAgICAgY29uc29sZS53YXJuKFwiVmFyeSBoZWFkZXJzIGFyZSBub3Qgc3VwcG9ydGVkIGluIGh0dHAtY2FjaGVcIilcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgKHJlcyBhcyBhbnkpLmhlYWRlcnMpIHtcbiAgICAgIHJlc0hlYWRlcnNbbmFtZV0gPSB2YWx1ZVxuICAgIH1cbiAgICBjb25zdCBjYWNoZWFibGVSZXMgPSB7XG4gICAgICBzdGF0dXM6IHJlcy5zdGF0dXMsXG4gICAgICBoZWFkZXJzOiByZXNIZWFkZXJzXG4gICAgfVxuICAgIGNvbnN0IHBvbGljeSA9IG5ldyBDYWNoZVBvbGljeShcbiAgICAgIHtcbiAgICAgICAgdXJsOiByZXEudXJsLFxuICAgICAgICBtZXRob2Q6IHJlcS5tZXRob2QsXG4gICAgICAgIGhlYWRlcnM6IHJlcS5oZWFkZXJzIHx8IHt9XG4gICAgICB9LFxuICAgICAgY2FjaGVhYmxlUmVzXG4gICAgKVxuXG4gICAgaWYodHlwZW9mIHR0bCA9PT0gXCJudW1iZXJcIil7XG4gICAgICBwb2xpY3kuX3Jlc2NjWydtYXgtYWdlJ10gPSB0dGw7IC8vIGhhY2sgdG8gbWFrZSBwb2xpY3kgaGFuZGxlIG92ZXJyaWRkZW4gdHRsXG4gICAgICBjb25zb2xlLndhcm4oXCJ0dGw6XCIsIHR0bCwgXCJzdG9yYWJsZTpcIiwgcG9saWN5LnN0b3JhYmxlKCkpO1xuICAgIH1cblxuICAgIHR0bCA9IHR5cGVvZiB0dGwgPT09IFwibnVtYmVyXCIgPyB0dGwgOiBNYXRoLmZsb29yKHBvbGljeS50aW1lVG9MaXZlKCkgLyAxMDAwKTtcbiAgICBpZiAocG9saWN5LnN0b3JhYmxlKCkgJiYgdHRsID4gMCkge1xuICAgICAgY29uc29sZS5kZWJ1ZyhcIlNldHRpbmcgY2FjaGUgcG9saWN5OlwiLCBcImh0dHBjYWNoZTpwb2xpY3k6XCIgKyBrZXksIHR0bClcbiAgICAgIGF3YWl0IGNhY2hlLnNldChcImh0dHBjYWNoZTpwb2xpY3k6XCIgKyBrZXksIEpTT04uc3RyaW5naWZ5KHBvbGljeS50b09iamVjdCgpKSwgdHRsKVxuICAgICAgY29uc3QgcmVzcEJvZHkgPSBhd2FpdCByZXMuYXJyYXlCdWZmZXIoKVxuICAgICAgYXdhaXQgY2FjaGUuc2V0KFwiaHR0cGNhY2hlOmJvZHk6XCIgKyBrZXksIHJlc3BCb2R5LCB0dGwpXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbmZ1bmN0aW9uIGhhc2hEYXRhKHJlcTogUmVxdWVzdCkge1xuICBsZXQgdG9IYXNoID0gYGBcblxuICBjb25zdCB1ID0gbm9ybWFsaXplVVJMKHJlcS51cmwpXG5cbiAgdG9IYXNoICs9IHUudG9TdHJpbmcoKVxuICB0b0hhc2ggKz0gcmVxLm1ldGhvZFxuXG4gIC8vIFRPRE86IGNhY2hlYWJsZSBjb29raWVzXG4gIC8vIFRPRE86IGNhY2hlIHZlcnNpb24gZm9yIGdyYW5kIGJ1c3RpbmdcblxuICBjb25zb2xlLmRlYnVnKFwiaGFzaERhdGFcIiwgdG9IYXNoKVxuICByZXR1cm4gKGNyeXB0byBhcyBhbnkpLnN1YnRsZS5kaWdlc3RTeW5jKFwic2hhLTFcIiwgdG9IYXNoLCBcImhleFwiKVxufVxuXG5mdW5jdGlvbiBub3JtYWxpemVVUkwodTpzdHJpbmcpIHtcbiAgY29uc3QgdXJsID0gbmV3IFVSTCh1KVxuICB1cmwuaGFzaCA9IFwiXCJcbiAgY29uc3Qgc3AgPSB1cmwuc2VhcmNoUGFyYW1zXG4gIHNwLnNvcnQoKVxuICB1cmwuc2VhcmNoID0gc3AudG9TdHJpbmcoKVxuXG4gIHJldHVybiB1cmxcbn1cbiJdfQ==