From 96fb6d807c36e4d987f4ab06c213ee0adbaef6c7 Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:41:14 -0400 Subject: [PATCH] Fix truncated responses from compressed upstreams fetch() decompresses transparently, but the proxies forwarded the upstream content-length, so browsers cut compressed Plex/Seafile responses short and JSON.parse failed. Ask Plex for identity encoding and drop the stale length whenever the upstream response was encoded. Co-Authored-By: Claude Sonnet 5.5 --- server.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 81d68f0..2969b0f 100644 --- a/server.js +++ b/server.js @@ -38,6 +38,7 @@ async function proxySeafile(req, res) { const out = {}; for (const h of ['content-type', 'content-length', 'content-disposition', 'content-range', 'accept-ranges']) { if (inline && h === 'content-disposition') continue; + if (h === 'content-length' && upstream.headers.get('content-encoding')) continue; // decompressed by fetch, so the length changed const v = upstream.headers.get(h); if (v) out[h] = v; } @@ -245,14 +246,16 @@ async function plexApi(req, res) { async function plexProxy(req, res) { const ck = parseCookies(req), base = unsigned(ck.plex_srv), tok = ck.plex_stk; if (!base || !tok) { res.writeHead(401); return res.end(); } - const headers = { ...PLEX_HEADERS, 'X-Plex-Token': tok, Accept: req.headers.accept || 'application/json' }; + const headers = { ...PLEX_HEADERS, 'X-Plex-Token': tok, Accept: req.headers.accept || 'application/json', 'Accept-Encoding': 'identity' }; if (req.headers.range) headers.range = req.headers.range; const ac = new AbortController(); res.on('close', () => ac.abort()); try { const up = await fetch(base + req.url.slice('/plex'.length), { headers, signal: ac.signal }); const out = {}; - for (const h of ['content-type', 'content-length', 'content-range', 'accept-ranges']) { const v = up.headers.get(h); if (v) out[h] = v; } + // fetch() transparently decompresses, so an upstream content-length would no longer match the bytes we send. + const encoded = !!up.headers.get('content-encoding'); + for (const h of ['content-type', 'content-length', 'content-range', 'accept-ranges']) { if (encoded && h === 'content-length') continue; const v = up.headers.get(h); if (v) out[h] = v; } if (req.url.startsWith('/plex/photo/')) out['cache-control'] = 'private, max-age=86400'; res.writeHead(up.status, out); if (up.body) Readable.fromWeb(up.body).on('error', () => res.destroy()).pipe(res); else res.end();