Cross-backend parity suite for the request body-size limit.
create_app_server (TS) and the Rust spine both cap the request body at a
1 MiB default (DEFAULT_MAX_BODY_SIZE / fuz_http's
DEFAULT_BODY_LIMIT_BYTES) and reject oversized payloads with 413 and the
canonical flat REST body {error: 'payload_too_large'} — *before* auth,
origin, or dispatch run (middleware step 4). Each impl unit-tests this in
isolation, but nothing fires an oversized POST over the wire, so the
cross-impl agreement on the status + body shape (and on the exact > cap
boundary, not an off-by-one divergence) was unpinned. Three cases:
- over-limit POST (cap + 1 byte) → 413
payload_too_large, refused
before any handler runs (the limit fires ahead of origin verification + the
dispatcher, so an over-cap body is rejected regardless of how well-formed it
is). Exactly one byte over — both impls reject on a strict >, so this is
the tight upper boundary, and staying just over keeps it clear of any
larger framework-default limit that would answer with a different body. - at-limit POST (exactly the cap) → not 413 — one byte under the
rejection threshold passes the size gate and reaches the dispatcher (the
downstream status is irrelevant; only "not size-rejected" is asserted). The
boundary sibling of the case above.
- under-limit POST (small) → 200 — a small, well-formed authenticated
account_verify envelope sails through to a successful handler response,
the positive control that the route works for normal traffic.
Real-socket connection hazard (cross-process only). When the server caps
the body it answers 413 and closes the connection *before* the client
finishes uploading — correct HTTP, since an unread request body can't share a
keep-alive socket. The client's pool can then hand that now-dead socket to
the very next request (observed as other side closed). So every request
here goes through fetch_retrying_once: a request that inherits the poisoned
socket retries onto a fresh connection, which both keeps the suite
deterministic *and* evicts the dead socket so it can't strand a later cross
suite in the same process. In-process (app.request) has no socket, so the
hazard is cross-process-only and the retry never fires there.
Like origin/payload rejection, this is middleware-level flat REST — not the
JSON-RPC envelope the conformance-table runner expects — so it's an
imperative suite, not a conformance_table row. Runs both legs via the
shared {setup_test, capabilities} protocol: the in-process leg
(auth/body_size_parity.db.test.ts, plain gro test) and the cross-process
leg (cross_backend/body_size.cross.test.ts, the TS spine binaries + Rust
testing_spine_stub over real HTTP). The body-size limit is on every spine,
so the suite is ungated.
Cited property: docs/security.md §"Body Size Limiting".
$lib-free by contract (relative specifiers only), like the sibling
cross-backend suites.