Skip to content

fix(local proxy): route every Cursor-host request through the local backend so unmatched paths use the configured outbound proxy - #433

Open
rittachaos wants to merge 4 commits into
leookun:mainfrom
rittachaos:fix-hudsucker-proxy
Open

fix(local proxy): route every Cursor-host request through the local backend so unmatched paths use the configured outbound proxy#433
rittachaos wants to merge 4 commits into
leookun:mainfrom
rittachaos:fix-hudsucker-proxy

Conversation

@rittachaos

Copy link
Copy Markdown

问题

hudsucker 对未命中白名单的 *.cursor.sh 请求(如 skills sync / agent-store-sync)会由 hyper Connector 直连官方上游 api2.cursor.sh,无视任何代理配置。在仅允许代理出网的网络上,每次直连都会挂死约 75s(macOS connect 超时),表现为工具 round 被量化成 75s 整数倍、exec 日志周期性出现 502 / deadline_exceeded。

修复

  1. server/src/local_app/proxy.rs — 把所有 Cursor-host 请求改写指向本地后端,白名单外的路径经 router fallback proxy::forward 转发(使用 DB 配置的 outbound proxy);仅保留 Tab Direct 模式的原始直连旁路。这样 hudsucker 不再产生任何对官方上游的直连。
  2. 同文件第二处修复 — 跳过 CONNECT 隧道,不对其改写:hyper 的 Uri::host() 对 authority-form CONNECT URI 也返回 cursor 域名,若改写会把 should_intercept_connect 看到的 authority 变成 127.0.0.1,导致所有 Cursor-host 连接失去 TLS MITM。
  3. apps/desktop/src-tauri/Cargo.toml — 为 tauri 增加 custom-protocol feature:tauri-build 仅在未启用该 feature 时输出 cfg(dev),裸 cargo build --release 会以 dev 模式编译(前端路由到 Vite 代理、代理不会自动启用)。tauri build 隐含该 feature,此处仅为本地 release 构建对齐官方行为。

验证(实测)

  • 非白名单路径经代理返回 200(之前 75s 挂死/502),耗时 ~230ms
  • TLS MITM 恢复正常(白名单路径可正常完成握手与本地路由)
  • 客户端 exec 日志 EPROTO / 502 / deadline_exceeded 归零
  • agent 工具 round 间隔由 75s 整数倍降至 <60s(多数 8-21s)

风险

  • 依赖网络环境存在可用的 outbound proxy(DB 配置),纯直连网络下行为不变(直连仍可达则无影响)
  • 若个别未实现路径需要本地鉴权注入,可能返回 401,需按 account 注入模式迭代

王超16 added 4 commits September 8, 2026 10:55
…ckend

hudsucker's default pass-through dials the official Cursor upstream
(api2.cursor.sh) directly, ignoring the configured outbound proxy. On
networks with proxied-only egress each such dial hangs for ~75s, stalling
skills/agent-store syncs and quantizing tool rounds to 75s multiples.

Rewrite every Cursor-host request to the local backend so unmatched paths
fall through to the router fallback proxy::forward, which honors the
configured outbound proxy. Tab paths in explicit Direct mode keep their
original pass-through.
…ev mode

tauri-build sets cfg(dev) unless the tauri custom-protocol feature is
enabled. Plain `cargo build --release` without it compiled the app in
dev mode: console routed to the Vite dev server (frontend 502, blank
window) and the harness never auto-enabled the hudsucker proxy. Official
`tauri build` enables this feature implicitly; mirror it for local
release builds.
hudsucker forwards every request, including CONNECT, through
handle_request before should_intercept_connect decides on MITM. Because
hyper's Uri::host() returns api2.cursor.sh for authority-form CONNECT
URIs, the catch-all routing rewrite also rewrote CONNECTs to the local
backend, so interception saw 127.0.0.1 and disabled TLS MITM for every
Cursor-host connection (clients got plain-HTTP 400s / EPROTO instead of
a TLS handshake). Skip CONNECT requests so interception keeps working;
only post-MITM inner requests are routed locally.
Endpoints the official upstream deterministically rejects for accounts
without the corresponding cloud features (legacy /agent/v1/run probe 404,
agent-store/background-composer mints 400, tab file sync 404,
ws-reachability 404) used to be forwarded upstream, re-producing the
rejection over the network every time. On proxied-only egress networks
that forwarding was also what used to hang ~75s. Answer these paths in
CursorRelay with the same status Cursor already tolerates, so the
request never leaves the machine and Cursor keeps its existing
fallbacks (gRPC RunSSE after the /agent/v1/run probe, local agent
stores after MintAgentStoreToken).
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.

1 participant