Optimize dev proxy upstream performance#896
Conversation
Replace the verbose `cargo run --manifest-path … --target … -- dev proxy` invocations with the installed `ts` binary (via `cargo install-cli`), so the guide reads the same way as the CLI guide. Note that `ts dev proxy` is macOS-only and phrase the install step as "install or update". Make the quick start a complete first run (`ca install`, then run with `--rewrite-host` and `--launch chrome`), and make `--rewrite-host` the recommended default for dev and staging upstreams. The Host-header guidance now turns on whether the upstream accepts `Host: <FROM>` rather than on the upstream being Trusted Server Compute. Correct several stale or wrong examples, verified against the CLI source: - Firefox `certutil` now uses `-d "sql:…"` and the full CA nickname, matching the auto-import the tool performs. - Add the missing `--connect-timeout` option and note that `[COMMAND]` is `ca`. - Prefer `--basic-auth-file` over inline `--basic-auth` in the staging example. - Clarify the CA key is stored outside the repository only by default, and rename "First run: CA setup" to "The development CA".
Keep `--rewrite-host` in the quick start (it is required for upstreams that reject `Host: <FROM>`), but state its trade-off honestly: against a real Trusted Server adapter, first-party URLs then render on the upstream host, not the production domain. Qualify the "first-party URLs always stay on the production domain" claim accordingly — it holds only when the upstream preserves `X-Forwarded-Host`. Also: - Note that Firefox CA auto-import needs `certutil` (`brew install nss`) and qualify the troubleshooting row that assumed it is always present. - State that `--launch` opens only the first mapped hostname while every mapping is still proxied. - Note that connection options (`--rewrite-host`, auth, `--insecure`, `--upstream-plaintext`) apply to every mapping, not per-rule. - Scope the Safari "only while the proxy runs" claim to a clean exit.
prk-Jr
left a comment
There was a problem hiding this comment.
Summary
Adds a bounded, reusable HTTP/1.1 upstream connection manager (plus DNS caching, precomputed upstream identities, and a repeatable benchmark suite) to ts dev proxy. The design is careful and thoroughly tested: the manager is an actor with a bounded ordinary lane + unbounded control lane so lifecycle events (cancel / driver-closed / shutdown) can never deadlock behind a saturated acquire lane, and capacity reconciliation is airtight — every path leads back to release(id) (reservation drop → ConnectFailed, driver-guard drop → DriverClosed, shutdown connector abort → finish error → reservation drop). The AcquireTicket single-terminal-transition invariant closes the resolve/cancel race. No blocking issues found; approving.
Non-blocking
♻️ refactor
- Crypto provider rebuilt per call:
NoVerifier::supported_verify_schemescallsaws_lc_rs::default_provider()(a non-trivial clone) on every invocation — cache in aOnceLock.--insecure-only path, cosmetic. (connect.rs:282)
🌱 seedling
- Non-idempotent 502 on stale reuse: the
send_requestretry is gated on provably-empty idempotent requests, so a POST racing an upstream idle-close returns 502 rather than replaying. This is the correct safe behavior; flagged only so it's a documented trade-off. (upstream/mod.rs:246)
⛏ nitpick
- Doc comments on new
pubitems: several new public items (ProxyMetrics::record_*,PooledResponseBody::new, etc.) lack doc comments. CLAUDE.md asks for one per public item;missing_docsisn't enforced here and it matches surrounding CLI style, so optional.
👍 praise
- Lifecycle & concurrency design: the
can_reusematrix + exhaustive test, DNS miss-coalescing that survives owner cancellation without poisoning the in-flight key, the trailer-frame deferral inPooledResponseBody, and thepriority_shutdown_overtakes_a_saturated_ordinary_lanetest are all excellent. - Security hardening: Basic-auth refused on non-loopback binds, hop-by-hop +
Connection-token stripping,Forwarded/Fastly-SSLstripped and authoritatively re-stamped, strict host validation before PAC / Host-header embedding, and redactedBasicAuthDebug.
CI Status
- fmt: PASS
- clippy (fastly/axum/cloudflare/spin native+wasm): PASS
- rust tests (fastly/axum/cloudflare/spin/CLI/parity): PASS
- js build + vitest + docs/ts prettier: PASS
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Summary
Approved with seven actionable follow-ups noted inline. The pooled HTTP/1 architecture and coverage are strong; the highest-priority changes are preserving request trailers end-to-end and tying connector-capacity release to actual task termination.
Only unmatched hosts reach the blind tunnel, and real publisher pages reference many third-party domains that are dead, blackholed, or DNS-blocked. Logging each failure at warn level drowned out failures on mapped upstreams, so log them at debug instead. The browser still receives its 502 and the failure remains visible at debug level.
Closes #895
Summary
TCP_NODELAYexperiments that did not satisfy their retention gates.--resolve, Basic authentication, hop-by-hop sanitation, and blind-tunnel isolation.Final review corrections
Connection: closeresponses.Performance results
Full measurements and experiment decisions are recorded in
docs/superpowers/implementation-notes/2026-07-10-dev-proxy-performance.md.Verification
cargo fmt --all -- --checkcargo check --testsand Clippy with-D warnings./scripts/test-cli.sh— 147 unit + 26 E2E testsproxy_perfworkloads with one test thread