43 lines
1.3 KiB
JavaScript
43 lines
1.3 KiB
JavaScript
export class RequestBodyTooLargeError extends Error {
|
|
status = 413;
|
|
constructor(max_bytes) {
|
|
super(`Request body exceeds ${max_bytes} bytes`);
|
|
this.name = "RequestBodyTooLargeError";
|
|
}
|
|
}
|
|
/**
|
|
* Reads the whole request body, aborting as soon as it grows past
|
|
* `max_bytes` so oversized (or chunked, length-less) bodies are never fully
|
|
* buffered. Returns `undefined` when the request has no body.
|
|
*/
|
|
export default async function readRequestBody({ req, max_bytes, }) {
|
|
if (req.method == "GET" || req.method == "HEAD" || !req.body) {
|
|
return undefined;
|
|
}
|
|
const content_length = Number(req.headers.get("content-length"));
|
|
if (content_length > max_bytes) {
|
|
throw new RequestBodyTooLargeError(max_bytes);
|
|
}
|
|
const reader = req.body.getReader();
|
|
const chunks = [];
|
|
let total = 0;
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done)
|
|
break;
|
|
total += value.byteLength;
|
|
if (total > max_bytes) {
|
|
await reader.cancel();
|
|
throw new RequestBodyTooLargeError(max_bytes);
|
|
}
|
|
chunks.push(value);
|
|
}
|
|
const body = new Uint8Array(total);
|
|
let offset = 0;
|
|
for (const chunk of chunks) {
|
|
body.set(chunk, offset);
|
|
offset += chunk.byteLength;
|
|
}
|
|
return body;
|
|
}
|