testing/cross_backend/body_size.ts

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.

view source

Declarations
#

2 declarations

BodySizeCrossTestOptions
#

testing/cross_backend/body_size.ts view source

RpcPathCrossSuiteOptions import type {BodySizeCrossTestOptions} from '@fuzdev/fuz_app/testing/cross_backend/body_size.js';

Options for the body-size parity suite — the standard RPC-dispatched cross-suite shape (setup_test / capabilities / rpc_path); aliases the shared RpcPathCrossSuiteOptions rather than minting a duplicate.

rpc_path?

RPC endpoint path the methods are mounted on. Default /api/rpc.

type string

readonly

setup_test

Per-test fixture-producing function (fresh keeper + db per call).

type (): Promise<TestFixtureBase>

readonly
returns Promise<TestFixtureBase>

capabilities

Backend capability declarations — each suite gates on its own flag.

type BackendCapabilities

readonly

describe_body_size_cross_tests
#

Depends on
#