All files / src/lib read-json-with-limit.ts

100% Statements 20/20
100% Branches 6/6
100% Functions 1/1
100% Lines 19/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32              35x 1x   34x 34x 34x 34x 77x 77x 45x 45x 2x 2x   43x   32x 32x 32x 33x 33x   32x    
export class BodyTooLargeError extends Error {}
 
// Reads req.body with a byte budget (App Router has no bodyParser.sizeLimit;
// Content-Length is absent under chunked transfer — spec F17). Cancels the
// stream the moment the budget is exceeded, then parses the buffered bytes.
// Throws BodyTooLargeError (caller → 413) or SyntaxError (caller → 400).
export async function readJsonWithLimit(req: Request, maxBytes: number): Promise<unknown> {
  if (req.body === null) {
    return JSON.parse(""); // throws SyntaxError, same as any empty body
  }
  const reader = req.body.getReader();
  const chunks: Uint8Array[] = [];
  let total = 0;
  for (;;) {
    const { done, value } = await reader.read();
    if (done) break;
    total += value.byteLength;
    if (total > maxBytes) {
      await reader.cancel();
      throw new BodyTooLargeError(`body exceeds ${maxBytes} bytes`);
    }
    chunks.push(value);
  }
  const buffer = new Uint8Array(total);
  let offset = 0;
  for (const chunk of chunks) {
    buffer.set(chunk, offset);
    offset += chunk.byteLength;
  }
  return JSON.parse(new TextDecoder().decode(buffer));
}