Skip to content

Read the request body after the source and key checks, with the gateway's 256 MiB as the only limit, v0.64.1 - #296

Merged
fylorn merged 2 commits into
mainfrom
fix/gateway-body-limit
Oct 8, 2026
Merged

fylorn merged 2 commits into
mainfrom
fix/gateway-body-limit

Conversation

@fylorn

@fylorn fylorn commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #295.

What was wrong

passthrough took the body with axum's Bytes extractor, which applies DefaultBodyLimit (2 MB). Any request over 2,097,152 bytes was answered 413 Failed to buffer the request body during extraction, so the pipeline's 256 MiB check was unreachable, the error was not in the client's format, and nothing was recorded. A session with a few inline screenshots could no longer be compacted.

The extractor also buffered the whole body before the handler ran, i.e. before the source-address and key checks.

Change

  • passthrough takes axum::body::Body unread. The body is read in server::intake::read only after the source check, key check and POST check pass.
  • read counts the bytes actually received (http_body_util::Limited); this is the only size limit in the gateway (256 MiB, unchanged).
  • A Content-Length already over the limit is refused without reading. The message says the length is declared, since the client wrote it. Understating the length does not lift the limit: hyper frames the body by the declared length, and Limited still counts.
  • New Source::TooLarge: 413, slug request (request_too_large in Anthropic format).
  • forward::check_body_size and the pipeline's check are removed. gw.request.body_too_large is replaced by gw.request.body_declared_too_large, gw.request.body_over_limit and gw.request.body_unreadable (the old one's sentence and arguments changed).

Tests

  • tests/body_size.rs: a 3 MiB request reaches the upstream; a wrong key with a 100 MiB declared length gets 401 without the body being sent; a 300 MiB declared length gets 413 in Anthropic format without the body being sent or forwarded.
  • server::intake unit tests: at the limit, over the limit without a length, declared over the limit (body never read), declared length understating the body.

🤖 Generated with Claude Code

fylorn and others added 2 commits October 8, 2026 10:07
…ay's 256 MiB as the only limit

The body was taken by axum's `Bytes` extractor, which carries a 2 MB default
limit: a conversation holding a few inline screenshots was refused with 413
before reaching the gateway's own 256 MiB check, compaction requests included,
and nothing was recorded. The extractor also buffered the whole body before the
source and key checks ran.

`passthrough` now takes the body unread and reads it once those checks and the
POST check pass, counting the bytes actually received. A Content-Length already
over the limit is refused without reading. Oversized requests get 413 in the
client's own error format (`request_too_large` for Anthropic).

Fixes #295

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fylorn fylorn changed the title Read the request body after the source and key checks, with the gateway's 256 MiB as the only limit Read the request body after the source and key checks, with the gateway's 256 MiB as the only limit, v0.64.1 Oct 8, 2026
@fylorn
fylorn merged commit 1ddda16 into main Oct 8, 2026
5 checks passed
@fylorn
fylorn deleted the fix/gateway-body-limit branch October 8, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Requests over 2 MiB are rejected with 413, though the gateway intends a 256 MiB limit

1 participant