service_proxy_* buffers the entire request body — switch to streaming #55

Closed
opened 2026-04-23 12:39:44 +00:00 by zaelgohary · 0 comments
Member

Problem

service_proxy_root and service_proxy_path in crates/hero_router/src/server/routes.rs collect the whole request body with axum::body::to_bytes(body, LIMIT) before forwarding to the backend UDS.

  • Hard ceiling on upload size = LIMIT (currently 16 MB).
  • When the body exceeds LIMIT, .unwrap_or_default() swallows the error and forwards an empty body — the client sees ERR_EMPTY_RESPONSE instead of 413 Payload Too Large.
  • Even within the limit, each concurrent upload pins up to LIMIT bytes of router memory.

Repro

Against any upload endpoint behind hero_router (e.g. hero_foundry WebDAV PUT):

for size in 15 20; do
  dd if=/dev/urandom of=/tmp/f bs=1M count=$size 2>/dev/null
  curl -sS -o /dev/null -w "$size MB: %{http_code}\n" -X PUT --data-binary @/tmp/f \
    http://HOST/hero_foundry/rpc/api/files/CTX/test.bin --max-time 60
done
# 15 MB: 200
# 20 MB: (no response, curl times out)

Fix

Replace to_bytes + buffered forwarding with a streaming pass-through to the backend UDS — forward hyper::Body straight through without materializing it. Removes the ceiling and keeps memory bounded regardless of upload size.

On genuine error, return 413 Payload Too Large explicitly rather than defaulting to an empty body, so the client sees a clear failure.

## Problem `service_proxy_root` and `service_proxy_path` in `crates/hero_router/src/server/routes.rs` collect the whole request body with `axum::body::to_bytes(body, LIMIT)` before forwarding to the backend UDS. - Hard ceiling on upload size = `LIMIT` (currently 16 MB). - When the body exceeds `LIMIT`, `.unwrap_or_default()` swallows the error and forwards an empty body — the client sees `ERR_EMPTY_RESPONSE` instead of `413 Payload Too Large`. - Even within the limit, each concurrent upload pins up to `LIMIT` bytes of router memory. ## Repro Against any upload endpoint behind hero_router (e.g. hero_foundry WebDAV PUT): ```bash for size in 15 20; do dd if=/dev/urandom of=/tmp/f bs=1M count=$size 2>/dev/null curl -sS -o /dev/null -w "$size MB: %{http_code}\n" -X PUT --data-binary @/tmp/f \ http://HOST/hero_foundry/rpc/api/files/CTX/test.bin --max-time 60 done # 15 MB: 200 # 20 MB: (no response, curl times out) ``` ## Fix Replace `to_bytes` + buffered forwarding with a streaming pass-through to the backend UDS — forward `hyper::Body` straight through without materializing it. Removes the ceiling and keeps memory bounded regardless of upload size. On genuine error, return `413 Payload Too Large` explicitly rather than defaulting to an empty body, so the client sees a clear failure.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_router#55
No description provided.