mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 11:09:34 +00:00
50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
export class RequestBodyTooLargeError extends Error {
|
|
constructor() {
|
|
super("Request body exceeds the allowed size");
|
|
}
|
|
}
|
|
|
|
function declaredContentLength(request: Request): number | null {
|
|
const value = request.headers.get("content-length");
|
|
if (!value || !/^\d+$/.test(value)) return null;
|
|
const length = Number(value);
|
|
return Number.isSafeInteger(length) ? length : null;
|
|
}
|
|
|
|
/**
|
|
* Parse multipart data only after constraining the complete wire body. This
|
|
* bounds chunked requests too, where Content-Length is unavailable or false.
|
|
*/
|
|
export async function parseFormDataWithinLimit(request: Request, maxBytes: number): Promise<FormData> {
|
|
const declared = declaredContentLength(request);
|
|
if (declared !== null && declared > maxBytes) {
|
|
throw new RequestBodyTooLargeError();
|
|
}
|
|
|
|
const reader = request.body?.getReader();
|
|
if (!reader) return request.formData();
|
|
|
|
const chunks: BlobPart[] = [];
|
|
let size = 0;
|
|
try {
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) break;
|
|
if (size + value.byteLength > maxBytes) {
|
|
await reader.cancel().catch(() => {});
|
|
throw new RequestBodyTooLargeError();
|
|
}
|
|
size += value.byteLength;
|
|
const chunk = new Uint8Array(value.byteLength);
|
|
chunk.set(value);
|
|
chunks.push(chunk);
|
|
}
|
|
} finally {
|
|
reader.releaseLock();
|
|
}
|
|
|
|
const contentType = request.headers.get("content-type");
|
|
const headers = contentType ? { "content-type": contentType } : undefined;
|
|
return new Response(new Blob(chunks), { headers }).formData();
|
|
}
|