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

Side by Side Diff: tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate

Issue 2042033002: Add zone task support to http-requests. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix reviewer comments. Created 4 years, 6 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 $LIBRARYNAME; 5 part of $LIBRARYNAME;
6 6
7 /**
8 * A task specification for http requests.
9 *
10 * This specification is not available when an http request is sent through
11 * direct use of [HttpRequest.send]. See [HttpRequestSendTaskSpecification].
12 *
13 * A task created by this specification is a `Future<HttpRequest>`.
14 */
15 class HttpRequestTaskSpecification extends TaskSpecification {
16 /// The URL of the request.
17 final String url;
18
19 /// The method used to do the request.
20 ///
21 /// By default (when `null`) this is a `"GET"` request. Alternatively, the
22 /// method can be `"POST"`, `"PUT"`, `"DELETE"`, etc.
23 final String method;
24
25 /// Whether the request should send credentials. Credentials are only useful
26 /// for cross-origin requests.
27 ///
28 /// See [HttpRequest.request] for more information.
29 final bool withCredentials;
30
31 /// The desired response format.
32 ///
33 /// Supported types are:
34 /// - `""`: (same as `"text"`),
35 /// - `"arraybuffer"`,
36 /// - `"blob"`,
37 /// - `"document"`,
38 /// - `"json"`,
39 /// - `"text"`
40 ///
41 /// By default (when `null`) the desired format is `""`.
42 final String responseType;
43
44 /// The desired mime type.
45 ///
46 /// This overrides the default mime-type which is set up to transfer textual
47 /// data.
48 final String mimeType;
49
50 /// The request headers that should be sent with the request.
51 final Map<String, String> requestHeaders;
52
53 /// The data that is sent with the request.
54 ///
55 /// When provided (not `null`) must be a [ByteBuffer],
56 /// [Blob], [Document], [String], or [FormData].
57 final dynamic sendData;
58
59 /// The function that is invoked on progress updates. This function is
60 /// registered as an event listener on the created [HttpRequest] object, and
61 /// thus has its own task. Further invocations of the progress function do
62 /// *not* use the http-request task as task object.
63 ///
64 /// Creating an HTTP request automatically registers the on-progress listener.
65 final ZoneUnaryCallback<dynamic, ProgressEvent> onProgress;
66
67 HttpRequestTaskSpecification(this.url,
68 {String this.method, bool this.withCredentials, String this.responseType,
69 String this.mimeType, Map<String, String> this.requestHeaders,
70 this.sendData,
71 void this.onProgress(ProgressEvent e)});
72
73 String get name => "dart.html.http-request";
74 bool get isOneShot => true;
75 }
76
77 /**
78 * A task specification for http requests that are initiated through a direct
79 * invocation of [HttpRequest.send].
80 *
81 * This specification serves as signal to zones that an http request has been
82 * initiated. The created task is the [request] object itself, and
83 * no callback is ever executed in this task.
84 *
85 * Note that event listeners on the http request are also registered in the
86 * zone (although with their own task creations), and that a zone can thus
87 * detect when the http-request returns.
88 *
89 * HTTP requests that are initiated through `request` methods don't use
90 * this class but use [HttpRequestTaskSpecification].
91 */
92 class HttpRequestSendTaskSpecification extends TaskSpecification {
93 final HttpRequest request;
94 final dynamic sendData;
95
96 HttpRequestSendTaskSpecification(this.request, this.sendData);
97
98 String get name => "dart.html.http-request-send";
99
100 /**
101 * No callback is ever executed in an http-request send task.
102 */
103 bool get isOneShot => false;
104 }
105
7 /** 106 /**
8 * A client-side XHR request for getting data from a URL, 107 * A client-side XHR request for getting data from a URL,
9 * formally known as XMLHttpRequest. 108 * formally known as XMLHttpRequest.
10 * 109 *
11 * HttpRequest can be used to obtain data from HTTP and FTP protocols, 110 * HttpRequest can be used to obtain data from HTTP and FTP protocols,
12 * and is useful for AJAX-style page updates. 111 * and is useful for AJAX-style page updates.
13 * 112 *
14 * The simplest way to get the contents of a text file, such as a 113 * The simplest way to get the contents of a text file, such as a
15 * JSON-formatted file, is with [getString]. 114 * JSON-formatted file, is with [getString].
16 * For example, the following code gets the contents of a JSON file 115 * For example, the following code gets the contents of a JSON file
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 * with appropriate permissions in their manifest. Requests to file:// URIs 282 * with appropriate permissions in their manifest. Requests to file:// URIs
184 * will also never fail- the Future will always complete successfully, even 283 * will also never fail- the Future will always complete successfully, even
185 * when the file cannot be found. 284 * when the file cannot be found.
186 * 285 *
187 * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access _authentication). 286 * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access _authentication).
188 */ 287 */
189 static Future<HttpRequest> request(String url, 288 static Future<HttpRequest> request(String url,
190 {String method, bool withCredentials, String responseType, 289 {String method, bool withCredentials, String responseType,
191 String mimeType, Map<String, String> requestHeaders, sendData, 290 String mimeType, Map<String, String> requestHeaders, sendData,
192 void onProgress(ProgressEvent e)}) { 291 void onProgress(ProgressEvent e)}) {
292 var spec = new HttpRequestTaskSpecification(
293 url, method: method,
294 withCredentials: withCredentials,
295 responseType: responseType,
296 mimeType: mimeType,
297 requestHeaders: requestHeaders,
298 sendData: sendData,
299 onProgress: onProgress);
300
301 if (identical(Zone.current, Zone.ROOT)) {
302 return _createHttpRequestTask(spec, null);
303 }
304 return Zone.current.createTask(_createHttpRequestTask, spec);
305 }
306
307 static Future<HttpRequest> _createHttpRequestTask(
308 HttpRequestTaskSpecification spec, Zone zone) {
309 String url = spec.url;
310 String method = spec.method;
311 bool withCredentials = spec.withCredentials;
312 String responseType = spec.responseType;
313 String mimeType = spec.mimeType;
314 Map<String, String> requestHeaders = spec.requestHeaders;
315 var sendData = spec.sendData;
316 var onProgress = spec.onProgress;
317
193 var completer = new Completer<HttpRequest>(); 318 var completer = new Completer<HttpRequest>();
319 var task = completer.future;
194 320
195 var xhr = new HttpRequest(); 321 var xhr = new HttpRequest();
196 if (method == null) { 322 if (method == null) {
197 method = 'GET'; 323 method = 'GET';
198 } 324 }
199 xhr.open(method, url, async: true); 325 xhr.open(method, url, async: true);
200 326
201 if (withCredentials != null) { 327 if (withCredentials != null) {
202 xhr.withCredentials = withCredentials; 328 xhr.withCredentials = withCredentials;
203 } 329 }
(...skipping 19 matching lines...) Expand all
223 xhr.onLoad.listen((e) { 349 xhr.onLoad.listen((e) {
224 var accepted = xhr.status >= 200 && xhr.status < 300; 350 var accepted = xhr.status >= 200 && xhr.status < 300;
225 var fileUri = xhr.status == 0; // file:// URIs have status of 0. 351 var fileUri = xhr.status == 0; // file:// URIs have status of 0.
226 var notModified = xhr.status == 304; 352 var notModified = xhr.status == 304;
227 // Redirect status is specified up to 307, but others have been used in 353 // Redirect status is specified up to 307, but others have been used in
228 // practice. Notably Google Drive uses 308 Resume Incomplete for 354 // practice. Notably Google Drive uses 308 Resume Incomplete for
229 // resumable uploads, and it's also been used as a redirect. The 355 // resumable uploads, and it's also been used as a redirect. The
230 // redirect case will be handled by the browser before it gets to us, 356 // redirect case will be handled by the browser before it gets to us,
231 // so if we see it we should pass it through to the user. 357 // so if we see it we should pass it through to the user.
232 var unknownRedirect = xhr.status > 307 && xhr.status < 400; 358 var unknownRedirect = xhr.status > 307 && xhr.status < 400;
233 359
234 if (accepted || fileUri || notModified || unknownRedirect) { 360 var isSuccessful = accepted || fileUri || notModified || unknownRedirect;
361
362 if (zone == null && isSuccessful) {
235 completer.complete(xhr); 363 completer.complete(xhr);
364 } else if (zone == null) {
365 completer.completeError(e);
366 } else if (isSuccessful) {
367 zone.runTask((task, value) {
368 completer.complete(value);
369 }, task, xhr);
236 } else { 370 } else {
237 completer.completeError(e); 371 zone.runTask((task, error) {
372 completer.completeError(error);
373 }, task, e);
238 } 374 }
239 }); 375 });
240 376
241 xhr.onError.listen(completer.completeError); 377 if (zone == null) {
378 xhr.onError.listen(completer.completeError);
379 } else {
380 xhr.onError.listen((error) {
381 zone.runTask((task, error) {
382 completer.completeError(error);
383 }, task, error);
384 });
385 }
242 386
243 if (sendData != null) { 387 if (sendData != null) {
244 xhr.send(sendData); 388 // TODO(floitsch): should we go through 'send()' and have nested tasks?
389 xhr._send(sendData);
245 } else { 390 } else {
246 xhr.send(); 391 xhr._send();
247 } 392 }
248 393
249 return completer.future; 394 return task;
250 } 395 }
251 396
252 /** 397 /**
253 * Checks to see if the Progress event is supported on the current platform. 398 * Checks to see if the Progress event is supported on the current platform.
254 */ 399 */
255 static bool get supportsProgressEvent { 400 static bool get supportsProgressEvent {
256 $if DART2JS 401 $if DART2JS
257 var xhr = new HttpRequest(); 402 var xhr = new HttpRequest();
258 return JS('bool', '("onprogress" in #)', xhr); 403 return JS('bool', '("onprogress" in #)', xhr);
259 $else 404 $else
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 * cross-origin support is not required then [request] should be used instead. 454 * cross-origin support is not required then [request] should be used instead.
310 */ 455 */
311 @Experimental() 456 @Experimental()
312 static Future<String> requestCrossOrigin(String url, 457 static Future<String> requestCrossOrigin(String url,
313 {String method, String sendData}) { 458 {String method, String sendData}) {
314 if (supportsCrossOrigin) { 459 if (supportsCrossOrigin) {
315 return request(url, method: method, sendData: sendData).then((xhr) { 460 return request(url, method: method, sendData: sendData).then((xhr) {
316 return xhr.responseText; 461 return xhr.responseText;
317 }); 462 });
318 } 463 }
464 // TODO(floitsch): the following code doesn't go through task zones.
465 // Since 'XDomainRequest' is an IE9 feature we should probably just remove
466 // it.
319 $if DART2JS 467 $if DART2JS
320 var completer = new Completer<String>(); 468 var completer = new Completer<String>();
321 if (method == null) { 469 if (method == null) {
322 method = 'GET'; 470 method = 'GET';
323 } 471 }
324 var xhr = JS('var', 'new XDomainRequest()'); 472 var xhr = JS('var', 'new XDomainRequest()');
325 JS('', '#.open(#, #)', xhr, method, url); 473 JS('', '#.open(#, #)', xhr, method, url);
326 JS('', '#.onload = #', xhr, convertDartClosureToJS((e) { 474 JS('', '#.onload = #', xhr, convertDartClosureToJS((e) {
327 var response = JS('String', '#.responseText', xhr); 475 var response = JS('String', '#.responseText', xhr);
328 completer.complete(response); 476 completer.complete(response);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 * 537 *
390 * By default the request is done asyncronously, with no user or password 538 * By default the request is done asyncronously, with no user or password
391 * authentication information. If `async` is false, the request will be send 539 * authentication information. If `async` is false, the request will be send
392 * synchronously. 540 * synchronously.
393 * 541 *
394 * Calling `open` again on a currently active request is equivalent to 542 * Calling `open` again on a currently active request is equivalent to
395 * calling `abort`. 543 * calling `abort`.
396 * 544 *
397 * Note: Most simple HTTP requests can be accomplished using the [getString], 545 * Note: Most simple HTTP requests can be accomplished using the [getString],
398 * [request], [requestCrossOrigin], or [postFormData] methods. Use of this 546 * [request], [requestCrossOrigin], or [postFormData] methods. Use of this
399 * `open` method is intended only for more complext HTTP requests where 547 * `open` method is intended only for more complex HTTP requests where
400 * finer-grained control is needed. 548 * finer-grained control is needed.
401 */ 549 */
402 @DomName('XMLHttpRequest.open') 550 @DomName('XMLHttpRequest.open')
403 @DocsEditable() 551 @DocsEditable()
404 $if JSINTEROP 552 $if JSINTEROP
405 void open(String method, String url, {bool async, String user, String password }) { 553 void open(String method, String url, {bool async, String user, String password }) {
406 if (async == null && user == null && password == null) { 554 if (async == null && user == null && password == null) {
407 _blink.BlinkXMLHttpRequest.instance.open_Callback_2_(this, method, url); 555 _blink.BlinkXMLHttpRequest.instance.open_Callback_2_(this, method, url);
408 } else { 556 } else {
409 _blink.BlinkXMLHttpRequest.instance.open_Callback_5_(this, method, url, as ync, user, password); 557 _blink.BlinkXMLHttpRequest.instance.open_Callback_5_(this, method, url, as ync, user, password);
410 } 558 }
411 } 559 }
412 $else 560 $else
413 void open(String method, String url, {bool async, String user, String password }) native; 561 void open(String method, String url, {bool async, String user, String password }) native;
414 $endif 562 $endif
415 563
564 /**
565 * Sends the request with any given `data`.
566 *
567 * Note: Most simple HTTP requests can be accomplished using the [getString],
568 * [request], [requestCrossOrigin], or [postFormData] methods. Use of this
569 * `send` method is intended only for more complex HTTP requests where
570 * finer-grained control is needed.
571 *
572 * ## Other resources
573 *
574 * * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHtt pRequest#send%28%29)
575 * from MDN.
576 */
577 @DomName('XMLHttpRequest.send')
578 @DocsEditable()
579 void send([body_OR_data]) {
580 if (identical(Zone.current, Zone.ROOT)) {
581 _send(body_OR_data);
582 } else {
583 Zone.current.createTask(_createHttpRequestSendTask,
584 new HttpRequestSendTaskSpecification(this, body_OR_data));
585 }
586 }
587
588 static HttpRequest _createHttpRequestSendTask(
589 HttpRequestSendTaskSpecification spec, Zone zone) {
590 spec.request._send(spec.sendData);
591 return spec.request;
592 }
593
416 $!MEMBERS 594 $!MEMBERS
417 } 595 }
OLDNEW
« tests/html/xhr_task2_test.dart ('K') | « tools/dom/scripts/htmlrenamer.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698