Skip to content

Follow-up: unify receiver HTTP body helpers and harden health transitions#1606

Merged
strawgate merged 1 commit into
mainfrom
codex/receiver-http-followup
Apr 8, 2026
Merged

Follow-up: unify receiver HTTP body helpers and harden health transitions#1606
strawgate merged 1 commit into
mainfrom
codex/receiver-http-followup

Conversation

@strawgate
Copy link
Copy Markdown
Owner

@strawgate strawgate commented Apr 8, 2026

Summary

  • add shared HTTP receiver helpers in receiver_http for Content-Length parsing and bounded body reads
  • route OTLP, OTAP, Arrow IPC, and generic HTTP input through the shared helper to remove duplicated logic
  • preallocate body buffers using Content-Length hints (while still enforcing max body size)
  • harden OTAP/Arrow receiver health transitions with atomic CAS loops to avoid load/store races under concurrent request handling

Context

This is a follow-up to the axum receiver migration work to address review feedback and tighten concurrency behavior.

Validation

  • just lint
  • cargo test -p logfwd-io otlp_receiver::tests:: -- --nocapture
  • cargo test -p logfwd-io otap_receiver::tests:: -- --nocapture
  • cargo test -p logfwd-io arrow_ipc_receiver::tests:: -- --nocapture
  • cargo test -p logfwd-io http_input::tests:: -- --nocapture

Note

Unify HTTP body helpers and fix concurrent health state transitions in receivers

  • Extracts shared declared_content_length and read_limited_body helpers into a new receiver_http module, replacing duplicated local implementations in the Arrow IPC, OTAP, OTLP, and HTTP input receivers.
  • read_limited_body accepts an optional content-length hint and returns 413 immediately (before reading any body data) when the declared Content-Length exceeds the configured limit.
  • Fixes a race condition in store_health_event across the Arrow IPC and OTAP receivers by replacing a non-atomic load/store sequence with a compare_exchange_weak CAS loop, preventing lost updates under concurrent modifications.

Macroscope summarized cd86b64.

Copilot AI review requested due to automatic review settings April 8, 2026 13:58
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

Walkthrough

This change extracts common HTTP request-handling utilities into a new shared receiver_http module within the logfwd-io crate. A declared_content_length helper parses the Content-Length header, and a read_limited_body helper reads the HTTP body asynchronously with size constraints. Multiple receiver implementations (Arrow IPC, HTTP input, OTAP, and OTLP) are refactored to import and use these shared helpers instead of maintaining duplicate local implementations. Additionally, health-state updates in some receivers are converted from simple load-then-store operations to atomic compare-exchange loops for concurrent correctness.

Possibly related PRs


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
High-Quality Rust Practices ❌ Error Two pub(crate) functions in receiver_http.rs lack /// documentation comments, violating the requirement for documented public items. Add /// doc comments to declared_content_length and read_limited_body functions explaining their behavior, parameters, and return values.
Formal Verification Coverage ❌ Error PR adds receiver_http.rs module with parser function but fails to update kani-boundary-contract.toml and VERIFICATION.md configuration files required for verification documentation. Add receiver_http.rs entry to kani-boundary-contract.toml with appropriate status and document in VERIFICATION.md with verification approach and proof counts.
Documentation Thoroughly Updated ⚠️ Warning PR adds pub(crate) functions without doc comments and introduces non-obvious concurrency fix undocumented in DEVELOPING.md. Add /// doc comments to declared_content_length and read_limited_body functions. Document the health-transition race condition and compare-and-swap fix in DEVELOPING.md.
✅ Passed checks (2 passed)
Check name Status Explanation
Crate Boundary And Dependency Integrity ✅ Passed PR consolidates HTTP body-reading helpers within logfwd-io using only pre-approved dependencies. No new external dependencies, crates, or boundary violations introduced.
Maintainer Fitness ✅ Passed PR consolidates duplicated HTTP body-handling logic into a shared module and hardens atomic health updates with CAS loops instead of vulnerable load-then-store patterns.

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

@macroscopeapp
Copy link
Copy Markdown

macroscopeapp Bot commented Apr 8, 2026

Approvability

Verdict: Approved

This PR consolidates duplicate HTTP body helper functions into a shared module and hardens atomic health state transitions with proper CAS loops. These are mechanical refactoring and correctness improvements with no new features or significant behavioral changes.

You can customize Macroscope's approvability policy. Learn more.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Follow-up refactor to reduce duplicated HTTP body handling across receivers and to make OTAP/Arrow receiver health updates race-free under concurrent request handling.

Changes:

  • Added receiver_http module with shared Content-Length parsing and bounded body reading (with Content-Length preallocation hints).
  • Routed OTLP, OTAP, Arrow IPC, and generic http_input request body reads through the shared helper.
  • Hardened OTAP and Arrow IPC receiver health transitions using atomic CAS loops to avoid lost updates under concurrency.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/logfwd-io/src/receiver_http.rs New shared helpers for parsing Content-Length and reading bounded request bodies.
crates/logfwd-io/src/otlp_receiver.rs Uses shared HTTP helper to remove local duplicated body logic.
crates/logfwd-io/src/otap_receiver.rs Uses shared HTTP helper; updates receiver health via CAS loop to avoid lost transitions.
crates/logfwd-io/src/arrow_ipc_receiver.rs Uses shared HTTP helper; updates receiver health via CAS loop to avoid lost transitions.
crates/logfwd-io/src/http_input.rs Uses shared HTTP helper to remove local duplicated body logic.
crates/logfwd-io/src/lib.rs Registers the new receiver_http module.

Comment on lines +21 to +26
let mut body = body;
let mut out = Vec::with_capacity(
content_length_hint
.map(|hint| hint.min(max_body_size as u64) as usize)
.unwrap_or_default(),
);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read_limited_body preallocates the output buffer up to min(Content-Length, max_body_size). For receivers with configurable max_body_size (e.g., http_input), a large configured limit plus a large Content-Length can force an immediate large allocation per request, increasing memory pressure for slowloris-style traffic and high concurrency. Consider capping the preallocation to a smaller fixed upper bound (while still enforcing max_body_size during reads), or reserving incrementally as frames arrive rather than allocating the full hinted size up front.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +19
pub(crate) fn declared_content_length(headers: &HeaderMap) -> Option<u64> {
headers
.get(CONTENT_LENGTH)
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse::<u64>().ok())
}

pub(crate) async fn read_limited_body(
body: Body,
max_body_size: usize,
content_length_hint: Option<u64>,
) -> Result<Vec<u8>, StatusCode> {
if content_length_hint.is_some_and(|hint| hint > max_body_size as u64) {
return Err(StatusCode::PAYLOAD_TOO_LARGE);
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New shared helpers declared_content_length / read_limited_body are now a single point of correctness for multiple receivers, but this new module doesn’t have direct unit tests. Adding focused tests (e.g., invalid/absent Content-Length, Content-Length > max triggers 413, streaming body that exceeds max_body_size triggers 413, and non-data frames are skipped) would help prevent regressions across OTLP/OTAP/Arrow/http_input.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/logfwd-io/src/otlp_receiver.rs (1)

373-402: ⚠️ Potential issue | 🟡 Minor

Inconsistent health update pattern vs. other receivers.

PR objective states "harden OTAP/Arrow receiver health transitions using atomic CAS loops." The OTAP and Arrow receivers now use compare_exchange_weak loops in store_health_event, but OTLP receiver still uses plain store(..., Ordering::Relaxed) for health updates.

This creates an inconsistency: under concurrent request handling, OTLP receiver health updates can exhibit the same load/store races that the CAS loops were introduced to prevent in the other receivers.

Consider unifying by either:

  1. Adding a shared store_health_event to receiver_health.rs and using it here, or
  2. Documenting why OTLP doesn't need the same treatment
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/logfwd-io/src/otlp_receiver.rs` around lines 373 - 402, The OTLP
receiver is still using direct atomic store calls (state.health.store(...,
Ordering::Relaxed)) for health transitions inside the send_result match, which
is inconsistent with the CAS-based updates used by OTAP/Arrow; update the OTLP
handling to use the same CAS-loop helper (store_health_event) from
receiver_health.rs (or implement the same compare_exchange_weak loop inline)
when setting ComponentHealth::Healthy, Degraded and Failed, and preserve the
existing is_running check before marking Failed so health updates are performed
via the compare-and-swap loop to avoid load/store races; locate uses in
otlp_receiver.rs around the send_result match and replace each
state.health.store(...) with a call to store_health_event(state,
ComponentHealth::X) (or replicate the identical compare_exchange_weak loop logic
referencing ComponentHealth and state.health) so behavior matches other
receivers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/logfwd-io/src/otlp_receiver.rs`:
- Around line 373-402: The OTLP receiver is still using direct atomic store
calls (state.health.store(..., Ordering::Relaxed)) for health transitions inside
the send_result match, which is inconsistent with the CAS-based updates used by
OTAP/Arrow; update the OTLP handling to use the same CAS-loop helper
(store_health_event) from receiver_health.rs (or implement the same
compare_exchange_weak loop inline) when setting ComponentHealth::Healthy,
Degraded and Failed, and preserve the existing is_running check before marking
Failed so health updates are performed via the compare-and-swap loop to avoid
load/store races; locate uses in otlp_receiver.rs around the send_result match
and replace each state.health.store(...) with a call to
store_health_event(state, ComponentHealth::X) (or replicate the identical
compare_exchange_weak loop logic referencing ComponentHealth and state.health)
so behavior matches other receivers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: c29718c6-c1da-488b-b3ea-b7fe5973bf02

📥 Commits

Reviewing files that changed from the base of the PR and between 77d68da and cd86b64.

📒 Files selected for processing (6)
  • crates/logfwd-io/src/arrow_ipc_receiver.rs
  • crates/logfwd-io/src/http_input.rs
  • crates/logfwd-io/src/lib.rs
  • crates/logfwd-io/src/otap_receiver.rs
  • crates/logfwd-io/src/otlp_receiver.rs
  • crates/logfwd-io/src/receiver_http.rs

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.

2 participants