astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
52 lines (51 loc) • 1.55 kB
JavaScript
/**
* Shared utility for reading request bodies with a size limit.
* Used by both Actions and Server Islands to enforce `security.actionBodySizeLimit`
* and `security.serverIslandBodySizeLimit` respectively.
*/
/**
* Read the request body as a `Uint8Array`, enforcing a maximum size limit.
* Checks the `Content-Length` header for early rejection, then streams the body
* and tracks bytes received.
*
* @throws {BodySizeLimitError} if the body exceeds the configured limit
*/
export async function readBodyWithLimit(request, limit) {
const contentLengthHeader = request.headers.get("content-length");
if (contentLengthHeader) {
const contentLength = Number.parseInt(contentLengthHeader, 10);
if (Number.isFinite(contentLength) && contentLength > limit) {
throw new BodySizeLimitError(limit);
}
}
if (!request.body) return new Uint8Array();
const reader = request.body.getReader();
const chunks = [];
let received = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (value) {
received += value.byteLength;
if (received > limit) {
throw new BodySizeLimitError(limit);
}
chunks.push(value);
}
}
const buffer = new Uint8Array(received);
let offset = 0;
for (const chunk of chunks) {
buffer.set(chunk, offset);
offset += chunk.byteLength;
}
return buffer;
}
export class BodySizeLimitError extends Error {
limit;
constructor(limit) {
super(`Request body exceeds the configured limit of ${limit} bytes`);
this.name = "BodySizeLimitError";
this.limit = limit;
}
}