mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 16:35:27 +08:00
Node fetch auto-decompresses upstream responses, but proxy_go.js was forwarding the original content-encoding header (e.g. br/gzip) to clients. Clients then tried to decompress already-decompressed data and failed. Filter out content-encoding alongside content-length.
107 lines
2.4 KiB
JavaScript
107 lines
2.4 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
buildInternalGoURL,
|
|
buildInternalGoHeaders,
|
|
isAbortError,
|
|
} = require('./http_internal');
|
|
|
|
async function proxyToGo(req, res, rawBody) {
|
|
const url = buildInternalGoURL(req);
|
|
const controller = new AbortController();
|
|
let clientClosed = false;
|
|
const markClientClosed = () => {
|
|
if (clientClosed) {
|
|
return;
|
|
}
|
|
clientClosed = true;
|
|
controller.abort();
|
|
};
|
|
const onReqAborted = () => markClientClosed();
|
|
const onResClose = () => {
|
|
if (!res.writableEnded) {
|
|
markClientClosed();
|
|
}
|
|
};
|
|
req.on('aborted', onReqAborted);
|
|
res.on('close', onResClose);
|
|
|
|
try {
|
|
let upstream;
|
|
try {
|
|
upstream = await fetch(url.toString(), {
|
|
method: 'POST',
|
|
headers: buildInternalGoHeaders(req, { withContentType: true }),
|
|
body: rawBody,
|
|
signal: controller.signal,
|
|
});
|
|
} catch (err) {
|
|
if (clientClosed || isAbortError(err)) {
|
|
if (!res.writableEnded) {
|
|
res.end();
|
|
}
|
|
return;
|
|
}
|
|
throw err;
|
|
}
|
|
if (clientClosed) {
|
|
if (!res.writableEnded) {
|
|
res.end();
|
|
}
|
|
return;
|
|
}
|
|
|
|
res.statusCode = upstream.status;
|
|
upstream.headers.forEach((value, key) => {
|
|
const lower = key.toLowerCase();
|
|
if (lower === 'content-length' || lower === 'content-encoding') {
|
|
return;
|
|
}
|
|
res.setHeader(key, value);
|
|
});
|
|
|
|
if (!upstream.body || typeof upstream.body.getReader !== 'function') {
|
|
const bytes = Buffer.from(await upstream.arrayBuffer());
|
|
res.end(bytes);
|
|
return;
|
|
}
|
|
|
|
const reader = upstream.body.getReader();
|
|
try {
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
if (clientClosed) {
|
|
break;
|
|
}
|
|
const { value, done } = await reader.read();
|
|
if (done) {
|
|
break;
|
|
}
|
|
if (value && value.length > 0) {
|
|
res.write(Buffer.from(value));
|
|
if (typeof res.flush === 'function') {
|
|
res.flush();
|
|
}
|
|
}
|
|
}
|
|
if (!res.writableEnded) {
|
|
res.end();
|
|
}
|
|
} catch (err) {
|
|
if (!isAbortError(err) && !res.writableEnded) {
|
|
res.end();
|
|
}
|
|
}
|
|
} finally {
|
|
req.removeListener('aborted', onReqAborted);
|
|
res.removeListener('close', onResClose);
|
|
if (!res.writableEnded) {
|
|
res.end();
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
proxyToGo,
|
|
};
|