Request class
An HTTP request that is waiting for a response. Requests can be queried for their pending status or they can be canceled.
Required Module
Modules that use this class should inheritcom.google.gwt.http.HTTP.
{@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
class Request {
/**
* Creates a {@link Response} instance for the given JavaScript XmlHttpRequest
* object.
*
* @param xmlHttpRequest xmlHttpRequest object for which we need a response
* @return a {@link Response} object instance
*/
static Response createResponse(dart_html.HttpRequest xmlHttpRequest) {
assert (isResponseReady(xmlHttpRequest));
Response response = new _Response(xmlHttpRequest);
return response;
}
/**
* Returns an array of headers built by parsing the string of headers returned
* by the JavaScript <code>XmlHttpRequest</code> object.
*
* @param xmlHttpRequest
* @return array of Header items
*/
static List<Header> getHeaders(dart_html.HttpRequest xmlHttp) {
String allHeaders = xmlHttp.getAllResponseHeaders();
List<String> unparsedHeaders = allHeaders.split("\n");
List<Header> parsedHeaders = new List<Header>(unparsedHeaders.length);
for (int i = 0, n = unparsedHeaders.length; i < n; ++i) {
String unparsedHeader = unparsedHeaders[i];
if (unparsedHeader.length == 0) {
continue;
}
int endOfNameIdx = unparsedHeader.indexOf(':');
if (endOfNameIdx < 0) {
continue;
}
String name = unparsedHeader.substring(0, endOfNameIdx).trim();
String value = unparsedHeader.substring(endOfNameIdx + 1).trim();
Header header = new _RequestHeader(name, value);
parsedHeaders[i] = header;
}
return parsedHeaders;
}
static bool isResponseReady(dart_html.HttpRequest xhr) {
return xhr.readyState == dart_html.HttpRequest.DONE;
}
/**
* The number of milliseconds to wait for this HTTP request to complete.
*/
int _timeoutMillis = 0;
/*
* Timer used to force HTTPRequest timeouts. If the user has not requested a
* timeout then this field is null.
*/
dart_async.Timer _timer;
/*
* JavaScript XmlHttpRequest object that this Java class wraps. This field is
* not final because we transfer ownership of it to the HTTPResponse object
* and set this field to null.
*/
dart_html.HttpRequest _xmlHttpRequest;
/**
* Only used for building a
* {@link com.google.gwt.user.client.rpc.impl.FailedRequest}.
*/
Request.internal();
/**
* Constructs an instance of the Request object.
*
* @param xmlHttpRequest JavaScript XmlHttpRequest object instance
* @param timeoutMillis number of milliseconds to wait for a response
* @param callback callback interface to use for notification
*
* @throws IllegalArgumentException if timeoutMillis < 0
* @throws NullPointerException if xmlHttpRequest, or callback are null
*/
Request(dart_html.HttpRequest xmlHttpRequest, int timeoutMillis, RequestCallback callback) {
if (xmlHttpRequest == null) {
throw new Exception();
}
if (callback == null) {
throw new Exception();
}
if (timeoutMillis < 0) {
throw new Exception();
}
this._timeoutMillis = timeoutMillis;
this._xmlHttpRequest = xmlHttpRequest;
if (timeoutMillis > 0) {
// create and start a Timer
_timer = new dart_async.Timer(new Duration(milliseconds:timeoutMillis), (){
_fireOnTimeout(callback);
});
} else {
// no Timer required
_timer = null;
}
}
/**
* Cancels a pending request. If the request has already been canceled or if
* it has timed out no action is taken.
*/
void cancel() {
/*
* There is a strange race condition that occurs on Mozilla when you cancel
* a request while the response is coming in. It appears that in some cases
* the onreadystatechange handler is still called after the handler function
* has been deleted and during the call to XmlHttpRequest.abort(). So we
* null the xmlHttpRequest here and that will prevent the
* fireOnResponseReceived method from calling the callback function.
*
* Setting the onreadystatechange handler to null gives us the correct
* behavior in Mozilla but crashes IE. That is why we have chosen to fixed
* this in Java by nulling out our reference to the XmlHttpRequest object.
*/
if (_xmlHttpRequest != null) {
dart_html.HttpRequest xmlHttp = _xmlHttpRequest;
_xmlHttpRequest = null;
//xmlHttp.onReadyStateChange. readyStateChangeEvent.addListener(listener); // clearOnReadyStateChange();
xmlHttp.onReadyStateChange.listen(null, onError:null, onDone:null, cancelOnError:true);
xmlHttp.abort();
_cancelTimer();
}
}
/**
* Returns true if this request is waiting for a response.
*
* @return true if this request is waiting for a response
*/
bool isPending() {
if (_xmlHttpRequest == null) {
return false;
}
int readyState = _xmlHttpRequest.readyState;
/*
* Because we are doing asynchronous requests it is possible that we can
* call XmlHttpRequest.send and still have the XmlHttpRequest.getReadyState
* method return the state as XmlHttpRequest.OPEN. That is why we include
* open although it is nottechnically true since open implies that the
* request has not been sent.
*/
switch (readyState) {
case dart_html.HttpRequest.OPENED:
case dart_html.HttpRequest.HEADERS_RECEIVED:
case dart_html.HttpRequest.LOADING:
return true;
}
return false;
}
/*
* Method called when the JavaScript XmlHttpRequest object's readyState
* reaches 4 (LOADED).
*/
void fireOnResponseReceived(RequestCallback callback) {
if (_xmlHttpRequest == null) {
// the request has timed out at this point
return;
}
_cancelTimer();
/*
* We cannot use cancel here because it would clear the contents of the
* JavaScript XmlHttpRequest object so we manually null out our reference to
* the JavaScriptObject
*/
dart_html.HttpRequest xhr = _xmlHttpRequest;
_xmlHttpRequest = null;
String errorMsg = _getBrowserSpecificFailure(xhr);
if (errorMsg != null) {
Exception exception = new Exception(errorMsg);
callback.onError(this, exception);
} else {
Response response = createResponse(xhr);
callback.onResponseReceived(this, response);
}
}
/*
* Stops the current HTTPRequest timer if there is one.
*/
void _cancelTimer() {
if (_timer != null) {
_timer.cancel();
}
}
/*
* Method called when this request times out.
*
* NOTE: this method is called from JSNI
*/
void _fireOnTimeout(RequestCallback callback) {
if (_xmlHttpRequest == null) {
// the request has been received at this point
return;
}
cancel();
callback.onError(this, new Exception()); //this, _timeoutMillis));
}
/**
* Tests if the JavaScript <code>XmlHttpRequest.status</code> property is
* readable. This can return failure in two different known scenarios:
*
* <ol>
* <li>On Mozilla, after a network error, attempting to read the status code
* results in an exception being thrown. See <a
* href="https://bugzilla.mozilla.org/show_bug.cgi?id=238559"
* >https://bugzilla.mozilla.org/show_bug.cgi?id=238559</a>.</li>
* <li>On Safari, if the HTTP response does not include any response text. See
* <a
* href="http://bugs.webkit.org/show_bug.cgi?id=3810">http://bugs.webkit.org
* /show_bug.cgi?id=3810</a>.</li>
* </ol>
*
* @param xhr the JavaScript <code>XmlHttpRequest</code> object to test
* @return a String message containing an error message if the
* <code>XmlHttpRequest.status</code> code is unreadable or null if
* the status code could be successfully read.
*/
String _getBrowserSpecificFailure(dart_html.HttpRequest xhr) {
try {
if (xhr.status == null) {
return "XmlHttpRequest.status == undefined, please see Safari bug http://bugs.webkit.org/show_bug.cgi?id=3810 for more details";
}
return null;
} on Exception catch (e) {
return "Unable to read XmlHttpRequest.status; likely causes are a networking error or bad cross-domain request. Please see https://bugzilla.mozilla.org/show_bug.cgi?id=238559 for more details";
}
}
}
Static Methods
Response createResponse(HttpRequest xmlHttpRequest) #
Creates a {@link Response} instance for the given JavaScript XmlHttpRequest object.
@param xmlHttpRequest xmlHttpRequest object for which we need a response @return a {@link Response} object instance
static Response createResponse(dart_html.HttpRequest xmlHttpRequest) {
assert (isResponseReady(xmlHttpRequest));
Response response = new _Response(xmlHttpRequest);
return response;
}
List<Header> getHeaders(HttpRequest xmlHttp) #
Returns an array of headers built by parsing the string of headers returned by the JavaScript <code>XmlHttpRequest</code> object.
@param xmlHttpRequest @return array of Header items
static List<Header> getHeaders(dart_html.HttpRequest xmlHttp) {
String allHeaders = xmlHttp.getAllResponseHeaders();
List<String> unparsedHeaders = allHeaders.split("\n");
List<Header> parsedHeaders = new List<Header>(unparsedHeaders.length);
for (int i = 0, n = unparsedHeaders.length; i < n; ++i) {
String unparsedHeader = unparsedHeaders[i];
if (unparsedHeader.length == 0) {
continue;
}
int endOfNameIdx = unparsedHeader.indexOf(':');
if (endOfNameIdx < 0) {
continue;
}
String name = unparsedHeader.substring(0, endOfNameIdx).trim();
String value = unparsedHeader.substring(endOfNameIdx + 1).trim();
Header header = new _RequestHeader(name, value);
parsedHeaders[i] = header;
}
return parsedHeaders;
}
bool isResponseReady(HttpRequest xhr) #
static bool isResponseReady(dart_html.HttpRequest xhr) {
return xhr.readyState == dart_html.HttpRequest.DONE;
}
Constructors
new Request(HttpRequest xmlHttpRequest, int timeoutMillis, RequestCallback callback) #
Constructs an instance of the Request object.
@param xmlHttpRequest JavaScript XmlHttpRequest object instance @param timeoutMillis number of milliseconds to wait for a response @param callback callback interface to use for notification
@throws IllegalArgumentException if timeoutMillis < 0 @throws NullPointerException if xmlHttpRequest, or callback are null
Request(dart_html.HttpRequest xmlHttpRequest, int timeoutMillis, RequestCallback callback) {
if (xmlHttpRequest == null) {
throw new Exception();
}
if (callback == null) {
throw new Exception();
}
if (timeoutMillis < 0) {
throw new Exception();
}
this._timeoutMillis = timeoutMillis;
this._xmlHttpRequest = xmlHttpRequest;
if (timeoutMillis > 0) {
// create and start a Timer
_timer = new dart_async.Timer(new Duration(milliseconds:timeoutMillis), (){
_fireOnTimeout(callback);
});
} else {
// no Timer required
_timer = null;
}
}
new Request.internal() #
Only used for building a {@link com.google.gwt.user.client.rpc.impl.FailedRequest}.
Request.internal();
Methods
void cancel() #
Cancels a pending request. If the request has already been canceled or if it has timed out no action is taken.
void cancel() {
/*
* There is a strange race condition that occurs on Mozilla when you cancel
* a request while the response is coming in. It appears that in some cases
* the onreadystatechange handler is still called after the handler function
* has been deleted and during the call to XmlHttpRequest.abort(). So we
* null the xmlHttpRequest here and that will prevent the
* fireOnResponseReceived method from calling the callback function.
*
* Setting the onreadystatechange handler to null gives us the correct
* behavior in Mozilla but crashes IE. That is why we have chosen to fixed
* this in Java by nulling out our reference to the XmlHttpRequest object.
*/
if (_xmlHttpRequest != null) {
dart_html.HttpRequest xmlHttp = _xmlHttpRequest;
_xmlHttpRequest = null;
//xmlHttp.onReadyStateChange. readyStateChangeEvent.addListener(listener); // clearOnReadyStateChange();
xmlHttp.onReadyStateChange.listen(null, onError:null, onDone:null, cancelOnError:true);
xmlHttp.abort();
_cancelTimer();
}
}
void fireOnResponseReceived(RequestCallback callback) #
void fireOnResponseReceived(RequestCallback callback) {
if (_xmlHttpRequest == null) {
// the request has timed out at this point
return;
}
_cancelTimer();
/*
* We cannot use cancel here because it would clear the contents of the
* JavaScript XmlHttpRequest object so we manually null out our reference to
* the JavaScriptObject
*/
dart_html.HttpRequest xhr = _xmlHttpRequest;
_xmlHttpRequest = null;
String errorMsg = _getBrowserSpecificFailure(xhr);
if (errorMsg != null) {
Exception exception = new Exception(errorMsg);
callback.onError(this, exception);
} else {
Response response = createResponse(xhr);
callback.onResponseReceived(this, response);
}
}
bool isPending() #
Returns true if this request is waiting for a response.
@return true if this request is waiting for a response
bool isPending() {
if (_xmlHttpRequest == null) {
return false;
}
int readyState = _xmlHttpRequest.readyState;
/*
* Because we are doing asynchronous requests it is possible that we can
* call XmlHttpRequest.send and still have the XmlHttpRequest.getReadyState
* method return the state as XmlHttpRequest.OPEN. That is why we include
* open although it is nottechnically true since open implies that the
* request has not been sent.
*/
switch (readyState) {
case dart_html.HttpRequest.OPENED:
case dart_html.HttpRequest.HEADERS_RECEIVED:
case dart_html.HttpRequest.LOADING:
return true;
}
return false;
}