74 lines
3.1 KiB
TypeScript
74 lines
3.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { readLimitedRequestBytes, readLimitedRequestFormData, RequestBodyLimitError } from "./readLimitedRequestBody.server";
|
|
|
|
describe("readLimitedRequestBytes", () => {
|
|
it("reads a bounded request body", async () => {
|
|
const request = new Request("https://app.example.test/upload", { method: "POST", body: new Uint8Array([1, 2, 3]) });
|
|
await expect(readLimitedRequestBytes(request, 3)).resolves.toEqual(new Uint8Array([1, 2, 3]));
|
|
});
|
|
|
|
it("rejects an oversized declared body before buffering", async () => {
|
|
const request = new Request("https://app.example.test/upload", {
|
|
method: "POST",
|
|
headers: { "content-length": "4" },
|
|
body: new Uint8Array([1]),
|
|
});
|
|
await expect(readLimitedRequestBytes(request, 3)).rejects.toBeInstanceOf(RequestBodyLimitError);
|
|
});
|
|
|
|
it("rejects streamed bytes when content-length is absent or understated", async () => {
|
|
for (const headers of [{}, { "content-length": "1" }]) {
|
|
const request = new Request("https://app.example.test/upload", {
|
|
method: "POST",
|
|
headers,
|
|
body: new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue(new Uint8Array([1, 2]));
|
|
controller.enqueue(new Uint8Array([3, 4]));
|
|
controller.close();
|
|
},
|
|
}),
|
|
duplex: "half",
|
|
} as RequestInit & { duplex: "half" });
|
|
await expect(readLimitedRequestBytes(request, 3)).rejects.toBeInstanceOf(RequestBodyLimitError);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("readLimitedRequestFormData", () => {
|
|
it("parses multipart form data within the streamed byte limit", async () => {
|
|
const boundary = "pilot-boundary";
|
|
const body = [
|
|
`--${boundary}\r\nContent-Disposition: form-data; name="csrf"\r\n\r\ncsrf-token\r\n`,
|
|
`--${boundary}\r\nContent-Disposition: form-data; name="message"\r\n\r\nPilot\r\n`,
|
|
`--${boundary}--\r\n`,
|
|
].join("");
|
|
const request = new Request("https://app.example.test/upload", {
|
|
method: "POST",
|
|
headers: { "content-type": `multipart/form-data; boundary=${boundary}` },
|
|
body,
|
|
});
|
|
|
|
const parsed = await readLimitedRequestFormData(request, 1024);
|
|
|
|
expect(parsed.get("csrf")).toBe("csrf-token");
|
|
expect(parsed.get("message")).toBe("Pilot");
|
|
});
|
|
|
|
it.each([undefined, "1"])("rejects actual multipart bytes when content-length is %s", async (contentLength) => {
|
|
const form = new FormData();
|
|
form.set("file", new File(["payload that exceeds the route limit"], "pilot.txt", { type: "text/plain" }));
|
|
const encoded = new Request("https://app.example.test/upload", { method: "POST", body: form });
|
|
const headers = new Headers({ "content-type": encoded.headers.get("content-type") ?? "" });
|
|
if (contentLength) headers.set("content-length", contentLength);
|
|
const request = new Request(encoded.url, {
|
|
method: "POST",
|
|
headers,
|
|
body: encoded.body,
|
|
duplex: "half",
|
|
} as RequestInit & { duplex: "half" });
|
|
|
|
await expect(readLimitedRequestFormData(request, 16)).rejects.toBeInstanceOf(RequestBodyLimitError);
|
|
});
|
|
});
|