refactor: dedupe media and request-body test scaffolding

This commit is contained in:
Peter Steinberger
2026-02-22 18:36:54 +00:00
parent 4a88c579ba
commit 0e4f3ccbdf
6 changed files with 93 additions and 56 deletions

View File

@@ -113,15 +113,29 @@ describe("http body limits", () => {
expect(req.__unhandledDestroyError).toBeUndefined();
});
it("timeout surfaces typed error", async () => {
it("timeout surfaces typed error when timeoutMs is clamped", async () => {
const req = createMockRequest({ emitEnd: false });
const promise = readRequestBodyWithLimit(req, { maxBytes: 128, timeoutMs: 10 });
const promise = readRequestBodyWithLimit(req, { maxBytes: 128, timeoutMs: 0 });
await expect(promise).rejects.toSatisfy((error: unknown) =>
isRequestBodyLimitError(error, "REQUEST_BODY_TIMEOUT"),
);
expect(req.__unhandledDestroyError).toBeUndefined();
});
it("guard clamps invalid maxBytes to one byte", async () => {
const req = createMockRequest({ chunks: ["ab"], emitEnd: false });
const res = createMockServerResponse();
const guard = installRequestBodyLimitGuard(req, res, {
maxBytes: Number.NaN,
responseFormat: "text",
});
await waitForMicrotaskTurn();
expect(guard.isTripped()).toBe(true);
expect(guard.code()).toBe("PAYLOAD_TOO_LARGE");
expect(res.statusCode).toBe(413);
expect(req.__unhandledDestroyError).toBeUndefined();
});
it("declared oversized content-length does not emit unhandled error", async () => {
const req = createMockRequest({
headers: { "content-length": "9999" },

View File

@@ -79,10 +79,15 @@ export type ReadRequestBodyOptions = {
encoding?: BufferEncoding;
};
export async function readRequestBodyWithLimit(
req: IncomingMessage,
options: ReadRequestBodyOptions,
): Promise<string> {
type RequestBodyLimitValues = {
maxBytes: number;
timeoutMs: number;
};
function resolveRequestBodyLimitValues(options: {
maxBytes: number;
timeoutMs?: number;
}): RequestBodyLimitValues {
const maxBytes = Number.isFinite(options.maxBytes)
? Math.max(1, Math.floor(options.maxBytes))
: 1;
@@ -90,6 +95,14 @@ export async function readRequestBodyWithLimit(
typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs)
? Math.max(1, Math.floor(options.timeoutMs))
: DEFAULT_WEBHOOK_BODY_TIMEOUT_MS;
return { maxBytes, timeoutMs };
}
export async function readRequestBodyWithLimit(
req: IncomingMessage,
options: ReadRequestBodyOptions,
): Promise<string> {
const { maxBytes, timeoutMs } = resolveRequestBodyLimitValues(options);
const encoding = options.encoding ?? "utf-8";
const declaredLength = parseContentLengthHeader(req);
@@ -241,13 +254,7 @@ export function installRequestBodyLimitGuard(
res: ServerResponse,
options: RequestBodyLimitGuardOptions,
): RequestBodyLimitGuard {
const maxBytes = Number.isFinite(options.maxBytes)
? Math.max(1, Math.floor(options.maxBytes))
: 1;
const timeoutMs =
typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs)
? Math.max(1, Math.floor(options.timeoutMs))
: DEFAULT_WEBHOOK_BODY_TIMEOUT_MS;
const { maxBytes, timeoutMs } = resolveRequestBodyLimitValues(options);
const responseFormat = options.responseFormat ?? "json";
const customText = options.responseText ?? {};