Skip to content

Commit

Permalink
Support loading source URLs in inspector-proxy
Browse files Browse the repository at this point in the history
Summary:
The path to a source file may be a bundler service URL, rather than a filesystem path. This change makes the inspector-proxy detect when the source path is a URL, and fetch the source over HTTP (so long as the URL is on localhost).

This change also includes a bit of reorganizing: the message-intercepting code is now responsible for sending the response, as some interceptions generate a synchronous response, some generate an asynchronous response, and some generate no response at all.

As with errors when loading a file, a failure to load is sent to the client.

Reviewed By: robhogan

Differential Revision: D39629274

fbshipit-source-id: a205a015bff68190448f28350d481304ad207556
  • Loading branch information
Matt Blagden authored and facebook-github-bot committed Sep 30, 2022
1 parent 0b4cd33 commit db19b06
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 38 deletions.
80 changes: 56 additions & 24 deletions packages/metro-inspector-proxy/src/Device.js
Expand Up @@ -11,7 +11,6 @@

import type {
DebuggerRequest,
DebuggerResponse,
GetScriptSourceRequest,
GetScriptSourceResponse,
MessageFromDevice,
Expand All @@ -21,6 +20,7 @@ import type {
} from './types';

import * as fs from 'fs';
import * as http from 'http';
import * as path from 'path';
import WS from 'ws';

Expand Down Expand Up @@ -177,14 +177,13 @@ class Device {
socket.on('message', (message: string) => {
debug('(Debugger) -> (Proxy) (Device): ' + message);
const debuggerRequest = JSON.parse(message);
const interceptedResponse = this._interceptMessageFromDebugger(
const handled = this._interceptMessageFromDebugger(
debuggerRequest,
debuggerInfo,
socket,
);

if (interceptedResponse) {
socket.send(JSON.stringify(interceptedResponse));
} else {
if (!handled) {
this._sendMessageToDevice({
event: 'wrappedEvent',
payload: {
Expand Down Expand Up @@ -437,21 +436,21 @@ class Device {
}
}

// Allows to make changes in incoming messages from debugger.
// Allows to make changes in incoming messages from debugger. Returns a boolean
// indicating whether the message has been handled locally (i.e. does not need
// to be forwarded to the target).
_interceptMessageFromDebugger(
req: DebuggerRequest,
debuggerInfo: DebuggerInfo,
): ?DebuggerResponse {
let response = null;
socket: typeof WS,
): boolean {
if (req.method === 'Debugger.setBreakpointByUrl') {
this._processDebuggerSetBreakpointByUrl(req, debuggerInfo);
} else if (req.method === 'Debugger.getScriptSource') {
response = {
id: req.id,
result: this._processDebuggerGetScriptSource(req),
};
this._processDebuggerGetScriptSource(req, socket);
return true;
}
return response;
return false;
}

_processDebuggerSetBreakpointByUrl(
Expand Down Expand Up @@ -488,26 +487,59 @@ class Device {

_processDebuggerGetScriptSource(
req: GetScriptSourceRequest,
): GetScriptSourceResponse {
socket: typeof WS,
) {
let scriptSource = `Source for script with id '${req.params.scriptId}' was not found.`;

const sendResponse = () => {
const result: GetScriptSourceResponse = {scriptSource};
socket.send(JSON.stringify({id: req.id, result}));
};

const pathToSource = this._scriptIdToSourcePathMapping.get(
req.params.scriptId,
);
if (pathToSource) {
let pathIsURL = false;
try {
scriptSource = fs.readFileSync(
path.resolve(this._projectRoot, pathToSource),
'utf8',
);
} catch (err) {
scriptSource = err.message;
pathIsURL = new URL(pathToSource).hostname == 'localhost';
} catch {}

if (pathIsURL) {
http
.get(pathToSource, httpResponse => {
const {statusCode} = httpResponse;
if (statusCode == 200) {
httpResponse.setEncoding('utf8');
scriptSource = '';
httpResponse.on('data', body => {
scriptSource += body;
});
httpResponse.on('end', () => {
sendResponse();
});
} else {
scriptSource = `Fetching ${pathToSource} returned status ${statusCode}`;
sendResponse();
httpResponse.resume();
}
})
.on('error', e => {
scriptSource = `Fetching ${pathToSource} failed with error ${e.message}`;
sendResponse();
});
} else {
try {
scriptSource = fs.readFileSync(
path.resolve(this._projectRoot, pathToSource),
'utf8',
);
} catch (err) {
scriptSource = err.message;
}
sendResponse();
}
}

return {
scriptSource,
};
}

_mapToDevicePageId(pageId: string): string {
Expand Down
14 changes: 0 additions & 14 deletions packages/metro-inspector-proxy/src/types.js
Expand Up @@ -110,15 +110,6 @@ export type SetBreakpointByUrlRequest = {
},
};

export type SetBreakpointByUrlResponse = {
breakpointId: string,
locations: {
scriptId: string,
lineNumber: number,
columnNumber?: number,
}[],
};

export type GetScriptSourceRequest = {
id: number,
method: 'Debugger.getScriptSource',
Expand All @@ -138,8 +129,3 @@ export type GetScriptSourceResponse = {
export type DebuggerRequest =
| SetBreakpointByUrlRequest
| GetScriptSourceRequest;

export type DebuggerResponse = {
id: number,
result: SetBreakpointByUrlResponse | GetScriptSourceResponse,
};

0 comments on commit db19b06

Please sign in to comment.