From 0c44ce1a4d1bbb420a99504049298fa72ce7a6a0 Mon Sep 17 00:00:00 2001 From: ThePhaseless Date: Sun, 9 Aug 2026 19:06:56 +0200 Subject: [PATCH] fix: request uncompressed bodies in CSP-strip route route.fulfill(response=...) re-serves the raw bytes fetched by route.fetch(), so compressed (gzip/brotli/zstd) documents arrive at the browser still compressed while the forwarded headers claim otherwise - page.content() then returns garbled binary, breaking indexers like uindex.org and 1337x.to (issue #385). Fetch with accept-encoding: identity so the re-served body is plain text, and drop content-encoding/content-length alongside the CSP headers since they are stale after the rewrite. --- src/endpoints.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/endpoints.py b/src/endpoints.py index dbe6788..714cb4f 100644 --- a/src/endpoints.py +++ b/src/endpoints.py @@ -26,8 +26,16 @@ router = APIRouter() BrowserDep = Annotated[BrowserDepClass, Depends(get_browser)] -CSP_HEADERS = frozenset( - {"content-security-policy", "content-security-policy-report-only"} +# Headers to strip from the fulfilled response: CSP is removed for navigation +# freedom, and content-encoding/content-length are stale once we request an +# uncompressed body via accept-encoding: identity below. +DROP_HEADERS = frozenset( + { + "content-security-policy", + "content-security-policy-report-only", + "content-encoding", + "content-length", + } ) @@ -80,7 +88,13 @@ async def read_item(request: LinkRequest, dep: BrowserDep) -> LinkResponse: if route.request.resource_type != "document": await route.continue_() return - response = await route.fetch() + # Request an uncompressed body via accept-encoding: identity. When + # route.fulfill re-serves the fetched response (by uid), it forwards + # the original compressed bytes; stripping content-encoding below + # would leave the browser reading compressed bytes as plain text. + response = await route.fetch( + headers={**route.request.headers, "accept-encoding": "identity"} + ) if route.request.frame == dep.page.main_frame: final_url = response.url await route.fulfill( @@ -88,7 +102,7 @@ async def read_item(request: LinkRequest, dep: BrowserDep) -> LinkResponse: headers={ key: value for key, value in response.headers.items() - if key.lower() not in CSP_HEADERS + if key.lower() not in DROP_HEADERS }, )