Skip to content

Commit 3e17660

Browse files
authored
[dwds] callServiceExtension should check all extensions and return kMethodNotFound when extension not found (#2597)
#2584 Currently, callServiceExtension checks the extensionRPCs field in the VM service. This list is populated when DWDS starts and checks the extensions currently registered in the runtime. This list is prone to becoming stale, however, as services may be registered or removed through the runtime (via dart:developer) later. Instead, we should seek to always check the runtime for the current registered extensions and then update this list whenever we do. It’s still prone to becoming stale, but it is less stale. Ideally, we would override extensionRPCs and fetch the current registered extensions, but that isn’t possible since it requires awaiting a future. We also can’t ignore this field altogether because it looks like clients, like Dart DevTools, uses this field. Note that extensionRPCs should be a subset of getExtensionRpcs since registerService isn't supported in DWDS. callServiceExtension should also return kMethodNotFound instead of its current JS evaluation error when an extension is not present.
1 parent 8f146a1 commit 3e17660

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

dwds/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## 24.3.7-wip
22

3+
- `callServiceExtension` now checks the runtime for the list of registered
4+
service extensions. It also now throws a `RPCError` with
5+
`RPCErrorKind.kMethodNotFound` when a service extension is not found instead
6+
of throwing a JS evaluation error.
7+
38
## 24.3.6
49

510
- Bump minimum sdk version to 3.7.0

dwds/lib/src/debugging/inspector.dart

+9-4
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ class AppInspector implements AppInspectorInterface {
115115
await DartUri.initialize();
116116
DartUri.recordAbsoluteUris(libraries.map((lib) => lib.uri).nonNulls);
117117
DartUri.recordAbsoluteUris(scripts.map((script) => script.uri).nonNulls);
118-
119-
isolate.extensionRPCs?.addAll(await _getExtensionRpcs());
118+
await getExtensionRpcs();
120119
}
121120

122121
static IsolateRef _toIsolateRef(Isolate isolate) => IsolateRef(
@@ -760,11 +759,16 @@ class AppInspector implements AppInspectorInterface {
760759
scriptId == null ? null : _scriptRefsById[scriptId];
761760

762761
/// Runs an eval on the page to compute all existing registered extensions.
763-
Future<List<String>> _getExtensionRpcs() async {
762+
///
763+
/// Combines this with the RPCs registered in the [isolate]. Use this over
764+
/// [Isolate.extensionRPCs] as this computes a live set.
765+
///
766+
/// Updates [Isolate.extensionRPCs] to this set.
767+
Future<Set<String>> getExtensionRpcs() async {
764768
final expression =
765769
globalToolConfiguration.loadStrategy.dartRuntimeDebugger
766770
.getDartDeveloperExtensionNamesJsExpression();
767-
final extensionRpcs = <String>[];
771+
final extensionRpcs = <String>{};
768772
final params = {
769773
'expression': expression,
770774
'returnByValue': true,
@@ -784,6 +788,7 @@ class AppInspector implements AppInspectorInterface {
784788
s,
785789
);
786790
}
791+
isolate.extensionRPCs = List<String>.of(extensionRpcs);
787792
return extensionRpcs;
788793
}
789794

dwds/lib/src/services/chrome_proxy_service.dart

+8-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ class ChromeProxyService implements VmServiceInterface {
343343
// TODO: We shouldn't need to fire these events since they exist on the
344344
// isolate, but devtools doesn't recognize extensions after a page refresh
345345
// otherwise.
346-
for (final extensionRpc in inspector.isolate.extensionRPCs ?? []) {
346+
for (final extensionRpc in await inspector.getExtensionRpcs()) {
347347
_streamNotify(
348348
'Isolate',
349349
Event(
@@ -509,6 +509,13 @@ class ChromeProxyService implements VmServiceInterface {
509509
v is String ? v : jsonEncode(v),
510510
),
511511
);
512+
if (!(await inspector.getExtensionRpcs()).contains(method)) {
513+
throw RPCError(
514+
method,
515+
RPCErrorKind.kMethodNotFound.code,
516+
'Unknown service method: $method',
517+
);
518+
}
512519
final expression = globalToolConfiguration.loadStrategy.dartRuntimeDebugger
513520
.invokeExtensionJsExpression(method, jsonEncode(stringArgs));
514521
final result = await inspector.jsEvaluate(expression, awaitPromise: true);

dwds/test/common/chrome_proxy_service_common.dart

+14
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,20 @@ void runTests({
298298
),
299299
},
300300
);
301+
302+
test('not found', () async {
303+
final serviceMethod = 'ext.test.missingServiceExtension';
304+
expect(
305+
service.callServiceExtension(serviceMethod),
306+
throwsA(
307+
predicate(
308+
(dynamic error) =>
309+
error is RPCError &&
310+
error.code == RPCErrorKind.kMethodNotFound.code,
311+
),
312+
),
313+
);
314+
});
301315
});
302316

303317
group('VMTimeline', () {

0 commit comments

Comments
 (0)