fix(browser): resolve HTTP CDP URLs#113
Conversation
There was a problem hiding this comment.
2 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/bcode-browser/src/cdp/session.ts">
<violation number="1" location="packages/bcode-browser/src/cdp/session.ts:95">
P2: An HTTP `BU_CDP_URL` connection can exceed the caller's `timeoutMs`: discovery consumes up to that timeout, then the WebSocket phase starts a fresh full timeout. A browser that becomes discoverable just before the deadline but whose WebSocket is unavailable can therefore take roughly twice the requested timeout to fail. Carry one absolute deadline through discovery and `openWs`, or pass only the remaining time to the second phase.</violation>
<violation number="2" location="packages/bcode-browser/src/cdp/session.ts:96">
P2: A valid HTTP `BU_CDP_URL` with an uppercase scheme bypasses `/json/version` discovery because the prefix check is case-sensitive, so the endpoint is treated as a direct WebSocket URL and the connection fails against the HTTP root. Case-insensitive scheme detection (or parsing with `new URL(...).protocol`) would keep equivalent HTTP URL spellings on the discovery path.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://') | ||
| ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs) | ||
| : envCdpUrl; |
There was a problem hiding this comment.
P2: A valid HTTP BU_CDP_URL with an uppercase scheme bypasses /json/version discovery because the prefix check is case-sensitive, so the endpoint is treated as a direct WebSocket URL and the connection fails against the HTTP root. Case-insensitive scheme detection (or parsing with new URL(...).protocol) would keep equivalent HTTP URL spellings on the discovery path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/bcode-browser/src/cdp/session.ts, line 96:
<comment>A valid HTTP `BU_CDP_URL` with an uppercase scheme bypasses `/json/version` discovery because the prefix check is case-sensitive, so the endpoint is treated as a direct WebSocket URL and the connection fails against the HTTP root. Case-insensitive scheme detection (or parsing with `new URL(...).protocol`) would keep equivalent HTTP URL spellings on the discovery path.</comment>
<file context>
@@ -85,11 +86,19 @@ export class Session implements Transport {
}
+ const envCdpUrl = process.env.BU_CDP_URL;
+ if (envCdpUrl) {
+ const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://')
+ ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs)
+ : envCdpUrl;
</file context>
| const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://') | |
| ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs) | |
| : envCdpUrl; | |
| const wsUrl = /^https?:\/\//i.test(envCdpUrl) | |
| ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs) | |
| : envCdpUrl; |
| if (envCdpUrl) { | ||
| const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://') | ||
| ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs) | ||
| : envCdpUrl; | ||
| await this.openWs(wsUrl, timeoutMs); | ||
| return; | ||
| } |
There was a problem hiding this comment.
P2: An HTTP BU_CDP_URL connection can exceed the caller's timeoutMs: discovery consumes up to that timeout, then the WebSocket phase starts a fresh full timeout. A browser that becomes discoverable just before the deadline but whose WebSocket is unavailable can therefore take roughly twice the requested timeout to fail. Carry one absolute deadline through discovery and openWs, or pass only the remaining time to the second phase.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/bcode-browser/src/cdp/session.ts, line 95:
<comment>An HTTP `BU_CDP_URL` connection can exceed the caller's `timeoutMs`: discovery consumes up to that timeout, then the WebSocket phase starts a fresh full timeout. A browser that becomes discoverable just before the deadline but whose WebSocket is unavailable can therefore take roughly twice the requested timeout to fail. Carry one absolute deadline through discovery and `openWs`, or pass only the remaining time to the second phase.</comment>
<file context>
@@ -85,11 +86,19 @@ export class Session implements Transport {
return;
}
+ const envCdpUrl = process.env.BU_CDP_URL;
+ if (envCdpUrl) {
+ const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://')
+ ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs)
</file context>
| if (envCdpUrl) { | |
| const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://') | |
| ? await resolveHttpCdpUrl(envCdpUrl, timeoutMs) | |
| : envCdpUrl; | |
| await this.openWs(wsUrl, timeoutMs); | |
| return; | |
| } | |
| if (envCdpUrl) { | |
| const deadline = Date.now() + timeoutMs; | |
| const wsUrl = envCdpUrl.startsWith('http://') || envCdpUrl.startsWith('https://') | |
| ? await resolveHttpCdpUrl(envCdpUrl, Math.max(1, deadline - Date.now())) | |
| : envCdpUrl; | |
| await this.openWs(wsUrl, Math.max(1, deadline - Date.now())); | |
| return; | |
| } |
Summary
BU_CDP_URL=http://...as a DevTools HTTP endpoint and resolve its WebSocket URL through/json/versionBU_CDP_URL=ws://...compatibility and keepBU_CDP_WSas the highest-priority direct WebSocket settingPreviously an HTTP
BU_CDP_URLwas passed directly tonew WebSocket, which attempted an upgrade on the HTTP root instead of querying/json/version. This matches the public browser-harness endpoint contract.Validation
bun testinpackages/bcode-browser: 16 pass, 8 environment-gated skipsbunx oxlint packages/bcode-browser/test/connect-env.test.ts: cleanSummary by cubic
Fixes connection to Chrome when
BU_CDP_URLis an HTTP DevTools endpoint by resolving its WebSocket URL via/json/version, preventing failed upgrades on the HTTP root. Adds retry until the caller’s timeout and clearer 403 permission errors, while keepingBU_CDP_WSpriority andBU_CDP_URLWebSocket compatibility.BU_CDP_URLthrough/json/versionto obtainwebSocketDebuggerUrl.BU_CDP_WSoverBU_CDP_URL; accept WebSocket values inBU_CDP_URL.Written for commit 2946376. Summary will update on new commits.