Index: tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate |
diff --git a/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate b/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate |
index 9ad00f61c2c2053f97c229ee85a0ffa0b1dd0b83..e586de83cda8264ba47f31efc28e7ac9aea7dc55 100644 |
--- a/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate |
+++ b/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate |
@@ -4,6 +4,67 @@ |
part of $LIBRARYNAME; |
+/** |
+ * A task specification for http requests. |
+ * |
+ * This specification is not available when an http request is sent through |
+ * direct use of [HttpRequest.send]. See [HttpRequestSendTaskSpecification]. |
+ * |
+ * A task created by this specification is a `Future<HttpRequest>`. |
+ */ |
+class HttpRequestTaskSpecification extends TaskSpecification { |
+ 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.
|
+ final String method; |
+ final bool withCredentials; |
+ final String responseType; |
+ final String mimeType; |
+ final Map<String, String> requestHeaders; |
+ final dynamic sendData; |
+ /** |
+ * The function that is invoked on progress updates. This function is *not* |
+ * 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.
|
+ * |
+ * Creating an http-request automatically registers the on-progress listener. |
+ */ |
+ final ZoneUnaryCallback<dynamic, ProgressEvent> onProgress; |
+ |
+ HttpRequestTaskSpecification(this.url, |
+ {String this.method, bool this.withCredentials, String this.responseType, |
+ String this.mimeType, Map<String, String> this.requestHeaders, |
+ this.sendData, |
+ void this.onProgress(ProgressEvent e)}); |
+ |
+ String get name => "dart.html.http-request"; |
+ bool get isOneShot => true; |
+} |
+ |
+/** |
+ * A task specification for http requests that are initiated through a direct |
+ * invocation of [HttpRequest.send]. |
+ * |
+ * 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.
|
+ * initiated. The created task is the [request] object itself, and |
+ * no callback is ever executed in this task. When the http request gets |
+ * 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.
|
+ * executed. |
+ * |
+ * Http requests that are initiated through `request` methods don't use |
+ * this class but use [HttpRequestTaskSpecification]. |
+ */ |
+class HttpRequestSendTaskSpecification extends TaskSpecification { |
+ final HttpRequest request; |
+ final dynamic sendData; |
+ |
+ HttpRequestSendTaskSpecification(this.request, this.sendData); |
+ |
+ String get name => "dart.html.http-request-send"; |
+ |
+ /** |
+ * No callback is ever executed in an http-request send task. |
+ */ |
+ bool get isOneShot => false; |
+} |
+ |
/** |
* A client-side XHR request for getting data from a URL, |
* formally known as XMLHttpRequest. |
@@ -190,7 +251,34 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS |
{String method, bool withCredentials, String responseType, |
String mimeType, Map<String, String> requestHeaders, sendData, |
void onProgress(ProgressEvent e)}) { |
+ var spec = new HttpRequestTaskSpecification( |
+ url, method: method, |
+ withCredentials: withCredentials, |
+ responseType: responseType, |
+ mimeType: mimeType, |
+ requestHeaders: requestHeaders, |
+ sendData: sendData, |
+ onProgress: onProgress); |
+ |
+ if (identical(Zone.current, Zone.ROOT)) { |
+ return _createHttpRequestTask(spec, null); |
+ } |
+ return Zone.current.createTask(_createHttpRequestTask, spec); |
+ } |
+ |
+ static Future<HttpRequest> _createHttpRequestTask( |
+ HttpRequestTaskSpecification spec, Zone zone) { |
+ String url = spec.url; |
+ String method = spec.method; |
+ bool withCredentials = spec.withCredentials; |
+ String responseType = spec.responseType; |
+ String mimeType = spec.mimeType; |
+ Map<String, String> requestHeaders = spec.requestHeaders; |
+ var sendData = spec.sendData; |
+ var onProgress = spec.onProgress; |
+ |
var completer = new Completer<HttpRequest>(); |
+ var task = completer.future; |
var xhr = new HttpRequest(); |
if (method == null) { |
@@ -230,23 +318,42 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS |
// redirect case will be handled by the browser before it gets to us, |
// so if we see it we should pass it through to the user. |
var unknownRedirect = xhr.status > 307 && xhr.status < 400; |
- |
- if (accepted || fileUri || notModified || unknownRedirect) { |
+ |
+ var isSuccessful = accepted || fileUri || notModified || unknownRedirect; |
+ |
+ if (zone == null && isSuccessful) { |
completer.complete(xhr); |
- } else { |
+ } else if (zone == null) { |
completer.completeError(e); |
+ } else if (isSuccessful) { |
+ zone.runTask((task, value) { |
+ completer.complete(value); |
+ }, task, xhr); |
+ } else { |
+ zone.runTask((task, error) { |
+ completer.completeError(error); |
+ }, task, e); |
} |
}); |
- xhr.onError.listen(completer.completeError); |
+ if (zone == null) { |
+ xhr.onError.listen(completer.completeError); |
+ } else { |
+ xhr.onError.listen((error) { |
+ zone.runTask((task, error) { |
+ completer.completeError(error); |
+ }, task, error); |
+ }); |
+ } |
if (sendData != null) { |
- xhr.send(sendData); |
+ // TODO(floitsch): should we go through 'send()' and have nested tasks? |
+ xhr._send(sendData); |
} else { |
- xhr.send(); |
+ xhr._send(); |
} |
- return completer.future; |
+ return task; |
} |
/** |
@@ -316,6 +423,9 @@ $endif |
return xhr.responseText; |
}); |
} |
+ // TODO(floitsch): the following code doesn't go through task zones. |
+ // Since 'XDomainRequest' is an IE9 feature we should probably just remove |
+ // it. |
$if DART2JS |
var completer = new Completer<String>(); |
if (method == null) { |
@@ -396,7 +506,7 @@ $endif |
* |
* Note: Most simple HTTP requests can be accomplished using the [getString], |
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this |
- * `open` method is intended only for more complext HTTP requests where |
+ * `open` method is intended only for more complex HTTP requests where |
* finer-grained control is needed. |
*/ |
@DomName('XMLHttpRequest.open') |
@@ -413,5 +523,35 @@ $else |
void open(String method, String url, {bool async, String user, String password}) native; |
$endif |
+ /** |
+ * Sends the request with any given `data`. |
+ * |
+ * Note: Most simple HTTP requests can be accomplished using the [getString], |
+ * [request], [requestCrossOrigin], or [postFormData] methods. Use of this |
+ * `send` method is intended only for more complex HTTP requests where |
+ * finer-grained control is needed. |
+ * |
+ * ## Other resources |
+ * |
+ * * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#send%28%29) |
+ * from MDN. |
+ */ |
+ @DomName('XMLHttpRequest.send') |
+ @DocsEditable() |
+ void send([body_OR_data]) { |
+ if (identical(Zone.current, Zone.ROOT)) { |
+ _send(body_OR_data); |
+ } else { |
+ Zone.current.createTask(_createHttpRequestSendTask, |
+ new HttpRequestSendTaskSpecification(this, body_OR_data)); |
+ } |
+ } |
+ |
+ static HttpRequest _createHttpRequestSendTask( |
+ HttpRequestSendTaskSpecification spec, Zone zone) { |
+ spec.request._send(spec.sendData); |
+ return spec.request; |
+ } |
+ |
$!MEMBERS |
} |