fix(gateway): apply the body limit where axum reads it (per-route DefaultBodyLimit) - #267
Merged
Merged
Conversation
…aultBodyLimit) `RequestBodyLimitLayer(70MB)` in main.rs never took effect: the extractor cap is axum-core's DEFAULT_LIMIT (2 MiB) and only axum's own DefaultBodyLimit sets the extension that overrides it. Raise the three gateway routes to 8 MiB, leave the unauthenticated endpoints at the default, and pin both with tests. rant 2026-09-18T09:14:18
Owner
Author
|
Self-review (Committer, Checked before merging:
|
argszero
added a commit
that referenced
this pull request
Sep 21, 2026
Ships the 10 PRs merged since v0.7.25 (#261-#270). No schema change, no config change, so the deployment-side config.toml needs no edit. One fact, one source / display must equal what it consumes (frontend, 6 places) - #261 read the spendable half of the wallet payload when refreshing your own balance; #262 the transactions payload signature covers the time range, with one reload trigger shared by the four controls; #263 the settings controls are either wired or explicitly inert; #265 the re-list outcome comes from the same entry as its action; #268 the sharing form shows a plan's label, not its config id; #269 the ops card stops reading a key's status count as a health verdict. i18n reachability - #266 every pack key must reach a consumer (the gate), and #270 drops the 23 keys that gate proved unreachable: ZH/EN key count 811 -> 788, sunset list 59 -> 36. Gateway - #267 applies the body limit where axum actually reads it (per-route DefaultBodyLimit, 8 MiB on the three gateway routes; unauthenticated endpoints keep the 2 MiB default). This is the application half of rant 2026-09-18T09:14:18. It also corrects the false v0.7.10 "raised to 70MB" CHANGELOG line, which described installing a layer rather than raising a limit. - Cargo.toml / Cargo.lock: 0.7.25 -> 0.7.26. - CHANGELOG.md: v0.7.26 entry plus the v0.7.10 correction. - ui/index.html cache-bust left as-is: this release touches no UI file; the live values are app.js 20260921-2 / i18n.js 20260921-2. cargo test 302 passed; cargo fmt --check clean; clippy -D warnings clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The gateway's long-context support has never actually been in effect.
src/main.rs:239installsRequestBodyLimitLayer::new(70 * 1024 * 1024), andCHANGELOG.md(v0.7.10) records the limit as "raised to 70MB" — but the effective cap has always been axum's built-in 2 MiB (axum-core 0.4.5,DEFAULT_LIMIT = 2_097_152). Every request to/v1/chat/completions,/anthropic/v1/messagesor/v1/responseswhose body exceeds 2 MiB is rejected with413 Failed to buffer the request body: length limit exceededinside the extractor, before the handler runs. For a ~1M-token JSON context (≈3–4 MB) that meant an effective ceiling of roughly a quarter of the intended context, and any base64 image payload over 2 MiB was refused outright.Why the installed layer is inert:
RequestBodyLimitLayer(tower-http) andDefaultBodyLimit(axum) are not the same mechanism. The extractors' limit comes fromaxum_core::extract::Request::with_limited_body(), which only reads theDefaultBodyLimitKindrequest extension — and only axum's ownDefaultBodyLimitwrites that extension. The tower-http layer never does, so the 70 MB number was decorative.Measured against an identical layering (separate throwaway crate, axum 0.7.9,
cargo build --offline), posting raw bodies to the same route shapes:/v1/chat/completions2 MiB/api/auth/login3 MBRequestBodyLimitLayer(70MB)only)DefaultBodyLimit::max(8 MiB))Router+mergeThe last two rows are byte-identical, so the minimal-diff form (
MethodRouter::layer) was chosen on evidence rather than on idiom.The same defect is reproduced inside this crate, not only in the throwaway one: with the route layers reverted and only the new tests applied,
gateway_routes_accept_bodies_past_the_default_limitfails on/v1/chat/completionswith413— the real router, the real extractor, a real 3 MiB body.Related Issue
No issue. Host rant
2026-09-18T09:14:18.500174+08:00— 「【部署/网关】请求体上限实际只有 1MB(prod 公网)/ 2MB(应用),代码里写的 70MB 从未生效」.client_max_body_sizedefaulting to 1 MB foraitokenpool.args.fun) is a host deployment action and is deliberately out of scope here — without it, raising the app limit to 8 MiB still leaves the public endpoint capped at 1 MB.Changes
src/routes/mod.rspub(crate) const GATEWAY_BODY_LIMIT: usize = 8 * 1024 * 1024;with a comment recording whymain.rs's tower-http layer cannot be used for this..layer(DefaultBodyLimit::max(GATEWAY_BODY_LIMIT))./api/auth/*) stay at the 2 MiB default, so an anonymous request cannot make the process buffer 8 MiB.src/gateway.rs: two tests in the existingtestsmodule.gateway_routes_accept_bodies_past_the_default_limit— 3 MiB body on each of the three gateway routes must not be 413, and must reach the handler (it asserts the gateway's own暂无可用 keyresponse for a non-existent model, which proves the body was read and routed).auth_endpoints_stay_at_the_default_limit— negative control:/api/auth/loginwith a 3 MiB body must still be 413.config.example.tomlneeds no counterpart.CHANGELOG.mdis deliberately not touched: onlychore(release)PRs write it (git log -- CHANGELOG.md— the last 12 commits are allchore(release)). The false v0.7.10 entry ("Request body limit raised to 70MB") is a candidate for correction by the next release PR; flagging it here rather than editing it in afixPR.Tests
cargo test— 299 passed / 0 failed on this branch (baselinemaina4cb622= 297; the difference is exactly the 2 tests added here)src/gateway.rsapplied (the route layers reverted)gateway_routes_accept_bodies_past_the_default_limitfails with413on/v1/chat/completionswhileauth_endpoints_stay_at_the_default_limitstill passes; re-applying the route layers turns both greencargo clippy --all-targets— no warnings on this treecargo fmt --check(both edited files verified withrustfmt --check --edition 2021)Checklist
fix/request-body-limit).route(...)lines plus an import, a const and two tests)