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

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, 4 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
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) {
Ivan Posva 2015/08/26 04:47:00 Can you clear/remove an extension by registering a
Cutch 2015/08/26 14:28:00 No. Registering a null handler is not allowed by t
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 external ServiceExtensionHandler _lookupExtension(String method);
106 List<String> parameterKeys, 109 external _registerExtension(String method, ServiceExtensionHandler handler);
107 List<String> parameterValues, 110
108 SendPort replyPort, 111 // This code is only invoked when there is no other Dart code on the stack.
109 Object id) { 112 _runExtension(ServiceExtensionHandler handler,
110 ServiceExtensionHandler handler = _extensions[method]; 113 String method,
111 if (handler == null) { 114 List<String> parameterKeys,
112 return false; 115 List<String> parameterValues,
116 SendPort replyPort,
117 Object id) {
118 var parameters = {};
119 for (var i = 0; i < parameterKeys.length; i++) {
120 parameters[parameterKeys[i]] = parameterValues[i];
113 } 121 }
114 // Defer execution of handler until next event loop. 122 var response;
115 Timer.run(() { 123 try {
116 var parameters = {}; 124 response = handler(method, parameters);
117 for (var i = 0; i < parameterKeys.length; i++) { 125 } catch (e, st) {
118 parameters[parameterKeys[i]] = parameterValues[i]; 126 var errorDetails = (st == null) ? '$e' : '$e\n$st';
119 } 127 response = new ServiceExtensionResponse.error(
120 var response; 128 ServiceExtensionResponse.kExtensionError,
121 try { 129 errorDetails);
122 response = handler(method, parameters); 130 _postResponse(replyPort, id, response);
123 } catch (e, st) { 131 return;
124 var errorDetails = (st == null) ? '$e' : '$e\n$st'; 132 }
133 if (response is! Future) {
134 response = new ServiceExtensionResponse.error(
135 ServiceExtensionResponse.kExtensionError,
136 "Extension handler must return a Future");
137 _postResponse(replyPort, id, response);
138 return;
139 }
140 response.catchError((e, st) {
Ivan Posva 2015/08/26 04:47:00 Usually I would expect to chain this in a normal t
Cutch 2015/08/26 14:28:00 I'm eagerly catching errors and wrapping them in a
141 var errorDetails = (st == null) ? '$e' : '$e\n$st';
142 return new ServiceExtensionResponse.error(
143 ServiceExtensionResponse.kExtensionError,
144 errorDetails);
145 }).then((response) {
146 if (response == null) {
125 response = new ServiceExtensionResponse.error( 147 response = new ServiceExtensionResponse.error(
126 ServiceExtensionResponse.kExtensionError, 148 ServiceExtensionResponse.kExtensionError,
127 errorDetails); 149 "Extension handler returned null");
128 _postResponse(replyPort, id, response);
129 return;
130 } 150 }
131 if (response is! Future) { 151 _postResponse(replyPort, id, response);
132 response = new ServiceExtensionResponse.error(
133 ServiceExtensionResponse.kExtensionError,
134 "Extension handler must return a Future");
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 }); 152 });
152 return true;
153 } 153 }
154 154
155 // This code is only invoked by _runExtension.
155 _postResponse(SendPort replyPort, 156 _postResponse(SendPort replyPort,
156 Object id, 157 Object id,
157 ServiceExtensionResponse response) { 158 ServiceExtensionResponse response) {
158 assert(replyPort != null); 159 assert(replyPort != null);
159 if (id == null) { 160 if (id == null) {
160 // No id -> no response. 161 // No id -> no response.
161 replyPort.send(null); 162 replyPort.send(null);
162 return; 163 return;
163 } 164 }
164 assert(id != null); 165 assert(id != null);
165 StringBuffer sb = new StringBuffer(); 166 StringBuffer sb = new StringBuffer();
166 sb.write('{"jsonrpc":"2.0",'); 167 sb.write('{"jsonrpc":"2.0",');
167 if (response._isError()) { 168 if (response._isError()) {
168 sb.write('"error":'); 169 sb.write('"error":');
169 } else { 170 } else {
170 sb.write('"result":'); 171 sb.write('"result":');
171 } 172 }
172 sb.write('${response._toString()},'); 173 sb.write('${response._toString()},');
173 if (id is String) { 174 if (id is String) {
174 sb.write('"id":"$id"}'); 175 sb.write('"id":"$id"}');
175 } else { 176 } else {
176 sb.write('"id":$id}'); 177 sb.write('"id":$id}');
177 } 178 }
178 replyPort.send(sb.toString()); 179 replyPort.send(sb.toString());
179 } 180 }
OLDNEW
« runtime/vm/isolate.h ('K') | « 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