From a52bd7dd080e1f0ad03209eecb69bda903470205 Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Tue, 16 Apr 2024 03:00:13 -0700 Subject: [PATCH] Inspector proxy: Rewrite 127.0.0.1 to localhost in source map URLs to support IPv4->IPv6 tunnels (#44092) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44092 In a setup where a device retrieves a bundle from `http://127.0.0.1:8081`, but this is tunnelled to a remote host with only an IPv6 stack (eg, FB dev servers), the host running the inspector-proxy will fail to fetch source or source maps from 127.0.0.1 despite typically being on the same host (indeed, process) as Metro. This causes a surprising inconsistency where using a bundler URL of `localhost` from the device results in source maps being inlined into `Debugger.scriptParsed`, but using a bundler URL of `127.0.0.1` causes inspector-proxy to fall back to preserving URLs, which are typically fetched lazily by CDT later. This should be unnecessary once we've implemented CDP `Network.loadNetworkResource` and removed `Debugger.scriptParsed` rewriting, but for now it brings IPv6 tunnelled servers in line with local servers. Changelog: [General][Changed] Inspector proxy: Rewrite 127.0.0.1 to localhost in source map URLs for better IPv4->IPv6 tunnelling support. Reviewed By: motiz88 Differential Revision: D56138742 fbshipit-source-id: b65c9cc8225a0ed54cf32171f640ef9e6408c762 --- .../InspectorProxyCdpRewritingHacks-test.js | 2 +- .../src/inspector-proxy/Device.js | 35 ++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js b/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js index b2d83c053d3..2f5eab91061 100644 --- a/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js +++ b/packages/dev-middleware/src/__tests__/InspectorProxyCdpRewritingHacks-test.js @@ -192,7 +192,7 @@ describe.each(['HTTP', 'HTTPS'])( } }); - describe.each(['10.0.2.2', '10.0.3.2'])( + describe.each(['10.0.2.2', '10.0.3.2', '127.0.0.1'])( '%s aliasing to and from localhost', sourceHost => { test('in source map fetching during Debugger.scriptParsed', async () => { diff --git a/packages/dev-middleware/src/inspector-proxy/Device.js b/packages/dev-middleware/src/inspector-proxy/Device.js index b9481dac910..1ecfd66f653 100644 --- a/packages/dev-middleware/src/inspector-proxy/Device.js +++ b/packages/dev-middleware/src/inspector-proxy/Device.js @@ -37,8 +37,21 @@ const debug = require('debug')('Metro:InspectorProxy'); const PAGES_POLLING_INTERVAL = 1000; -// Android's stock emulator and other emulators such as genymotion use a standard localhost alias. -const EMULATOR_LOCALHOST_ADDRESSES: Array = ['10.0.2.2', '10.0.3.2']; +// Replace hosts appearing in the `url` and `sourceMapURL` fields of +// `Debugger.scriptParsed`, and back again in messages from the debugger, +// to account for device/debugger/proxy running on different networks. +const REWRITE_HOSTS_TO_LOCALHOST: Array = [ + // A device may retrieve a bundle through 127.0.0.1 via a (SSH) tunnel, but + // the (remote) Metro server may be on a host without an IPv4 loopback, so + // 127.0.0.1 may not be addressible locally for (e.g., for source map + // fetching). Replacing with the more general 'localhost' should always be + // safe while also more compatible with IPv6-only setups. + '127.0.0.1', + // Android's stock emulator and other emulators such as genymotion use a + // standard localhost alias. + '10.0.2.2', + '10.0.3.2', +]; // Prefix for script URLs that are alphanumeric IDs. See comment in #processMessageFromDeviceLegacy method for // more details. @@ -621,15 +634,14 @@ export default class Device { ) { const params = payload.params; if ('sourceMapURL' in params) { - for (let i = 0; i < EMULATOR_LOCALHOST_ADDRESSES.length; ++i) { - const address = EMULATOR_LOCALHOST_ADDRESSES[i]; - if (params.sourceMapURL.includes(address)) { + for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) { + if (params.sourceMapURL.includes(hostToRewrite)) { // $FlowFixMe[cannot-write] payload.params.sourceMapURL = params.sourceMapURL.replace( - address, + hostToRewrite, 'localhost', ); - debuggerInfo.originalSourceURLAddress = address; + debuggerInfo.originalSourceURLAddress = hostToRewrite; } } @@ -654,12 +666,11 @@ export default class Device { } } if ('url' in params) { - for (let i = 0; i < EMULATOR_LOCALHOST_ADDRESSES.length; ++i) { - const address = EMULATOR_LOCALHOST_ADDRESSES[i]; - if (params.url.indexOf(address) >= 0) { + for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) { + if (params.url.includes(hostToRewrite)) { // $FlowFixMe[cannot-write] - payload.params.url = params.url.replace(address, 'localhost'); - debuggerInfo.originalSourceURLAddress = address; + payload.params.url = params.url.replace(hostToRewrite, 'localhost'); + debuggerInfo.originalSourceURLAddress = hostToRewrite; } }