diff --git a/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js b/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js index bf7656843a2..d0cff55f83e 100644 --- a/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js +++ b/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js @@ -295,6 +295,42 @@ describe.each(['HTTP', 'HTTPS'])( debugger_.close(); } }); + + describe('Network.loadNetworkResource', () => { + test('should respond with an error without forwarding to the client', async () => { + const {device, debugger_} = await createAndConnectTarget( + serverRef, + autoCleanup.signal, + { + app: 'bar-app', + id: 'page1', + title: 'bar-title', + vm: 'bar-vm', + }, + ); + try { + const response = await debugger_.sendAndGetResponse({ + id: 1, + method: 'Network.loadNetworkResource', + params: { + url: 'http://example.com', + }, + }); + expect(response.result).toEqual( + expect.objectContaining({ + error: { + code: -32601, + message: + '[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.', + }, + }), + ); + } finally { + device.close(); + debugger_.close(); + } + }); + }); }, ); @@ -581,6 +617,33 @@ describe.each(['HTTP', 'HTTPS'])( } }); }); + + describe('Network.loadNetworkResource', () => { + test('should forward event directly to client (does not rewrite url host)', async () => { + const {device, debugger_} = await createAndConnectTarget( + serverRef, + autoCleanup.signal, + pageDescription, + ); + try { + const message = { + id: 1, + method: 'Network.loadNetworkResource', + params: { + url: `${protocol.toLowerCase()}://10.0.2.2:${serverRef.port}`, + }, + }; + await sendFromDebuggerToTarget(debugger_, device, 'page1', message); + expect(device.wrappedEventParsed).toBeCalledWith({ + pageId: 'page1', + wrappedEvent: message, + }); + } finally { + device.close(); + debugger_.close(); + } + }); + }); }); }, ); diff --git a/packages/dev-middleware/src/inspector-proxy/Device.js b/packages/dev-middleware/src/inspector-proxy/Device.js index 88b82f5995f..54fe5397fce 100644 --- a/packages/dev-middleware/src/inspector-proxy/Device.js +++ b/packages/dev-middleware/src/inspector-proxy/Device.js @@ -799,6 +799,31 @@ export default class Device { // Sends response to debugger via side-effect this.#processDebuggerGetScriptSource(req, socket); return null; + case 'Network.loadNetworkResource': + // If we're rewriting URLs (to frontend-relative), we don't want to + // pass these URLs to the device, since it may try to fetch, return a + // CDP *result* (not error) with a network failure, and CDT + // will *not* then fall back to fetching locally. + // + // Instead, take the absence of a nativeSourceCodeFetching + // capability as a signal to never pass a loadNetworkResource request + // to the device. By returning a CDP error, the frontend should fetch. + const result = { + error: { + code: -32601, // Method not found + message: + '[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.', + }, + }; + const response = {id: req.id, result}; + socket.send(JSON.stringify(response)); + const pageId = this.#debuggerConnection?.pageId ?? null; + this.#deviceEventReporter?.logResponse(response, 'proxy', { + pageId, + frontendUserAgent: this.#debuggerConnection?.userAgent ?? null, + prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId), + }); + return null; default: return req; } diff --git a/packages/dev-middleware/src/inspector-proxy/cdp-types/messages.js b/packages/dev-middleware/src/inspector-proxy/cdp-types/messages.js index b019728d15d..67ffef60e6c 100644 --- a/packages/dev-middleware/src/inspector-proxy/cdp-types/messages.js +++ b/packages/dev-middleware/src/inspector-proxy/cdp-types/messages.js @@ -44,6 +44,7 @@ export type CDPClientMessage = | CDPRequest<'Debugger.getScriptSource'> | CDPRequest<'Debugger.scriptParsed'> | CDPRequest<'Debugger.setBreakpointByUrl'> + | CDPRequest<'Network.loadNetworkResource'> | CDPRequest<>; export type CDPServerMessage =