Skip to content

refactor(ffi): Slice E — collapse channel-backed pumps now that BodyReader: http_body::Body #187

Description

@momics

Summary

Slice E of #182. Now that BodyReader: http_body::Body (6fb9c1b) and http::serve / http::fetch use Body directly (Slices C, D), the bespoke pump tasks that bridge channel-backed bodies into hyper become deletable. This slice removes the redundant pumps and lets BodyReader flow through Body::new directly into hyper's request/response.

This is the cleanup that turns "FFI plumbing exists alongside HTTP plumbing" into "FFI plumbing wraps HTTP plumbing".

Evidence

  • crates/iroh-http-core/src/stream.rs:600-997 defines pump_quic_recv_to_body, pump_body_to_quic_send, pump_duplex, plus pump_hyper_body_to_channel / pump_hyper_body_to_channel_limited in client.rs.
  • After Slice C, hyper polls BodyReader directly via its http_body::Body impl on the serve path — pump_hyper_body_to_channel becomes redundant on that path.
  • After Slice D, the same applies to pump_hyper_body_to_channel_limited on the fetch path.
  • The remaining legitimate uses (Session uni/bidi streams that pump raw QUIC bytes through user-visible BodyReader/BodyWriter handles) stay — they are part of the FFI session API contract, not redundant.

Remediation

  1. Audit each pump function's call sites after Slices C and D have landed:
    • pump_hyper_body_to_channel / pump_hyper_body_to_channel_limited: expected to be deletable. Hyper now polls BodyReader directly via http_body::Body.
    • pump_quic_recv_to_body / pump_body_to_quic_send: still needed for Session::create_uni_stream / Session::next_uni_stream / Session::create_bidi_stream etc., where the FFI surface gives JS a BodyReader/BodyWriter handle directly.
    • pump_duplex: dead — raw_connect was dropped (8754da4), no other callers.
  2. Delete the redundant pumps. Keep the ones with legitimate session-API call sites.
  3. Where pumps remain, ensure they live in ffi/pumps.rs (after Slice A) — they are FFI plumbing, not HTTP plumbing.
  4. Verify BodyReader::poll_frame correctness under hyper's drive: the existing implementation polls a pending future and recreates it on Pending drop. tokio mpsc recv is cancellation-safe; this is correct, but add a regression test that drives BodyReader through hyper end-to-end so the property is locked in.
  5. Backpressure: BodyReader channel capacity (DEFAULT_CHANNEL_CAPACITY = 32) is the only buffer between QUIC and hyper. Confirm no perf regression on large body streaming via the existing benchmarks.

Acceptance criteria

  1. pump_hyper_body_to_channel and pump_hyper_body_to_channel_limited are deleted (or, if any legitimate caller remains, the rationale is documented in a comment that references this slice and epic: clean Rust core — mod http / mod ffi split + dynamic stack (supersedes ADR-014 drift) #182).
  2. pump_duplex is deleted (no callers after raw_connect removal).
  3. Remaining pumps (pump_quic_recv_to_body, pump_body_to_quic_send) live in ffi/pumps.rs with call sites only in mod ffi (Session API).
  4. End-to-end test: a 10 MiB body streamed through http::servehttp::fetch round-trips correctly with bounded memory (no hidden buffering).
  5. Benchmark suite shows no regression on body throughput vs. pre-slice baseline.
  6. tests/architecture.rs is extended to enforce the canonical root layout end-to-end:
    • The walker covers src/ (not just src/http/).
    • It asserts the only entries directly under crates/iroh-http-core/src/ are lib.rs, endpoint.rs, http/, ffi/ — any other file or folder fails the test.
    • The TEMPORARY_EXCEPTIONS allowlist for the http → ffi import ban is empty. Slices C and D remove the three remaining entries (http/client.rs, http/server/mod.rs, http/session.rs); this slice removes any leftovers and asserts the empty list as a hard invariant.
  7. npm run ci green; 92 interop pairs pass.

Subsumes

Notes

Strictly depends on Slices C and D being merged first. Until then, the call-site analysis is hypothetical.

If during the audit a fourth use case for the pumps surfaces that we missed, surface it in #182 — it may indicate Slices C/D didn't deliver the promised body unification and need follow-up before this slice can land.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priorityapiAPI design / ergonomicsenhancementNew feature or requestrustPull requests that update rust code

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions