Skip to content

fleet-proxy(http): response reader caps every line but nothing caps repetition — endless 1xx heads, header lines, or trailer lines hang an exchange (and its pooled tunnel) forever #6509

Open

Description

@dezren39

Problem

fleet-proxy's HTTP response reader (pkgs/fleet/crates/fleet-proxy/src/http.rs) bounds every unit a peer can send — one line is capped at MAX_LINE_BYTES (:52, enforced in read_line_bounded :143), a declared body is capped at MAX_RESPONSE_BODY_BYTES before allocation — but nothing bounds repetition. Three loops consume peer-controlled units forever:

  1. Interim 1xx heads — request() (:215) loops read_response_head() and continues on every 1xx (except 101) with no count limit.
  2. Header lines — read_response_head() (:282, loop at :305) reads header lines until a blank line with no line-count limit.
  3. Chunked trailer lines — read_chunked() (:355, trailer loop :369) reads trailer lines until a blank line with no line-count limit.

A laptop service that is stuck, buggy, or hostile can therefore hang one broker exchange indefinitely: every unit arrives promptly, so the tunnel's 660 s per-read timeout (tunnel.rs TUNNEL_READ_TIMEOUT, applied per read syscall) never fires — each successful read starts a fresh window. The exchange holds its pooled tunnel (per-port pool, serve.rs) and broker thread the whole time; repeated requests to the same misbehaving service can pin the whole pool (default 50) one exchange at a time, with no error ever surfaced.

This is the one peer-trust gap left in a module whose stated doctrine (#5579, module doc :16-27) is that peer-declared sizes are never trusted: sizes are capped, counts are not.

Evidence (verified this run)

Probe ~/git/fleet/probe-proxy-http on the laptop (real fleet-proxy crate via path dependency, http.rs byte-identical at laptop HEAD and origin/main 85c435e; loopback fake peer, HttpConn::request on a thread with a timed wait):

  • Control — peer sends one 100 Continue head then 200 OK with Content-Length: 2: RETURNED status=200 body_len=2 in ~202µs.
  • flood1xx — peer streams HTTP/1.1 100 Continue\r\n\r\n heads at 1 ms intervals: STILL BLOCKED after 4s (would run to the peer's 200,000-head budget and beyond).
  • floodhdr — peer sends HTTP/1.1 200 OK\r\n then streams X-Fill: y\r\n header lines: STILL BLOCKED after 4s.
  • floodtrailer — peer sends a chunked head + 0\r\n then streams trailer lines: STILL BLOCKED after 4s.

Dedup: #5579 (closed) capped declared sizes; #5921 (closed) made 1xx interim heads consumed rather than returned — it introduced loop 1 without a bound. No open issue covers repetition/count bounds in this reader (searched: "fleet-proxy 1xx", "interim response unbounded", "http.rs trailer").

Why it matters

The broker is the fleet's single transport chokepoint to laptop services. A hang here is silent and unbounded — not a slow error but a permanently pinned tunnel and thread per exchange — and the trigger is exactly the peer this module already treats as untrusted for sizes. The failure mode also defeats the pool's bounded-wait design: slots are never returned, discarded, or timed out.

Acceptance criteria

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 6, 2026
  2. developing-today commented on Nov 6, 2026

    @developing-today
    Contributor
  3. added
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/fleetpkgs/fleet multicall binary + platform crates
    on Nov 6, 2026
  4. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  5. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 6, 2026
  6. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    Lane Q (code-q) claimed task 11023 for issue #6509. Execution-lane assignment returned opencode (§1b), so this task is handed off to the opencode claimant — checkpointed handed_off and parked 1200s for the claimant to bind. Attempts 1/4.

  7. 21 remaining items

  8. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. added
    queue/claimedQueue worker lifecycle state
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    queue/claimedQueue worker lifecycle state
    on Nov 6, 2026
  10. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · design-architect pass 62 — adopted as Phase 2 of design #6582

  11. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  12. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/fleetpkgs/fleet multicall binary + platform crateskind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobsource/design-architectFiled by the repo design architect jobstatus/parkedDeliberately paused with a recorded resume conditiontask/triageQueue packet kind: verify, reproduce, and route this itemwork/assignedQueue worker lifecycle state

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions