-
Notifications
You must be signed in to change notification settings - Fork 402
Expand file tree
/
Copy path_devtools_extensions.dart
More file actions
122 lines (111 loc) · 4.63 KB
/
Copy path_devtools_extensions.dart
File metadata and controls
122 lines (111 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright 2024 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
part of '../server_api.dart';
/// A namespace for DevTools extensions server request handlers.
extension _ExtensionsApiHandler on Never {
static Future<shelf.Response> handleServeAvailableExtensions(
ServerApi api,
Map<String, String> queryParams,
ExtensionsManager extensionsManager,
DtdInfo? dtd,
) async {
final missingRequiredParams = ServerApi._checkRequiredParameters(
[ExtensionsApi.packageRootUriPropertyName],
queryParams: queryParams,
api: api,
requestName: ExtensionsApi.apiServeAvailableExtensions,
);
if (missingRequiredParams != null) return missingRequiredParams;
final logs = <String>[];
final rootFileUriString =
queryParams[ExtensionsApi.packageRootUriPropertyName];
final result = <String, Object?>{};
/// Helper to return a success response with all available extensions
/// detected by [extensionsManager].
shelf.Response succeedWithAvailableExtensions({String? warning}) {
final extensions =
extensionsManager.devtoolsExtensions.map((p) => p.toJson()).toList();
result[ExtensionsApi.extensionsResultPropertyName] = extensions;
if (warning != null) {
result[ExtensionsApi.extensionsResultWarningPropertyName] = warning;
}
return ServerApi._encodeResponse(
ServerApi._wrapWithLogs(result, logs),
api: api,
);
}
try {
await extensionsManager.serveAvailableExtensions(
rootFileUriString,
logs,
dtd,
);
} on ExtensionParsingException catch (e) {
// For [ExtensionParsingException]s, we should return a success response
// with a warning message.
result[ExtensionsApi.extensionsResultWarningPropertyName] = e.message;
} catch (e) {
// If any extensions were successfully detected, return a success response
// with a warning.
if (extensionsManager.devtoolsExtensions.isNotEmpty) {
return succeedWithAvailableExtensions(warning: '$e');
}
return api.serverError('$e', logs);
}
return succeedWithAvailableExtensions();
}
static shelf.Response handleExtensionEnabledState(
ServerApi api,
Map<String, String> queryParams,
) {
final missingRequiredParams = ServerApi._checkRequiredParameters(
[
ExtensionsApi.devtoolsOptionsUriPropertyName,
ExtensionsApi.extensionNamePropertyName,
],
queryParams: queryParams,
api: api,
requestName: ExtensionsApi.apiExtensionEnabledState,
);
if (missingRequiredParams != null) return missingRequiredParams;
final devtoolsOptionsFileUriString =
queryParams[ExtensionsApi.devtoolsOptionsUriPropertyName]!;
final devtoolsOptionsFileUri = Uri.parse(devtoolsOptionsFileUriString);
// Validate that the URI is a local file URI whose file name is exactly
// 'devtools_options.yaml'. Accepting arbitrary URIs from the query string
// would allow an untrusted caller to create or overwrite any file writable
// by the DevTools server process. Resolving the name through
// `Uri.toFilePath()` + `p.basename` handles both '/' and '\' path
// separators, so the check holds for Windows file URIs as well. Requiring
// an empty host rejects UNC paths (e.g. `file://server/share/...`) and
// keeps `toFilePath()` from throwing on a non-local authority.
final isFileUri = devtoolsOptionsFileUri.scheme == 'file' &&
devtoolsOptionsFileUri.host.isEmpty;
final fileName = isFileUri
? p.basename(devtoolsOptionsFileUri.toFilePath())
: '';
if (!isFileUri || fileName != 'devtools_options.yaml') {
return api.badRequest(
'Invalid devtoolsOptionsUri: must be a file: URI named '
"'devtools_options.yaml'.",
);
}
final extensionName = queryParams[ExtensionsApi.extensionNamePropertyName]!;
final activate = queryParams[ExtensionsApi.enabledStatePropertyName];
if (activate != null) {
final newState = ServerApi._devToolsOptions.setExtensionEnabledState(
devtoolsOptionsUri: devtoolsOptionsFileUri,
extensionName: extensionName,
enable: bool.parse(activate),
);
return ServerApi._encodeResponse(newState.name, api: api);
}
final activationState =
ServerApi._devToolsOptions.lookupExtensionEnabledState(
devtoolsOptionsUri: devtoolsOptionsFileUri,
extensionName: extensionName,
);
return ServerApi._encodeResponse(activationState.name, api: api);
}
}