Skip to content

🐛 stop proxy from serving decompressed HTML as gzip#487

Merged
taras merged 1 commit into
productionfrom
fix-proxy-gzip-header
Jul 7, 2026
Merged

🐛 stop proxy from serving decompressed HTML as gzip#487
taras merged 1 commit into
productionfrom
fix-proxy-gzip-header

Conversation

@taras

@taras taras commented Jul 6, 2026

Copy link
Copy Markdown
Member

Motivation

The deploy workflow was failing at the Staticalize step with an uncaught TypeError: Invalid gzip header. Running the (newly improved) staticalize against the live local site pinpointed it: 259 pages OK, but 349 failures — every one Invalid gzip header, all confined to the proxied doc sub-sites /effection/*, /interactors/*, /graphgen/*.

Root cause is in routes/proxy-route.ts. For HTML responses the proxy reads the upstream body with response.text() — which fetch() has already decompressed — rewrites the HTML, and rebuilds the Response from the plain-text result. But it copied the upstream headers verbatim onto the new body, including content-encoding: gzip and the stale content-length. So it served uncompressed HTML labelled as gzip, and any client (staticalize, browsers) failed to decode it.

Assets went through the untouched return response pass-through, which Deno serves correctly — which is why only the rewritten HTML pages broke.

Approach

Add a copyHeaders() helper that copies an upstream response's headers while dropping the ones that describe the original wire framing — content-encoding, content-length, transfer-encoding — and let the server recompute them for the rebuilt body. Applied in both the HTML-rewrite branch and the redirect branch.

Verification

Ran the site locally with the fix and re-ran staticalize exactly as CI does:

  • Before: 259 pages, 349 errors, exit 1
  • After: 608 pages, 322 assets, 0 errors, exit 0

/effection/ now responds without content-encoding: gzip and with a correct content-length, and the body decodes as HTML.

The staticalize error-reporting improvement (staticalize#8) is what surfaced the offending URLs but is not required for this fix.

The proxy reads an upstream response with `response.text()`, which fetch
transparently decompresses, then rebuilds the response from the rewritten
HTML. It copied the upstream headers verbatim onto the new body — including
`content-encoding: gzip` and the stale `content-length` — so it served
plain HTML labelled as gzip. Clients (staticalize, browsers) then failed to
decode it with `Invalid gzip header`, which broke the deploy for every
proxied /effection, /interactors and /graphgen page.

Drop content-encoding/content-length/transfer-encoding when copying headers
for a rebuilt body and let the server recompute them.

@jbolda jbolda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran into this in #488. Seems like a reasonable resolution.

@taras taras merged commit 1fb03eb into production Jul 7, 2026
3 checks passed
@taras taras deleted the fix-proxy-gzip-header branch July 7, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants