// Byte-capped body readers: never buffer more than a caller-set limit from a // peer or remote API. // A fetch Response body as a Buffer, refusing more than maxBytes: by declared // Content-Length first, then by running count, so a lying or chunked response is // cut off (leaving the for-await cancels the stream) rather than buffered. const readCappedResponse = async (res, maxBytes) => { const declared = Number(res.headers.get("content-length")); if (Number.isFinite(declared) && declared > maxBytes) { throw new Error(`response too large (${declared} bytes exceeds ${maxBytes})`); } if (!res.body) { return Buffer.alloc(0); } const chunks = []; let total = 0; for await (const chunk of res.body) { total += chunk.length; if (total > maxBytes) { throw new Error(`response too large (exceeds ${maxBytes} bytes)`); } chunks.push(Buffer.from(chunk)); } return Buffer.concat(chunks); }; // An incoming request stream as a Buffer, or null once it exceeds maxBytes. // Leaving the for-await early destroys the stream, so an oversized upload is cut // off rather than buffered. const readCappedRequest = async (req, maxBytes) => { const chunks = []; let total = 0; for await (const chunk of req) { const buf = typeof chunk === "string" ? Buffer.from(chunk) : chunk; total += buf.length; if (total > maxBytes) { return null; } chunks.push(buf); } return Buffer.concat(chunks); }; module.exports = { readCappedResponse, readCappedRequest };