From 3c2adf81f01ec561f1f54fadd0dd1aeaca12b3e6 Mon Sep 17 00:00:00 2001 From: quetaifu Date: Fri, 17 Apr 2026 10:31:09 +0800 Subject: [PATCH] feat(browse): BROWSE_NO_PROXY env var to bypass system proxy on launch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS, Chromium (via Playwright) inherits the system HTTP/S proxy by default. When the user runs a local VPN/proxy app (Shadowrocket, ClashX, Surge, etc.) that does TLS interception, Chromium's HTTPS handshake breaks with SSL error 1 / net_error -100, and every goto fails with ERR_ABORTED. The renderer then crashes and kills the browse server, triggering the familiar '[browse] Starting server...' restart loop. curl is unaffected because curl ignores the system proxy by default, so curl-based health checks continue to pass while browse is broken — making this failure mode especially confusing. Opt-in: set BROWSE_NO_PROXY=1 in the environment and browse will pass '--proxy-server=direct://' to Chromium at launch, bypassing the system proxy entirely. Default behavior unchanged (still inherits system proxy) so corporate proxy users are not affected. Repro: # With Shadowrocket running in HTTP-proxy mode on macOS: browse goto https://example.com # ERR_ABORTED / Timeout 15000ms BROWSE_NO_PROXY=1 browse goto https://example.com # 200 OK --- browse/src/browser-manager.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/browse/src/browser-manager.ts b/browse/src/browser-manager.ts index 63d783580..845611091 100644 --- a/browse/src/browser-manager.ts +++ b/browse/src/browser-manager.ts @@ -163,6 +163,19 @@ export class BrowserManager { launchArgs.push('--no-sandbox'); } + // System proxy bypass: on macOS, Chromium inherits the system HTTP/S proxy + // by default. Local VPN/proxy apps (Shadowrocket, ClashX, Surge, etc.) + // typically MITM TLS via a local proxy — when the proxy's cert handling + // breaks, every Chromium navigation fails with net_error -100 / + // ERR_ABORTED and the renderer crashes, killing the browse server. + // Setting BROWSE_NO_PROXY=1 tells Chromium to route directly, bypassing + // the system proxy entirely. curl is unaffected by system proxy by + // default, so curl-based health checks can remain working while + // Chromium is broken — hence this needs to be explicit. + if (process.env.BROWSE_NO_PROXY === '1') { + launchArgs.push('--proxy-server=direct://'); + } + if (extensionsDir) { launchArgs.push( `--disable-extensions-except=${extensionsDir}`,