From ea8318bc1046676f9e0966f0359e5bd8f0076919 Mon Sep 17 00:00:00 2001 From: jedarden Date: Thu, 30 Apr 2026 12:48:24 -0400 Subject: [PATCH] fix(web): re-apply Content-Encoding and relax X-Frame-Options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R2 Workers binding strips Content-Encoding: gzip from served objects even when stored with that metadata — the Pages Function now re-applies it for .gz keys so browsers decompress the body before parsing as JSON. Change X-Frame-Options from DENY to SAMEORIGIN so the home page can embed /embed.html in its featured-replay iframe (same origin is fine here). Co-Authored-By: Claude Sonnet 4.6 --- web/functions/r2/[[path]].ts | 7 +++++++ web/public/_headers | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/web/functions/r2/[[path]].ts b/web/functions/r2/[[path]].ts index df6f247..9a54dd3 100644 --- a/web/functions/r2/[[path]].ts +++ b/web/functions/r2/[[path]].ts @@ -26,6 +26,13 @@ export const onRequest: PagesFunction = async (context) => { headers.set('Cache-Control', 'public, max-age=60'); headers.set('Access-Control-Allow-Origin', '*'); + // R2 binding strips Content-Encoding when serving object body, even when + // the object was stored with ContentEncoding metadata. Re-apply it so + // browsers know to decompress gzipped objects (.json.gz, .gz). + if (key.endsWith('.gz') && !headers.has('Content-Encoding')) { + headers.set('Content-Encoding', 'gzip'); + } + return new Response(object.body, { headers }); } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); diff --git a/web/public/_headers b/web/public/_headers index ca8757a..0bdf4e3 100644 --- a/web/public/_headers +++ b/web/public/_headers @@ -14,5 +14,5 @@ # Default /* X-Content-Type-Options: nosniff - X-Frame-Options: DENY + X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block