Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 final String url; | |
|
Lasse Reichstein Nielsen
2016/06/08 09:40:28
Document fields (e.g., by referencing the XmlHttpR
floitsch
2016/06/10 15:46:57
Done.
| |
| 17 final String method; | |
| 18 final bool withCredentials; | |
| 19 final String responseType; | |
| 20 final String mimeType; | |
| 21 final Map<String, String> requestHeaders; | |
| 22 final dynamic sendData; | |
| 23 /** | |
| 24 * The function that is invoked on progress updates. This function is *not* | |
| 25 * executed as part of the http-request task, but as an event callback. | |
|
Lasse Reichstein Nielsen
2016/06/08 09:40:28
I don't understand what it means to be "part of th
floitsch
2016/06/10 15:46:57
Done.
| |
| 26 * | |
| 27 * Creating an http-request automatically registers the on-progress listener. | |
| 28 */ | |
| 29 final ZoneUnaryCallback<dynamic, ProgressEvent> onProgress; | |
| 30 | |
| 31 HttpRequestTaskSpecification(this.url, | |
| 32 {String this.method, bool this.withCredentials, String this.responseType, | |
| 33 String this.mimeType, Map<String, String> this.requestHeaders, | |
| 34 this.sendData, | |
| 35 void this.onProgress(ProgressEvent e)}); | |
| 36 | |
| 37 String get name => "dart.html.http-request"; | |
| 38 bool get isOneShot => true; | |
| 39 } | |
| 40 | |
| 41 /** | |
| 42 * A task specification for http requests that are initiated through a direct | |
| 43 * invocation of [HttpRequest.send]. | |
| 44 * | |
| 45 * This specification serves as signal to zones that an http request has been | |
|
Lasse Reichstein Nielsen
2016/06/08 09:40:28
http -> HTTP
acronym, dittos below.
floitsch
2016/06/10 15:46:57
Done.
| |
| 46 * initiated. The created task is the [request] object itself, and | |
| 47 * no callback is ever executed in this task. When the http request gets | |
| 48 * data event-listeners that have the request object as event target are | |
|
Lasse Reichstein Nielsen
2016/06/08 09:40:28
commas in this sentence? I have a hard time parsin
floitsch
2016/06/10 15:46:57
Reworded.
Done.
| |
| 49 * executed. | |
| 50 * | |
| 51 * Http requests that are initiated through `request` methods don't use | |
| 52 * this class but use [HttpRequestTaskSpecification]. | |
| 53 */ | |
| 54 class HttpRequestSendTaskSpecification extends TaskSpecification { | |
| 55 final HttpRequest request; | |
| 56 final dynamic sendData; | |
| 57 | |
| 58 HttpRequestSendTaskSpecification(this.request, this.sendData); | |
| 59 | |
| 60 String get name => "dart.html.http-request-send"; | |
| 61 | |
| 62 /** | |
| 63 * No callback is ever executed in an http-request send task. | |
| 64 */ | |
| 65 bool get isOneShot => false; | |
| 66 } | |
| 67 | |
| 7 /** | 68 /** |
| 8 * A client-side XHR request for getting data from a URL, | 69 * A client-side XHR request for getting data from a URL, |
| 9 * formally known as XMLHttpRequest. | 70 * formally known as XMLHttpRequest. |
| 10 * | 71 * |
| 11 * HttpRequest can be used to obtain data from HTTP and FTP protocols, | 72 * HttpRequest can be used to obtain data from HTTP and FTP protocols, |
| 12 * and is useful for AJAX-style page updates. | 73 * and is useful for AJAX-style page updates. |
| 13 * | 74 * |
| 14 * The simplest way to get the contents of a text file, such as a | 75 * The simplest way to get the contents of a text file, such as a |
| 15 * JSON-formatted file, is with [getString]. | 76 * JSON-formatted file, is with [getString]. |
| 16 * For example, the following code gets the contents of a JSON file | 77 * For example, the following code gets the contents of a JSON file |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 183 * with appropriate permissions in their manifest. Requests to file:// URIs | 244 * with appropriate permissions in their manifest. Requests to file:// URIs |
| 184 * will also never fail- the Future will always complete successfully, even | 245 * will also never fail- the Future will always complete successfully, even |
| 185 * when the file cannot be found. | 246 * when the file cannot be found. |
| 186 * | 247 * |
| 187 * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access _authentication). | 248 * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access _authentication). |
| 188 */ | 249 */ |
| 189 static Future<HttpRequest> request(String url, | 250 static Future<HttpRequest> request(String url, |
| 190 {String method, bool withCredentials, String responseType, | 251 {String method, bool withCredentials, String responseType, |
| 191 String mimeType, Map<String, String> requestHeaders, sendData, | 252 String mimeType, Map<String, String> requestHeaders, sendData, |
| 192 void onProgress(ProgressEvent e)}) { | 253 void onProgress(ProgressEvent e)}) { |
| 254 var spec = new HttpRequestTaskSpecification( | |
| 255 url, method: method, | |
| 256 withCredentials: withCredentials, | |
| 257 responseType: responseType, | |
| 258 mimeType: mimeType, | |
| 259 requestHeaders: requestHeaders, | |
| 260 sendData: sendData, | |
| 261 onProgress: onProgress); | |
| 262 | |
| 263 if (identical(Zone.current, Zone.ROOT)) { | |
| 264 return _createHttpRequestTask(spec, null); | |
| 265 } | |
| 266 return Zone.current.createTask(_createHttpRequestTask, spec); | |
| 267 } | |
| 268 | |
| 269 static Future<HttpRequest> _createHttpRequestTask( | |
| 270 HttpRequestTaskSpecification spec, Zone zone) { | |
| 271 String url = spec.url; | |
| 272 String method = spec.method; | |
| 273 bool withCredentials = spec.withCredentials; | |
| 274 String responseType = spec.responseType; | |
| 275 String mimeType = spec.mimeType; | |
| 276 Map<String, String> requestHeaders = spec.requestHeaders; | |
| 277 var sendData = spec.sendData; | |
| 278 var onProgress = spec.onProgress; | |
| 279 | |
| 193 var completer = new Completer<HttpRequest>(); | 280 var completer = new Completer<HttpRequest>(); |
| 281 var task = completer.future; | |
| 194 | 282 |
| 195 var xhr = new HttpRequest(); | 283 var xhr = new HttpRequest(); |
| 196 if (method == null) { | 284 if (method == null) { |
| 197 method = 'GET'; | 285 method = 'GET'; |
| 198 } | 286 } |
| 199 xhr.open(method, url, async: true); | 287 xhr.open(method, url, async: true); |
| 200 | 288 |
| 201 if (withCredentials != null) { | 289 if (withCredentials != null) { |
| 202 xhr.withCredentials = withCredentials; | 290 xhr.withCredentials = withCredentials; |
| 203 } | 291 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 223 xhr.onLoad.listen((e) { | 311 xhr.onLoad.listen((e) { |
| 224 var accepted = xhr.status >= 200 && xhr.status < 300; | 312 var accepted = xhr.status >= 200 && xhr.status < 300; |
| 225 var fileUri = xhr.status == 0; // file:// URIs have status of 0. | 313 var fileUri = xhr.status == 0; // file:// URIs have status of 0. |
| 226 var notModified = xhr.status == 304; | 314 var notModified = xhr.status == 304; |
| 227 // Redirect status is specified up to 307, but others have been used in | 315 // Redirect status is specified up to 307, but others have been used in |
| 228 // practice. Notably Google Drive uses 308 Resume Incomplete for | 316 // practice. Notably Google Drive uses 308 Resume Incomplete for |
| 229 // resumable uploads, and it's also been used as a redirect. The | 317 // 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, | 318 // 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. | 319 // so if we see it we should pass it through to the user. |
| 232 var unknownRedirect = xhr.status > 307 && xhr.status < 400; | 320 var unknownRedirect = xhr.status > 307 && xhr.status < 400; |
| 233 | 321 |
| 234 if (accepted || fileUri || notModified || unknownRedirect) { | 322 var isSuccessful = accepted || fileUri || notModified || unknownRedirect; |
| 323 | |
| 324 if (zone == null && isSuccessful) { | |
| 235 completer.complete(xhr); | 325 completer.complete(xhr); |
| 326 } else if (zone == null) { | |
| 327 completer.completeError(e); | |
| 328 } else if (isSuccessful) { | |
| 329 zone.runTask((task, value) { | |
| 330 completer.complete(value); | |
| 331 }, task, xhr); | |
| 236 } else { | 332 } else { |
| 237 completer.completeError(e); | 333 zone.runTask((task, error) { |
| 334 completer.completeError(error); | |
| 335 }, task, e); | |
| 238 } | 336 } |
| 239 }); | 337 }); |
| 240 | 338 |
| 241 xhr.onError.listen(completer.completeError); | 339 if (zone == null) { |
| 340 xhr.onError.listen(completer.completeError); | |
| 341 } else { | |
| 342 xhr.onError.listen((error) { | |
| 343 zone.runTask((task, error) { | |
| 344 completer.completeError(error); | |
| 345 }, task, error); | |
| 346 }); | |
| 347 } | |
| 242 | 348 |
| 243 if (sendData != null) { | 349 if (sendData != null) { |
| 244 xhr.send(sendData); | 350 // TODO(floitsch): should we go through 'send()' and have nested tasks? |
| 351 xhr._send(sendData); | |
| 245 } else { | 352 } else { |
| 246 xhr.send(); | 353 xhr._send(); |
| 247 } | 354 } |
| 248 | 355 |
| 249 return completer.future; | 356 return task; |
| 250 } | 357 } |
| 251 | 358 |
| 252 /** | 359 /** |
| 253 * Checks to see if the Progress event is supported on the current platform. | 360 * Checks to see if the Progress event is supported on the current platform. |
| 254 */ | 361 */ |
| 255 static bool get supportsProgressEvent { | 362 static bool get supportsProgressEvent { |
| 256 $if DART2JS | 363 $if DART2JS |
| 257 var xhr = new HttpRequest(); | 364 var xhr = new HttpRequest(); |
| 258 return JS('bool', '("onprogress" in #)', xhr); | 365 return JS('bool', '("onprogress" in #)', xhr); |
| 259 $else | 366 $else |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 * cross-origin support is not required then [request] should be used instead. | 416 * cross-origin support is not required then [request] should be used instead. |
| 310 */ | 417 */ |
| 311 @Experimental() | 418 @Experimental() |
| 312 static Future<String> requestCrossOrigin(String url, | 419 static Future<String> requestCrossOrigin(String url, |
| 313 {String method, String sendData}) { | 420 {String method, String sendData}) { |
| 314 if (supportsCrossOrigin) { | 421 if (supportsCrossOrigin) { |
| 315 return request(url, method: method, sendData: sendData).then((xhr) { | 422 return request(url, method: method, sendData: sendData).then((xhr) { |
| 316 return xhr.responseText; | 423 return xhr.responseText; |
| 317 }); | 424 }); |
| 318 } | 425 } |
| 426 // TODO(floitsch): the following code doesn't go through task zones. | |
| 427 // Since 'XDomainRequest' is an IE9 feature we should probably just remove | |
| 428 // it. | |
| 319 $if DART2JS | 429 $if DART2JS |
| 320 var completer = new Completer<String>(); | 430 var completer = new Completer<String>(); |
| 321 if (method == null) { | 431 if (method == null) { |
| 322 method = 'GET'; | 432 method = 'GET'; |
| 323 } | 433 } |
| 324 var xhr = JS('var', 'new XDomainRequest()'); | 434 var xhr = JS('var', 'new XDomainRequest()'); |
| 325 JS('', '#.open(#, #)', xhr, method, url); | 435 JS('', '#.open(#, #)', xhr, method, url); |
| 326 JS('', '#.onload = #', xhr, convertDartClosureToJS((e) { | 436 JS('', '#.onload = #', xhr, convertDartClosureToJS((e) { |
| 327 var response = JS('String', '#.responseText', xhr); | 437 var response = JS('String', '#.responseText', xhr); |
| 328 completer.complete(response); | 438 completer.complete(response); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 389 * | 499 * |
| 390 * By default the request is done asyncronously, with no user or password | 500 * By default the request is done asyncronously, with no user or password |
| 391 * authentication information. If `async` is false, the request will be send | 501 * authentication information. If `async` is false, the request will be send |
| 392 * synchronously. | 502 * synchronously. |
| 393 * | 503 * |
| 394 * Calling `open` again on a currently active request is equivalent to | 504 * Calling `open` again on a currently active request is equivalent to |
| 395 * calling `abort`. | 505 * calling `abort`. |
| 396 * | 506 * |
| 397 * Note: Most simple HTTP requests can be accomplished using the [getString], | 507 * Note: Most simple HTTP requests can be accomplished using the [getString], |
| 398 * [request], [requestCrossOrigin], or [postFormData] methods. Use of this | 508 * [request], [requestCrossOrigin], or [postFormData] methods. Use of this |
| 399 * `open` method is intended only for more complext HTTP requests where | 509 * `open` method is intended only for more complex HTTP requests where |
| 400 * finer-grained control is needed. | 510 * finer-grained control is needed. |
| 401 */ | 511 */ |
| 402 @DomName('XMLHttpRequest.open') | 512 @DomName('XMLHttpRequest.open') |
| 403 @DocsEditable() | 513 @DocsEditable() |
| 404 $if JSINTEROP | 514 $if JSINTEROP |
| 405 void open(String method, String url, {bool async, String user, String password }) { | 515 void open(String method, String url, {bool async, String user, String password }) { |
| 406 if (async == null && user == null && password == null) { | 516 if (async == null && user == null && password == null) { |
| 407 _blink.BlinkXMLHttpRequest.instance.open_Callback_2_(this, method, url); | 517 _blink.BlinkXMLHttpRequest.instance.open_Callback_2_(this, method, url); |
| 408 } else { | 518 } else { |
| 409 _blink.BlinkXMLHttpRequest.instance.open_Callback_5_(this, method, url, as ync, user, password); | 519 _blink.BlinkXMLHttpRequest.instance.open_Callback_5_(this, method, url, as ync, user, password); |
| 410 } | 520 } |
| 411 } | 521 } |
| 412 $else | 522 $else |
| 413 void open(String method, String url, {bool async, String user, String password }) native; | 523 void open(String method, String url, {bool async, String user, String password }) native; |
| 414 $endif | 524 $endif |
| 415 | 525 |
| 526 /** | |
| 527 * Sends the request with any given `data`. | |
| 528 * | |
| 529 * Note: Most simple HTTP requests can be accomplished using the [getString], | |
| 530 * [request], [requestCrossOrigin], or [postFormData] methods. Use of this | |
| 531 * `send` method is intended only for more complex HTTP requests where | |
| 532 * finer-grained control is needed. | |
| 533 * | |
| 534 * ## Other resources | |
| 535 * | |
| 536 * * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHtt pRequest#send%28%29) | |
| 537 * from MDN. | |
| 538 */ | |
| 539 @DomName('XMLHttpRequest.send') | |
| 540 @DocsEditable() | |
| 541 void send([body_OR_data]) { | |
| 542 if (identical(Zone.current, Zone.ROOT)) { | |
| 543 _send(body_OR_data); | |
| 544 } else { | |
| 545 Zone.current.createTask(_createHttpRequestSendTask, | |
| 546 new HttpRequestSendTaskSpecification(this, body_OR_data)); | |
| 547 } | |
| 548 } | |
| 549 | |
| 550 static HttpRequest _createHttpRequestSendTask( | |
| 551 HttpRequestSendTaskSpecification spec, Zone zone) { | |
| 552 spec.request._send(spec.sendData); | |
| 553 return spec.request; | |
| 554 } | |
| 555 | |
| 416 $!MEMBERS | 556 $!MEMBERS |
| 417 } | 557 } |
| OLD | NEW |