Fix truncated responses from compressed upstreams
build-container / build (push) Successful in 2m21s

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 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-20 14:41:14 -04:00
1 parent 4227883a29
commit 96fb6d807c
1 file changed
+5 -2
+5 -2
View File
@@ -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();