Skip to content

feat(net): response-body bounds — stall timeout + buffered size cap (ADR-0034 Am#13)#125

Merged
NotAProfDev merged 10 commits into
mainfrom
worktree-feat+net-response-body-bounds
Jul 10, 2026
Merged

feat(net): response-body bounds — stall timeout + buffered size cap (ADR-0034 Am#13)#125
NotAProfDev merged 10 commits into
mainfrom
worktree-feat+net-response-body-bounds

Conversation

@NotAProfDev

@NotAProfDev NotAProfDev commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Closes #124.

Bounds a misbehaving venue HTTP response body on two independent axes, landing ADR-0034 Amendment #13 (un-defers Am#6's TimeoutBody; wires §2's size guard). Implements the Tier-2 "Streaming stall TimeoutBody" item (#102) plus the untracked N1 buffered-cap straggler.

What

1. Streaming stall timeout — a per-frame inactivity deadline for streaming bodies via the runtime-neutral Timer seam. TimeoutBody<B,T> + StallTimeoutLayer<T> wrap the response body and yield HttpError::Timeout if no frame arrives within HttpConfig.body_stall_timeout. The layer is composed innermost in stack() so Guarded (the permit-carrying wrapper) ends up outside TimeoutBody — a stall therefore releases the concurrency permit instead of wedging it. Inert on buffered bodies and when None.

2. Buffered size capLimitedBody<B>, a typed max-bytes wrapper (yields HttpError::BodyTooLarge once cumulative DATA bytes exceed the cap; clamps size_hint), applied in the hyper leaf's BufferMode::Buffer arm via ConnConfig.max_response_bytes. Two layers: an upfront size_hint().upper() fast-fail for an honest Content-Length, plus the LimitedBody mid-collect wrapper for unsized/chunked bodies. Overflow is the new non-retryable, breaker-neutral HttpError::BodyTooLarge / ErrorKind::BodyTooLarge (error_kind="body_too_large").

Breaking (pre-release)

  • Timer gains an associated type Sleep: Future<Output=()> + Send (was -> impl Future), so body wrappers store the sleep future inline without boxing. All impls updated (TokioTimer, MockTimer, FixedTimer).
  • HttpConfig gains body_stall_timeout: Option<Duration>; ConnConfig gains max_response_bytes: Option<usize> (both new required fields). body_stall_timeout is validate_config-rejected when Some(ZERO).
  • HttpError / ErrorKind gain a BodyTooLarge variant.

Tests & verification

  • TDD throughout: stall fires / per-frame reset / None-inert / transparency / permit-release (the crux); LimitedBody under/at/over cap, both size_hint-clamp branches, trailers-don't-count; leaf cap on honest Content-Length (fast-fail) and raw-TCP chunked (mid-collect); a pinning test that BodyTooLarge classifies breaker-Ignored.
  • just ci green (fmt, clippy -D warnings, 244 tests + doctests, doc, deny, typos, machete, gitleaks, actionlint, shellcheck).

Design: docs/superpowers/specs/2026-07-10-net-http-response-body-bounds-design.md · Plan: docs/superpowers/plans/2026-07-10-net-http-response-body-bounds.md · CHANGELOG [Unreleased] updated.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added configurable inactivity timeouts for streaming HTTP response bodies.
    • Added configurable maximum sizes for buffered response bodies.
  • Bug Fixes
    • Stalled response bodies now fail with a timeout instead of remaining stuck indefinitely.
    • Oversized buffered responses are rejected before excessive memory use.
    • Oversized-body errors are non-retryable and reported with a stable error classification.
  • Documentation
    • Updated HTTP configuration guidance and architecture documentation for response-body safety limits.

NotAProfDev and others added 10 commits July 10, 2026 08:10
Adds HttpConfig.body_stall_timeout (validated non-zero-when-Some via
BuildError::ZeroDuration) and composes StallTimeoutLayer innermost in
stack()'s LayerBuilder chain, just outside SetHeaders/Auth. This puts
Guarded outside TimeoutBody so a mid-transfer body stall releases the
concurrency permit instead of pinning it (ADR-0034 Amendment #13).

Breaking: HttpConfig gains a new required field; updates the hyper
build() doctest/test helper and the client_with_directives example.
Adds RangeHint (bounded-above-cap and unbounded-upper size_hint
branches) and TrailersOnly (non-DATA frame accounting) test doubles.
Add ConnConfig.max_response_bytes: Option<usize>, threaded through
HyperLeaf, and apply it only to the BufferMode::Buffer arm of
HyperLeaf::call. Two-layer cap: an upfront fast-fail when the
response's honest Content-Length (size_hint().upper()) already
exceeds the cap, then wrap the incoming body in LimitedBody before
collect() so an unsized/chunked body is caught mid-collect. None
stays unbounded (current behavior); overflow surfaces as
HttpError::BodyTooLarge. Streaming responses are untouched (the
stall timeout already covers those).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records the streaming stall-timeout (StallTimeoutLayer/TimeoutBody) and
buffered size-cap (LimitedBody/ConnConfig::max_response_bytes) work
(Tasks 1-6 on this branch) as ADR-0034 Amendment #13, un-deferring
Amendment #6's TimeoutBody and wiring Section 2's size guard. Adds the
matching Unreleased CHANGELOG entries (Added + a breaking-change note
under Changed).
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f745e9d8-35ea-47db-ba8e-4882fe60a409

📥 Commits

Reviewing files that changed from the base of the PR and between b6655be and a92e294.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (20)
  • CHANGELOG.md
  • crates/adapter/net/api/src/error_kind.rs
  • crates/adapter/net/api/src/timer.rs
  • crates/adapter/net/http/api/src/body.rs
  • crates/adapter/net/http/api/src/circuit_breaker.rs
  • crates/adapter/net/http/api/src/error.rs
  • crates/adapter/net/http/api/src/lib.rs
  • crates/adapter/net/http/api/src/retry.rs
  • crates/adapter/net/http/api/src/stack.rs
  • crates/adapter/net/http/api/src/stall.rs
  • crates/adapter/net/http/api/src/trace.rs
  • crates/adapter/net/http/hyper/Cargo.toml
  • crates/adapter/net/http/hyper/examples/client_with_directives.rs
  • crates/adapter/net/http/hyper/src/build.rs
  • crates/adapter/net/http/hyper/src/leaf.rs
  • crates/adapter/net/http/hyper/src/timer.rs
  • crates/adapter/net/mock/src/timer.rs
  • docs/adr/0034-http-construction-surface-auth-guarded-boot-coverage.md
  • docs/superpowers/plans/2026-07-10-net-http-response-body-bounds.md
  • docs/superpowers/specs/2026-07-10-net-http-response-body-bounds-design.md

📝 Walkthrough

Walkthrough

Adds per-frame streaming stall timeouts and configurable buffered response-size limits. It introduces associated timer sleep types, new body-size errors and classifications, stack configuration, Hyper enforcement, tests, examples, and ADR/changelog documentation.

Changes

Timer and error contracts

Layer / File(s) Summary
Timer and error contracts
crates/adapter/net/api/*, crates/adapter/net/http/api/{error.rs,retry.rs,circuit_breaker.rs,trace.rs}, crates/adapter/net/{http/hyper,mock}/*
Timer now exposes an associated Sleep future type. BodyTooLarge is added across error, tracing, retry, and circuit-breaker classifications.

Streaming stall timeout

Layer / File(s) Summary
Streaming stall timeout
crates/adapter/net/http/api/{stall.rs,lib.rs}
TimeoutBody applies per-frame inactivity deadlines, while StallTimeoutLayer wraps response bodies and preserves body metadata behavior.

Stack configuration and wiring

Layer / File(s) Summary
Stack configuration and wiring
crates/adapter/net/http/api/stack.rs, crates/adapter/net/http/hyper/{src/build.rs,examples/*}
HttpConfig.body_stall_timeout is validated and wired into the resilience stack, with updated examples, helpers, and full-stack timeout tests.

Buffered response-size enforcement

Layer / File(s) Summary
Buffered response-size enforcement
crates/adapter/net/http/api/body.rs, crates/adapter/net/http/hyper/{Cargo.toml,src/leaf.rs,examples/*}
LimitedBody bounds DATA bytes, and HyperLeaf applies ConnConfig.max_response_bytes during buffered collection with fast-fail and streaming overflow checks.

ADR and release documentation

Layer / File(s) Summary
ADR and release documentation
CHANGELOG.md, docs/adr/*, docs/superpowers/{plans,specs}/*
The response-body bounds design, implementation plan, ADR amendment, and unreleased changelog entries are documented.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • NotAProfDev/oath#58: Introduced the shared Timer contract later updated with the associated Sleep type.
  • NotAProfDev/oath#90: Added the Hyper backend whose timer and leaf implementations are extended here.
  • NotAProfDev/oath#92: Added the buffered collection path extended here with response-size enforcement.

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the response-body bounds work.
Linked Issues check ✅ Passed The PR implements all requested safeguards: stall timeout, buffered size cap, Timer::Sleep, ADR docs, and the required error semantics.
Out of Scope Changes check ✅ Passed The changes stay within the response-body bounds scope, with only supporting docs, tests, config, and example updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-feat+net-response-body-bounds

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@NotAProfDev NotAProfDev merged commit 35d5a04 into main Jul 10, 2026
5 checks passed
@NotAProfDev NotAProfDev deleted the worktree-feat+net-response-body-bounds branch July 10, 2026 12:02
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.

net-http: bound a misbehaving response body — streaming stall timeout + buffered size cap

1 participant