Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(835)

Side by Side Diff: sdk/lib/developer/extension.dart

Issue 1299493007: Rework service extensions to be safe (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sdk/lib/_internal/js_runtime/lib/developer_patch.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.developer; 5 part of dart.developer;
6 6
7 class ServiceExtensionResponse { 7 class ServiceExtensionResponse {
8 final String _result; 8 final String _result;
9 final int _errorCode; 9 final int _errorCode;
10 final String _errorDetail; 10 final String _errorDetail;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 79
80 /// A service protocol extension handler. Registered with [registerExtension]. 80 /// A service protocol extension handler. Registered with [registerExtension].
81 /// 81 ///
82 /// Must complete to a [ServiceExtensionResponse]. 82 /// Must complete to a [ServiceExtensionResponse].
83 /// 83 ///
84 /// [method] - the method name. 84 /// [method] - the method name.
85 /// [parameters] - the parameters. 85 /// [parameters] - the parameters.
86 typedef Future<ServiceExtensionResponse> 86 typedef Future<ServiceExtensionResponse>
87 ServiceExtensionHandler(String method, Map parameters); 87 ServiceExtensionHandler(String method, Map parameters);
88 88
89 final _extensions = new Map<String, ServiceExtensionHandler>();
90
91 /// Register a [ServiceExtensionHandler] that will be invoked in this isolate 89 /// Register a [ServiceExtensionHandler] that will be invoked in this isolate
92 /// for [method]. 90 /// for [method].
93 void registerExtension(String method, ServiceExtensionHandler handler) { 91 void registerExtension(String method, ServiceExtensionHandler handler) {
94 if (_extensions[method] != null) { 92 if (method is! String) {
93 throw new ArgumentError.value(method,
94 'method',
95 'Must be a String');
96 }
97 if (_lookupExtension(method) != null) {
95 throw new ArgumentError('Extension already registered: $method'); 98 throw new ArgumentError('Extension already registered: $method');
96 } 99 }
97 if (handler is! ServiceExtensionHandler) { 100 if (handler is! ServiceExtensionHandler) {
98 throw new ArgumentError.value(handler, 101 throw new ArgumentError.value(handler,
99 'handler', 102 'handler',
100 'Must be a ServiceExtensionHandler'); 103 'Must be a ServiceExtensionHandler');
101 } 104 }
102 _extensions[method] = handler; 105 _registerExtension(method, handler);
103 } 106 }
104 107
105 bool _scheduleExtension(String method, 108 // Both of these functions are written inside C++ to avoid updating the data
106 List<String> parameterKeys, 109 // structures in Dart, getting an OOB, and observing stale state. Do not move
107 List<String> parameterValues, 110 // these into Dart code unless you can ensure that the operations will can be
108 SendPort replyPort, 111 // done atomically. Native code lives in vm/isolate.cc-
109 Object id) { 112 // LookupServiceExtensionHandler and RegisterServiceExtensionHandler.
110 ServiceExtensionHandler handler = _extensions[method]; 113 external ServiceExtensionHandler _lookupExtension(String method);
111 if (handler == null) { 114 external _registerExtension(String method, ServiceExtensionHandler handler);
112 return false; 115
116 // This code is only invoked when there is no other Dart code on the stack.
117 _runExtension(ServiceExtensionHandler handler,
118 String method,
119 List<String> parameterKeys,
120 List<String> parameterValues,
121 SendPort replyPort,
122 Object id) {
123 var parameters = {};
124 for (var i = 0; i < parameterKeys.length; i++) {
125 parameters[parameterKeys[i]] = parameterValues[i];
113 } 126 }
114 // Defer execution of handler until next event loop. 127 var response;
115 Timer.run(() { 128 try {
116 var parameters = {}; 129 response = handler(method, parameters);
117 for (var i = 0; i < parameterKeys.length; i++) { 130 } catch (e, st) {
118 parameters[parameterKeys[i]] = parameterValues[i]; 131 var errorDetails = (st == null) ? '$e' : '$e\n$st';
119 } 132 response = new ServiceExtensionResponse.error(
120 var response; 133 ServiceExtensionResponse.kExtensionError,
121 try { 134 errorDetails);
122 response = handler(method, parameters); 135 _postResponse(replyPort, id, response);
123 } catch (e, st) { 136 return;
124 var errorDetails = (st == null) ? '$e' : '$e\n$st'; 137 }
138 if (response is! Future) {
139 response = new ServiceExtensionResponse.error(
140 ServiceExtensionResponse.kExtensionError,
141 "Extension handler must return a Future");
142 _postResponse(replyPort, id, response);
143 return;
144 }
145 response.catchError((e, st) {
146 // Catch any errors eagerly and wrap them in a ServiceExtensionResponse.
147 var errorDetails = (st == null) ? '$e' : '$e\n$st';
148 return new ServiceExtensionResponse.error(
149 ServiceExtensionResponse.kExtensionError,
150 errorDetails);
151 }).then((response) {
152 // Post the valid response or the wrapped error after verifying that
153 // the response is a ServiceExtensionResponse.
154 if (response is! ServiceExtensionResponse) {
125 response = new ServiceExtensionResponse.error( 155 response = new ServiceExtensionResponse.error(
126 ServiceExtensionResponse.kExtensionError, 156 ServiceExtensionResponse.kExtensionError,
127 errorDetails); 157 "Extension handler must complete to a ServiceExtensionResponse");
128 _postResponse(replyPort, id, response);
129 return;
130 } 158 }
131 if (response is! Future) { 159 _postResponse(replyPort, id, response);
132 response = new ServiceExtensionResponse.error( 160 }).catchError((e, st) {
133 ServiceExtensionResponse.kExtensionError, 161 // We do not expect any errors to occur in the .then or .catchError blocks
134 "Extension handler must return a Future"); 162 // but, suppress them just in case.
135 _postResponse(replyPort, id, response);
136 return;
137 }
138 response.catchError((e, st) {
139 var errorDetails = (st == null) ? '$e' : '$e\n$st';
140 return new ServiceExtensionResponse.error(
141 ServiceExtensionResponse.kExtensionError,
142 errorDetails);
143 }).then((response) {
144 if (response == null) {
145 response = new ServiceExtensionResponse.error(
146 ServiceExtensionResponse.kExtensionError,
147 "Extension handler returned null");
148 }
149 _postResponse(replyPort, id, response);
150 });
151 }); 163 });
152 return true;
153 } 164 }
154 165
166 // This code is only invoked by _runExtension.
155 _postResponse(SendPort replyPort, 167 _postResponse(SendPort replyPort,
156 Object id, 168 Object id,
157 ServiceExtensionResponse response) { 169 ServiceExtensionResponse response) {
158 assert(replyPort != null); 170 assert(replyPort != null);
159 if (id == null) { 171 if (id == null) {
160 // No id -> no response. 172 // No id -> no response.
161 replyPort.send(null); 173 replyPort.send(null);
162 return; 174 return;
163 } 175 }
164 assert(id != null); 176 assert(id != null);
165 StringBuffer sb = new StringBuffer(); 177 StringBuffer sb = new StringBuffer();
166 sb.write('{"jsonrpc":"2.0",'); 178 sb.write('{"jsonrpc":"2.0",');
167 if (response._isError()) { 179 if (response._isError()) {
168 sb.write('"error":'); 180 sb.write('"error":');
169 } else { 181 } else {
170 sb.write('"result":'); 182 sb.write('"result":');
171 } 183 }
172 sb.write('${response._toString()},'); 184 sb.write('${response._toString()},');
173 if (id is String) { 185 if (id is String) {
174 sb.write('"id":"$id"}'); 186 sb.write('"id":"$id"}');
175 } else { 187 } else {
176 sb.write('"id":$id}'); 188 sb.write('"id":$id}');
177 } 189 }
178 replyPort.send(sb.toString()); 190 replyPort.send(sb.toString());
179 } 191 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/js_runtime/lib/developer_patch.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698