Skip to content

Commit d75e017

Browse files
authored
Ensure launchDevTools always returns success or a valid error (#621)
* Ensure launchDevTools always returns success or a valid error Fixes #617. * Include stack in the error * Add a note about the format of the response
1 parent d9338b5 commit d75e017

File tree

1 file changed

+50
-33
lines changed

1 file changed

+50
-33
lines changed

packages/devtools_server/lib/src/server.dart

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const argMachine = 'machine';
2222
const argPort = 'port';
2323
const launchDevToolsService = 'launchDevTools';
2424

25+
const errorLaunchingBrowserCode = 500;
26+
2527
final argParser = new ArgParser()
2628
..addFlag(
2729
argHelp,
@@ -200,41 +202,56 @@ Future<void> registerLaunchDevToolsService(
200202
final VmService service = await _connectToVmService(vmServiceUri);
201203

202204
service.registerServiceCallback(launchDevToolsService, (params) async {
203-
final uriParams = <String, dynamic>{};
204-
205-
// Copy over queryParams passed by the client
206-
if (params != null) {
207-
params['queryParams']?.forEach((key, value) => uriParams[key] = value);
208-
}
205+
try {
206+
final uriParams = <String, dynamic>{};
207+
208+
// Copy over queryParams passed by the client
209+
if (params != null) {
210+
params['queryParams']
211+
?.forEach((key, value) => uriParams[key] = value);
212+
}
213+
214+
// Add the URI to the VM service
215+
uriParams['uri'] = vmServiceUri.toString();
216+
217+
final devToolsUri = Uri.parse(devToolsUrl);
218+
final uriToLaunch = devToolsUri.replace(
219+
// If path is empty, we generate 'http://foo:8000?uri=' (missing `/`) and
220+
// ChromeOS fails to detect that it's a port that's tunneled, and will
221+
// quietly replace the IP with "penguin.linux.test". This is not valid
222+
// for us since the server isn't bound to the containers IP (it's bound
223+
// to the containers loopback IP).
224+
path: devToolsUri.path.isEmpty ? '/' : devToolsUri.path,
225+
queryParameters: uriParams,
226+
);
209227

210-
// Add the URI to the VM service
211-
uriParams['uri'] = vmServiceUri.toString();
212-
213-
final devToolsUri = Uri.parse(devToolsUrl);
214-
final uriToLaunch = devToolsUri.replace(
215-
// If path is empty, we generate 'http://foo:8000?uri=' (missing `/`) and
216-
// ChromeOS fails to detect that it's a port that's tunneled, and will
217-
// quietly replace the IP with "penguin.linux.test". This is not valid
218-
// for us since the server isn't bound to the containers IP (it's bound
219-
// to the containers loopback IP).
220-
path: devToolsUri.path.isEmpty ? '/' : devToolsUri.path,
221-
queryParameters: uriParams,
222-
);
223-
224-
// TODO(dantup): When ChromeOS has support for tunneling all ports we
225-
// can change this to always use the native browser for ChromeOS
226-
// and may wish to handle this inside `browser_launcher`.
227-
// https://crbug.com/848063
228-
final useNativeBrowser = _isChromeOS &&
229-
_isAccessibleToChromeOSNativeBrowser(Uri.parse(devToolsUrl)) &&
230-
_isAccessibleToChromeOSNativeBrowser(vmServiceUri);
231-
if (useNativeBrowser) {
232-
await Process.start('x-www-browser', [uriToLaunch.toString()]);
233-
} else {
234-
await Chrome.start([uriToLaunch.toString()]);
228+
// TODO(dantup): When ChromeOS has support for tunneling all ports we
229+
// can change this to always use the native browser for ChromeOS
230+
// and may wish to handle this inside `browser_launcher`.
231+
// https://crbug.com/848063
232+
final useNativeBrowser = _isChromeOS &&
233+
_isAccessibleToChromeOSNativeBrowser(Uri.parse(devToolsUrl)) &&
234+
_isAccessibleToChromeOSNativeBrowser(vmServiceUri);
235+
if (useNativeBrowser) {
236+
await Process.start('x-www-browser', [uriToLaunch.toString()]);
237+
} else {
238+
await Chrome.start([uriToLaunch.toString()]);
239+
}
240+
241+
return {'result': Success().toJson()};
242+
} catch (e, s) {
243+
// Note: It's critical that we return responses in exactly the right format
244+
// or the VM will unregister the service. The objects must match JSON-RPC
245+
// however a successful response must also have a "type" field in its result.
246+
// Otherwise, we can return an error object (instead of result) that includes
247+
// code + message.
248+
return {
249+
'error': {
250+
'code': errorLaunchingBrowserCode,
251+
'message': 'Failed to launch browser: $e\n$s',
252+
},
253+
};
235254
}
236-
237-
return {'result': Success().toJson()};
238255
});
239256

240257
await service.registerService(launchDevToolsService, 'DevTools Server');

0 commit comments

Comments
 (0)