|
export default { |
|
async fetch(request, env, ctx) { |
|
if (request.method !== "GET") { |
|
return new Response("Only GET requests are allowed.", { |
|
status: 405, // Method Not Allowed |
|
headers: { Allow: "GET" }, |
|
}); |
|
} |
|
|
|
let url = new URL(request.url); |
|
|
|
// Define allowed path regex patterns |
|
const allowedPaths = [ |
|
/^\/$/, // / |
|
/^\/nix-cache-info$/, // /nix-cache-info |
|
/^\/[a-z0-9]+\.narinfo$/, // /[a-z0-9]+.narinfo |
|
/^\/nar\/[a-z0-9]+\.nar(\.[a-z0-9]{2,4})?$/, // /nar/[a-z0-9]+.nar(.{2})? |
|
]; |
|
|
|
// Check if the path matches any of the allowed patterns |
|
const isAllowed = allowedPaths.some((regex) => regex.test(url.pathname)); |
|
if (!isAllowed) { |
|
return new Response("Forbidden: Path not allowed.", { |
|
status: 403, // Forbidden |
|
}); |
|
} |
|
|
|
let cache = caches.default; // Default Cloudflare cache |
|
|
|
// Remove query string |
|
url.search = ""; |
|
|
|
// Update protocol and host |
|
url.protocol = "http:"; |
|
url.host = "cache.nixos.org"; |
|
|
|
// Check if the response is already cached |
|
let cachedResponse = await cache.match(request); |
|
if (cachedResponse) { |
|
return cachedResponse; |
|
} |
|
|
|
// Fetch from origin |
|
const originResponse = await fetch(url.href); |
|
|
|
let response; |
|
|
|
// Modify response for `/` route |
|
if (url.pathname === "/") { |
|
const originalBody = await originResponse.text(); |
|
const modifiedBody = originalBody.replace(/cache\.nixos\.org/g, "nixos-cache-proxy.cofob.dev"); |
|
|
|
response = new Response(modifiedBody, { |
|
status: originResponse.status, |
|
statusText: originResponse.statusText, |
|
headers: originResponse.headers, |
|
}); |
|
} else { |
|
response = originResponse; |
|
} |
|
|
|
const updatedHeaders = new Headers(response.headers); |
|
|
|
// Filter headers to remove those starting with "x-" and replace Cache-Control |
|
for (let [key, value] of response.headers) { |
|
if (key.toLowerCase().startsWith("x-") || key.toLowerCase() === "cache-control") { |
|
updatedHeaders.delete(key); |
|
} |
|
} |
|
|
|
// Adjust caching for 404 responses |
|
if (response.status === 404) { |
|
updatedHeaders.set("Cache-Control", "public, max-age=3600"); // 1 hour cache |
|
} else { |
|
updatedHeaders.set("Cache-Control", "public, immutable, max-age=31536000"); |
|
} |
|
|
|
// Create a new response with updated headers |
|
const finalResponse = new Response(response.body, { |
|
status: response.status, |
|
statusText: response.statusText, |
|
headers: updatedHeaders, |
|
}); |
|
|
|
// Cache the response clone for future requests |
|
ctx.waitUntil(cache.put(request, finalResponse.clone())); |
|
|
|
return finalResponse; |
|
}, |
|
}; |