From a52c2d6bf2b3a3fa44d70736d6ec8511a5ec50c3 Mon Sep 17 00:00:00 2001 From: Ljy-0827 Date: Tue, 28 Jul 2026 11:19:19 +0800 Subject: [PATCH] feat(vom): split function fix --- .../__tests__/chromium-cdp.test.ts | 82 ------------- .../src/browser-driver/chromium-cdp.ts | 108 ------------------ 2 files changed, 190 deletions(-) diff --git a/apps/extension/src/browser-driver/__tests__/chromium-cdp.test.ts b/apps/extension/src/browser-driver/__tests__/chromium-cdp.test.ts index 8e09273..f6d88d3 100644 --- a/apps/extension/src/browser-driver/__tests__/chromium-cdp.test.ts +++ b/apps/extension/src/browser-driver/__tests__/chromium-cdp.test.ts @@ -119,88 +119,6 @@ describe("ChromiumCdp", () => { expect(api.sendCommand).toHaveBeenCalledWith({ tabId: 9 }, "Page.enable", {}); }); - it("validates the attached top-frame URL for page reads", async () => { - const { api } = fakeApi(); - (api.sendCommand as ReturnType).mockImplementation( - async (_target, method: string) => { - if (method === "Page.getFrameTree") { - return { frameTree: { frame: { url: "https://example.test/page" } } }; - } - return {}; - }, - ); - const cdp = new ChromiumCdp(api); - - await expect( - cdp.ensureAttachedToUrl(9, "https://example.test/page#section"), - ).resolves.toBeUndefined(); - expect(api.detach).not.toHaveBeenCalled(); - }); - - it("reattaches when the cached CDP target points at an extension page", async () => { - const { api } = fakeApi(); - let frameReads = 0; - (api.sendCommand as ReturnType).mockImplementation( - async (_target, method: string) => { - if (method === "Page.getFrameTree") { - frameReads += 1; - return { - frameTree: { - frame: { - url: - frameReads === 1 - ? "chrome-extension://other-extension/page.html" - : "https://example.test/page", - }, - }, - }; - } - return {}; - }, - ); - const cdp = new ChromiumCdp(api); - - await expect(cdp.ensureAttachedToUrl(9, "https://example.test/page")).resolves.toBeUndefined(); - expect(api.attach).toHaveBeenCalledTimes(2); - expect(api.detach).toHaveBeenCalledWith({ tabId: 9 }); - }); - - it("rejects when reattach still points at the wrong page", async () => { - const { api } = fakeApi(); - (api.sendCommand as ReturnType).mockImplementation( - async (_target, method: string) => { - if (method === "Page.getFrameTree") { - return { frameTree: { frame: { url: "https://wrong.test/" } } }; - } - return {}; - }, - ); - const cdp = new ChromiumCdp(api); - - await expect(cdp.ensureAttachedToUrl(9, "https://example.test/")).rejects.toThrow( - /CDP target URL mismatch/, - ); - expect(api.attach).toHaveBeenCalledTimes(2); - }); - - it("clears the attach cache after an internal-page access error", async () => { - const { api } = fakeApi(); - (api.sendCommand as ReturnType).mockImplementation( - async (_target, method: string) => { - if (method === "DOM.getDocument") { - throw new Error("Cannot access a chrome-extension:// URL of different extension"); - } - return {}; - }, - ); - const cdp = new ChromiumCdp(api); - - await expect(cdp.ensureAttached(9)).resolves.toBeUndefined(); - expect(cdp.isAttached(9)).toBe(true); - await expect(cdp.send(9, "DOM.getDocument")).rejects.toThrow(/chrome-extension/); - expect(cdp.isAttached(9)).toBe(false); - }); - it("enables console capture domains best-effort during attach", async () => { const { api } = fakeApi(); (api.sendCommand as ReturnType).mockImplementation( diff --git a/apps/extension/src/browser-driver/chromium-cdp.ts b/apps/extension/src/browser-driver/chromium-cdp.ts index 8aeec4f..3848e97 100644 --- a/apps/extension/src/browser-driver/chromium-cdp.ts +++ b/apps/extension/src/browser-driver/chromium-cdp.ts @@ -93,15 +93,6 @@ const MAX_CONSOLE_STACK_FRAMES = 20; const MAX_NETWORK_BUFFER = 200; const MAX_NETWORK_FIELD_LENGTH = 4096; const MAX_NETWORK_REQUEST_META = 1024; -const CDP_INTERNAL_PROTOCOLS = new Set([ - "chrome:", - "chrome-extension:", - "devtools:", - "edge:", - "brave:", - "vivaldi:", - "opera:", -]); interface ParsedDialogOpening { type: JavaScriptDialogType; @@ -182,31 +173,6 @@ export class ChromiumCdp { await attach; } - /** - * Attach and verify Chrome's actual CDP target still points at the page URL - * Chrome tabs reported to the tool resolver. A stale debugger target can - * otherwise surface another extension/internal URL while the tab record looks - * like a normal page. - */ - async ensureAttachedToUrl(tabId: number, expectedUrl: string | undefined): Promise { - await this.ensureAttached(tabId); - if (!expectedUrl) return; - - const first = await this.readTopFrameUrl(tabId).catch((err) => { - if (isInternalTargetAccessError(err)) return null; - throw err; - }); - if (first && cdpUrlsCompatible(first, expectedUrl)) return; - - await this.forceReattach(tabId); - const second = await this.readTopFrameUrl(tabId); - if (cdpUrlsCompatible(second, expectedUrl)) return; - - throw new Error( - `CDP target URL mismatch for tab ${tabId}: expected ${expectedUrl}, attached to ${second}`, - ); - } - /** * Send a CDP command and decode the result as `T`. Throws on any * `chrome.runtime.lastError`. @@ -219,9 +185,6 @@ export class ChromiumCdp { const result = await this.api.sendCommand({ tabId }, method, params ?? {}); return result as T; } catch (err) { - if (isInternalTargetAccessError(err)) { - this.clearAttachedState(tabId); - } throw normalizeError(err); } } @@ -396,31 +359,6 @@ export class ChromiumCdp { } } - private async forceReattach(tabId: number): Promise { - this.clearAttachedState(tabId); - try { - await this.api.detach({ tabId }); - } catch { - // Chrome may already have detached; attach below is the source of truth. - } - await this.ensureAttached(tabId); - } - - private clearAttachedState(tabId: number): void { - this.attachInFlight.delete(tabId); - this.attachedTabs.delete(tabId); - this.clearDialogState(tabId); - this.clearConsoleState(tabId); - this.clearNetworkState(tabId); - } - - private async readTopFrameUrl(tabId: number): Promise { - const frameTree = await this.api.sendCommand({ tabId }, "Page.getFrameTree", {}); - const url = topFrameUrl(frameTree); - if (!url) throw new Error(`Page.getFrameTree returned no top-frame URL for tab ${tabId}`); - return url; - } - private bindDialogHandler(): void { if (this.dialogSubscription) return; const listener = (source: chrome.debugger.Debuggee, method: string, params: unknown) => { @@ -968,49 +906,3 @@ function normalizeError(err: unknown): Error { } return new Error("unknown chrome.debugger error"); } - -function isInternalTargetAccessError(err: unknown): boolean { - const message = normalizeError(err).message; - return ( - /Cannot access a chrome-extension:\/\/ URL/i.test(message) || - /Cannot access a chrome:\/\/ URL/i.test(message) || - /Cannot access contents of url/i.test(message) - ); -} - -function topFrameUrl(frameTree: unknown): string | null { - const raw = (frameTree ?? {}) as Record; - const tree = (raw.frameTree ?? {}) as Record; - const frame = (tree.frame ?? {}) as Record; - return typeof frame.url === "string" && frame.url.length > 0 ? frame.url : null; -} - -function cdpUrlsCompatible(actualUrl: string, expectedUrl: string): boolean { - const actual = normalizeComparableUrl(actualUrl); - const expected = normalizeComparableUrl(expectedUrl); - if (!actual || !expected) return false; - if (isInternalCdpUrl(actual)) return false; - return actual === expected; -} - -function normalizeComparableUrl(value: string): string | null { - let parsed: URL; - try { - parsed = new URL(value); - } catch { - return null; - } - parsed.hash = ""; - return parsed.toString(); -} - -function isInternalCdpUrl(value: string): boolean { - let parsed: URL; - try { - parsed = new URL(value); - } catch { - return false; - } - if (CDP_INTERNAL_PROTOCOLS.has(parsed.protocol)) return true; - return parsed.protocol === "about:" && parsed.pathname !== "blank"; -}