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

Side by Side Diff: pkg/analysis_server/lib/src/protocol.dart

Issue 245113006: Consistently type check analysis server request parameters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library protocol; 5 library protocol;
6 6
7 import 'dart:convert' show JsonDecoder; 7 import 'dart:convert' show JsonDecoder;
8 8
9 /** 9 /**
10 * Instances of the class [Request] represent a request that was received. 10 * Instances of the class [Request] represent a request that was received.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 } else if (params != null) { 87 } else if (params != null) {
88 return null; 88 return null;
89 } 89 }
90 return request; 90 return request;
91 } catch (exception) { 91 } catch (exception) {
92 return null; 92 return null;
93 } 93 }
94 } 94 }
95 95
96 /** 96 /**
97 * Return the value of the parameter with the given [name], or `null` if there 97 * Return the value of the parameter with the given [name], or defaultValue
Brian Wilkerson 2014/04/21 22:12:32 "defaultValue" --> "[defaultValue]"
Paul Berry 2014/04/21 22:22:21 Done.
98 * is no such parameter associated with this request. 98 * if there is no such parameter associated with this request.
99 */ 99 */
100 Object getParameter(String name) => params[name]; 100 RequestDatum getParameter(String name, dynamic defaultValue) {
Brian Wilkerson 2014/04/21 22:12:32 Do we want a default default value, such as Requ
Paul Berry 2014/04/21 22:22:21 I don't know. Currently there's not really a need
101 Object value = params[name];
102 if (value == null) {
103 return new RequestDatum(this, "default for $name", defaultValue);
104 }
105 return new RequestDatum(this, name, params[name]);
106 }
101 107
102 /** 108 /**
103 * Return the value of the parameter with the given [name], or throw a 109 * Return the value of the parameter with the given [name], or throw a
104 * [RequestFailure] exception with an appropriate error message if there is no 110 * [RequestFailure] exception with an appropriate error message if there is no
105 * such parameter associated with this request. 111 * such parameter associated with this request.
106 */ 112 */
107 Object getRequiredParameter(String name) { 113 RequestDatum getRequiredParameter(String name) {
108 Object value = params[name]; 114 Object value = params[name];
109 if (value == null) { 115 if (value == null) {
110 throw new RequestFailure(new Response.missingRequiredParameter(this, name) ); 116 throw new RequestFailure(new Response.missingRequiredParameter(this, name) );
111 } 117 }
112 return value; 118 return new RequestDatum(this, name, value);
113 } 119 }
114 120
115 /** 121 /**
116 * Set the value of the parameter with the given [name] to the given [value]. 122 * Set the value of the parameter with the given [name] to the given [value].
117 */ 123 */
118 void setParameter(String name, Object value) { 124 void setParameter(String name, Object value) {
119 params[name] = value; 125 params[name] = value;
120 } 126 }
121 127
122 /** 128 /**
123 * Convert the given [value] to a boolean, or throw a [RequestFailure]
124 * exception if the [value] could not be converted.
125 *
126 * The value is typically the result of invoking either [getParameter] or
127 * [getRequiredParameter].
128 */
129 bool toBool(Object value) {
130 if (value is bool) {
131 return value;
132 } else if (value is String) {
133 return value == 'true';
134 }
135 throw new RequestFailure(new Response.expectedBoolean(this, value));
136 }
137
138 /**
139 * Convert the given [value] to an integer, or throw a [RequestFailure]
140 * exception if the [value] could not be converted.
141 *
142 * The value is typically the result of invoking either [getParameter] or
143 * [getRequiredParameter].
144 */
145 int toInt(Object value) {
146 if (value is int) {
147 return value;
148 } else if (value is String) {
149 return int.parse(value, onError: (String value) {
150 throw new RequestFailure(new Response.expectedInteger(this, value));
151 });
152 }
153 throw new RequestFailure(new Response.expectedInteger(this, value));
154 }
155
156 /**
157 * Return a table representing the structure of the Json object that will be 129 * Return a table representing the structure of the Json object that will be
158 * sent to the client to represent this response. 130 * sent to the client to represent this response.
159 */ 131 */
160 Map<String, Object> toJson() { 132 Map<String, Object> toJson() {
161 Map<String, Object> jsonObject = new Map<String, Object>(); 133 Map<String, Object> jsonObject = new Map<String, Object>();
162 jsonObject[ID] = id; 134 jsonObject[ID] = id;
163 jsonObject[METHOD] = method; 135 jsonObject[METHOD] = method;
164 if (params.isNotEmpty) { 136 if (params.isNotEmpty) {
165 jsonObject[PARAMS] = params; 137 jsonObject[PARAMS] = params;
166 } 138 }
167 return jsonObject; 139 return jsonObject;
168 } 140 }
169 } 141 }
170 142
143 /**
144 * Instances of the class [RequestDatum] wrap a piece of data from a
145 * request parameter, and contain accessor methods which automatically validate
146 * and convert the data into the appropriate form.
147 */
148 class RequestDatum {
149 /**
150 * Request object that should be referred to in any errors that are
151 * generated.
152 */
153 final Request request;
154
155 /**
156 * String description of how [datum] was obtained from the request.
157 */
158 final String path;
159
160 /**
161 * Value to be decoded and validated.
162 */
163 final dynamic datum;
164
165 /**
166 * Create a RequestDatum for decoding and validating [datum], which refers to
167 * [request] in any errors it reports.
168 */
169 RequestDatum(this.request, this.path, this.datum);
170
171 /**
172 * Validate that the datum is a Map containing the given [key], and return
173 * a [RequestDatum] containing the corresponding value.
174 */
175 RequestDatum operator [](String key) {
176 if (datum is! Map<String, dynamic>) {
177 throw new RequestFailure(new Response.invalidParameter(request, path,
178 "be a map"));
179 }
180 if (!datum.containsKey(key)) {
181 throw new RequestFailure(new Response.invalidParameter(request, path,
182 "contain key '$key'"));
183 }
184 return new RequestDatum(request, "$path.$key", datum[key]);
185 }
186
187 /**
188 * Validate that the datum is a Map whose keys are strings, and call [f] on
189 * each key/value pair in the map.
190 */
191 void forEachMap(void f(String key, RequestDatum value)) {
192 if (datum is! Map<String, dynamic>) {
193 throw new RequestFailure(new Response.invalidParameter(request, path,
194 "be a map"));
195 }
196 datum.forEach((String key, dynamic value) {
197 f(key, new RequestDatum(request, "$path.$key", value));
198 });
199 }
200
201 /**
202 * Validate that the datum is an integer (or a string that can be parsed
203 * as an integer), and return the int.
204 */
205 int asInt() {
206 if (datum is int) {
207 return datum;
208 } else if (datum is String) {
209 return int.parse(datum, onError: (String value) {
210 throw new RequestFailure(new Response.invalidParameter(request, path,
211 "be an integer"));
212 });
213 }
214 throw new RequestFailure(new Response.invalidParameter(request, path,
215 "be an integer"));
216 }
217
218 /**
219 * Validate that the datum is a boolean (or a string that can be parsed
220 * as a boolean), and return the bool.
221 *
222 * The value is typically the result of invoking either [getParameter] or
223 * [getRequiredParameter].
224 */
225 bool asBool() {
226 if (datum is bool) {
227 return datum;
228 } else if (datum == 'true') {
229 return datum == 'true';
230 } else if (datum == 'false') {
231 return datum == 'false';
232 }
233 throw new RequestFailure(new Response.invalidParameter(request, datum,
234 "be a boolean"));
235 }
236
237 /**
238 * Validate that the datum is a string, and return it.
239 */
240 String asString() {
241 if (datum is! String) {
242 throw new RequestFailure(new Response.invalidParameter(request, path,
243 "be a string"));
244 }
245 return datum;
246 }
247
248 /**
249 * Validate that the datum is a list of strings, and return it.
250 */
251 List<String> asStringList() {
252 if (datum is! List<String>) {
253 throw new RequestFailure(new Response.invalidParameter(request, path,
254 "be a list of strings"));
255 }
256 return datum;
257 }
258
259 /**
260 * Validate that the datum is a map from strings to strings, and return it.
261 */
262 Map<String, String> asStringMap() {
263 if (datum is! Map<String, String>) {
264 throw new RequestFailure(new Response.invalidParameter(request, path,
265 "be a string map"));
266 }
267 return datum;
268 }
269 }
270
171 /** 271 /**
172 * Instances of the class [Response] represent a response to a request. 272 * Instances of the class [Response] represent a response to a request.
173 */ 273 */
174 class Response { 274 class Response {
175 /** 275 /**
176 * The name of the JSON attribute containing the id of the request for which 276 * The name of the JSON attribute containing the id of the request for which
177 * this is a response. 277 * this is a response.
178 */ 278 */
179 static const String ID = 'id'; 279 static const String ID = 'id';
180 280
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 315
216 /** 316 /**
217 * Initialize a newly created instance to represent an error condition caused 317 * Initialize a newly created instance to represent an error condition caused
218 * by a [request] referencing a context that does not exist. 318 * by a [request] referencing a context that does not exist.
219 */ 319 */
220 Response.contextDoesNotExist(Request request) 320 Response.contextDoesNotExist(Request request)
221 : this(request.id, new RequestError(-1, 'Context does not exist')); 321 : this(request.id, new RequestError(-1, 'Context does not exist'));
222 322
223 /** 323 /**
224 * Initialize a newly created instance to represent an error condition caused 324 * Initialize a newly created instance to represent an error condition caused
225 * by a [request] that was expected to have a boolean-valued parameter but was 325 * by a [request] that had invalid parameter. [path] is the path to the
226 * passed a non-boolean value. 326 * invalid parameter, in Javascript notation (e.g. "foo.bar" means that the
327 * parameter "foo" contained a key "bar" whose value was the wrong type).
328 * [expectation] is a description of the type of data that was expected.
227 */ 329 */
228 Response.expectedBoolean(Request request, Object value) 330 Response.invalidParameter(Request request, String path, String expectation)
229 : this(request.id, new RequestError(-2, 'Expected a boolean value, but found "$value"')); 331 : this(request.id, new RequestError(-2,
332 "Expected parameter $path to $expectation"));
230 333
231 /** 334 /**
232 * Initialize a newly created instance to represent an error condition caused 335 * Initialize a newly created instance to represent an error condition caused
233 * by a [request] that was expected to have a integer-valued parameter but was
234 * passed a non-integer value.
235 */
236 Response.expectedInteger(Request request, Object value)
237 : this(request.id, new RequestError(-3, 'Expected an integer value, but foun d "$value"'));
238
239 /**
240 * Initialize a newly created instance to represent an error condition caused
241 * by a malformed request. 336 * by a malformed request.
242 */ 337 */
243 Response.invalidRequestFormat() 338 Response.invalidRequestFormat()
244 : this('', new RequestError(-4, 'Invalid request')); 339 : this('', new RequestError(-4, 'Invalid request'));
245 340
246 /** 341 /**
247 * Initialize a newly created instance to represent an error condition caused 342 * Initialize a newly created instance to represent an error condition caused
248 * by a [request] that does not have a required parameter. 343 * by a [request] that does not have a required parameter.
249 */ 344 */
250 Response.missingRequiredParameter(Request request, String parameterName) 345 Response.missingRequiredParameter(Request request, String parameterName)
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 /** 695 /**
601 * The response to be returned as a result of the failure. 696 * The response to be returned as a result of the failure.
602 */ 697 */
603 final Response response; 698 final Response response;
604 699
605 /** 700 /**
606 * Initialize a newly created exception to return the given reponse. 701 * Initialize a newly created exception to return the given reponse.
607 */ 702 */
608 RequestFailure(this.response); 703 RequestFailure(this.response);
609 } 704 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/src/domain_server.dart ('k') | pkg/analysis_server/test/domain_context_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698