mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
69 lines
2.0 KiB
JavaScript
69 lines
2.0 KiB
JavaScript
export {
|
|
readResponseTextCapped,
|
|
readResponseJsonCapped,
|
|
} from '../../../src/sources/httpBody.js';
|
|
|
|
/**
|
|
* Return the existing promise for a cache key, or create one and remove it
|
|
* only when that exact promise settles.
|
|
*/
|
|
export function coalesceProxyRequest(inFlight, key, create) {
|
|
const existing = inFlight.get(key);
|
|
if (existing) return { promise: existing, shared: true };
|
|
let promise;
|
|
promise = Promise.resolve()
|
|
.then(create)
|
|
.finally(() => {
|
|
if (inFlight.get(key) === promise) inFlight.delete(key);
|
|
});
|
|
inFlight.set(key, promise);
|
|
return { promise, shared: false };
|
|
}
|
|
|
|
/**
|
|
* Read a fetch Response body as text while enforcing a hard byte cap during
|
|
* the read — so a malicious or buggy upstream that streams an unbounded body
|
|
* (no/oversized Content-Length, chunked) can't OOM the proxy. Returns
|
|
* { tooLarge, text }. Cancels the stream as soon as the cap is crossed.
|
|
* @param {Response} upstream - fetch() response.
|
|
* @param {number} maxBytes - hard ceiling on decoded bytes.
|
|
* @returns {Promise<{tooLarge: boolean, text: string}>}
|
|
*/
|
|
export async function readCappedResponseText(upstream, maxBytes) {
|
|
const declared = Number(upstream.headers.get('content-length'));
|
|
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
try {
|
|
await upstream.body?.cancel();
|
|
} catch {
|
|
/* no-op */
|
|
}
|
|
return { tooLarge: true, text: '' };
|
|
}
|
|
if (
|
|
!upstream.body ||
|
|
typeof upstream.body[Symbol.asyncIterator] !== 'function'
|
|
) {
|
|
const text = await upstream.text();
|
|
return text.length > maxBytes
|
|
? { tooLarge: true, text: '' }
|
|
: { tooLarge: false, text };
|
|
}
|
|
const decoder = new TextDecoder();
|
|
let text = '';
|
|
let total = 0;
|
|
for await (const chunk of upstream.body) {
|
|
total += chunk.length;
|
|
if (total > maxBytes) {
|
|
try {
|
|
await upstream.body.cancel();
|
|
} catch {
|
|
/* no-op */
|
|
}
|
|
return { tooLarge: true, text: '' };
|
|
}
|
|
text += decoder.decode(chunk, { stream: true });
|
|
}
|
|
text += decoder.decode();
|
|
return { tooLarge: false, text };
|
|
}
|