mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-18 12:31:36 +00:00
* test: bound npm fixture upstream responses * test: auto-clean npm fixture temp dirs * style: format npm fixture assertion test * test: simplify plugin fixture temp cleanup
73 lines
2.1 KiB
JavaScript
73 lines
2.1 KiB
JavaScript
// Bounded response body reader used by E2E HTTP fixture clients.
|
|
function bodyTooLargeError(label, byteLimit) {
|
|
return Object.assign(new Error(`${label} response body exceeded ${byteLimit} bytes`), {
|
|
code: "ETOOBIG",
|
|
});
|
|
}
|
|
|
|
function cancelReaderSoon(reader) {
|
|
void Promise.resolve()
|
|
.then(() => reader.cancel())
|
|
.catch(() => {});
|
|
}
|
|
|
|
function parseContentLengthHeader(headers) {
|
|
const raw = headers.get("content-length");
|
|
if (!raw || !/^\d+$/u.test(raw)) {
|
|
return undefined;
|
|
}
|
|
const parsed = Number(raw);
|
|
return Number.isSafeInteger(parsed) ? parsed : Number.POSITIVE_INFINITY;
|
|
}
|
|
|
|
export async function readBoundedResponseBytes(response, label, byteLimit, timeoutPromise) {
|
|
const contentLength = parseContentLengthHeader(response.headers);
|
|
if (contentLength !== undefined && contentLength > byteLimit) {
|
|
await response.body?.cancel().catch(() => {});
|
|
throw bodyTooLargeError(label, byteLimit);
|
|
}
|
|
if (!response.body) {
|
|
return Buffer.alloc(0);
|
|
}
|
|
|
|
const reader = response.body.getReader();
|
|
const chunks = [];
|
|
let byteCount = 0;
|
|
let canceled = false;
|
|
try {
|
|
while (true) {
|
|
const read = reader.read();
|
|
const readWithTimeout = timeoutPromise
|
|
? Promise.race([
|
|
read,
|
|
timeoutPromise.catch((error) => {
|
|
canceled = true;
|
|
cancelReaderSoon(reader);
|
|
throw error;
|
|
}),
|
|
])
|
|
: read;
|
|
const { done, value } = await readWithTimeout;
|
|
if (done) {
|
|
return Buffer.concat(chunks, byteCount);
|
|
}
|
|
byteCount += value.byteLength;
|
|
if (byteCount > byteLimit) {
|
|
canceled = true;
|
|
await reader.cancel().catch(() => {});
|
|
throw bodyTooLargeError(label, byteLimit);
|
|
}
|
|
chunks.push(Buffer.from(value));
|
|
}
|
|
} finally {
|
|
if (!canceled) {
|
|
reader.releaseLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function readBoundedResponseText(response, label, byteLimit, timeoutPromise) {
|
|
const bytes = await readBoundedResponseBytes(response, label, byteLimit, timeoutPromise);
|
|
return new TextDecoder().decode(bytes);
|
|
}
|