cappedBytes

tcmts.atproto.cappedBytes · #ldjf5ah2 · term · runs anywhere

A response's body, read only up to max bytes: one that says it's longer, or turns out to be, is refused (an answer from a server someone else names can't take all the memory there is).

import { Refused } from "#codebase/tcmts/atproto";

export async function cappedBytes(res: Response, max: number, what: string): Promise<Uint8Array> {
  const said = Number(res.headers.get("content-length") ?? Number.NaN);
  const tooBig = () => new Refused(`${what} answered with more than ${Math.round(max / 1024)} KB`);
  if (said > max) {
    await res.body?.cancel();
    throw tooBig();
  }
  const chunks: Uint8Array[] = [];
  let size = 0;
  const reader = res.body?.getReader();
  for (;;) {
    const r = reader ? await reader.read() : { done: true as const, value: undefined };
    if (r.done) break;
    size += r.value.length;
    if (size > max) {
      await reader!.cancel();
      throw tooBig();
    }
    chunks.push(r.value);
  }
  const out = new Uint8Array(size);
  let at = 0;
  for (const c of chunks) {
    out.set(c, at);
    at += c.length;
  }
  return out;
}

uses

used by