Adds a native XMLHttpRequest implementation, updates RequestBuilder to use it,
and removes the long-deprecated XMLHTTPRequest object from the User module.
This object uses no deferred-binding and is intended to be suitable for use in
Core.
Patch by: jgw
Review by: spoon
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4779 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/http/HTTP.gwt.xml b/user/src/com/google/gwt/http/HTTP.gwt.xml
index 76d3238..c212dd4 100644
--- a/user/src/com/google/gwt/http/HTTP.gwt.xml
+++ b/user/src/com/google/gwt/http/HTTP.gwt.xml
@@ -18,5 +18,10 @@
<!-- package must inherit this module. -->
<!-- -->
<module>
- <inherits name="com.google.gwt.core.Core"/>
+ <inherits name="com.google.gwt.core.Core"/>
+ <inherits name="com.google.gwt.xhr.XMLHttpRequest"/>
+
+ <!-- Inheriting User module for Window and Timer. These should be factored
+ out of User soon. -->
+ <inherits name="com.google.gwt.user.User"/>
</module>
diff --git a/user/src/com/google/gwt/http/client/Request.java b/user/src/com/google/gwt/http/client/Request.java
index ddc8ecd..fd0ea9d 100644
--- a/user/src/com/google/gwt/http/client/Request.java
+++ b/user/src/com/google/gwt/http/client/Request.java
@@ -16,22 +16,23 @@
package com.google.gwt.http.client;
import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.xhr.client.XMLHttpRequest;
/**
* An HTTP request that is waiting for a response. Requests can be queried for
* their pending status or they can be canceled.
*
- * <h3>Required Module</h3>
- * Modules that use this class should inherit
+ * <h3>Required Module</h3> Modules that use this class should inherit
* <code>com.google.gwt.http.HTTP</code>.
*
- * {@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
+ * {@gwt.include
+ * com/google/gwt/examples/http/InheritsExample.gwt.xml}
*
*/
public class Request {
+
/**
* Creates a {@link Response} instance for the given JavaScript XmlHttpRequest
* object.
@@ -39,45 +40,98 @@
* @param xmlHttpRequest xmlHttpRequest object for which we need a response
* @return a {@link Response} object instance
*/
- private static Response createResponse(final JavaScriptObject xmlHttpRequest) {
- assert (XMLHTTPRequest.isResponseReady(xmlHttpRequest));
+ private static Response createResponse(final XMLHttpRequest xmlHttpRequest) {
+ assert (isResponseReady(xmlHttpRequest));
Response response = new Response() {
@Override
public String getHeader(String header) {
StringValidator.throwIfEmptyOrNull("header", header);
- return XMLHTTPRequest.getResponseHeader(xmlHttpRequest, header);
+ return xmlHttpRequest.getResponseHeader(header);
}
@Override
public Header[] getHeaders() {
- return XMLHTTPRequest.getHeaders(xmlHttpRequest);
+ return Request.getHeaders(xmlHttpRequest);
}
@Override
public String getHeadersAsString() {
- return XMLHTTPRequest.getAllResponseHeaders(xmlHttpRequest);
+ return xmlHttpRequest.getAllResponseHeaders();
}
@Override
public int getStatusCode() {
- return XMLHTTPRequest.getStatusCode(xmlHttpRequest);
+ return xmlHttpRequest.getStatus();
}
@Override
public String getStatusText() {
- return XMLHTTPRequest.getStatusText(xmlHttpRequest);
+ return xmlHttpRequest.getStatusText();
}
@Override
public String getText() {
- return XMLHTTPRequest.getResponseText(xmlHttpRequest);
+ return xmlHttpRequest.getResponseText();
}
};
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
+ */
+ private static Header[] getHeaders(XMLHttpRequest xmlHttp) {
+ String allHeaders = xmlHttp.getAllResponseHeaders();
+ String[] unparsedHeaders = allHeaders.split("\n");
+ Header[] parsedHeaders = new 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;
+ }
+
+ final String name = unparsedHeader.substring(0, endOfNameIdx).trim();
+ final String value = unparsedHeader.substring(endOfNameIdx + 1).trim();
+ Header header = new Header() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return name + " : " + value;
+ }
+ };
+
+ parsedHeaders[i] = header;
+ }
+
+ return parsedHeaders;
+ }
+
+ private static boolean isResponseReady(XMLHttpRequest xhr) {
+ return xhr.getReadyState() == XMLHttpRequest.DONE;
+ }
+
+ /**
* The number of milliseconds to wait for this HTTP request to complete.
*/
private final int timeoutMillis;
@@ -93,7 +147,7 @@
* not final because we transfer ownership of it to the HTTPResponse object
* and set this field to null.
*/
- private JavaScriptObject xmlHttpRequest;
+ private XMLHttpRequest xmlHttpRequest;
/**
* Constructs an instance of the Request object.
@@ -105,7 +159,7 @@
* @throws IllegalArgumentException if timeoutMillis < 0
* @throws NullPointerException if xmlHttpRequest, or callback are null
*/
- Request(JavaScriptObject xmlHttpRequest, int timeoutMillis,
+ Request(XMLHttpRequest xmlHttpRequest, int timeoutMillis,
final RequestCallback callback) {
if (xmlHttpRequest == null) {
throw new NullPointerException();
@@ -157,10 +211,11 @@
* this in Java by nulling out our reference to the XmlHttpRequest object.
*/
if (xmlHttpRequest != null) {
- JavaScriptObject xmlHttp = xmlHttpRequest;
+ XMLHttpRequest xmlHttp = xmlHttpRequest;
xmlHttpRequest = null;
- XMLHTTPRequest.abort(xmlHttp);
+ xmlHttp.clearOnReadyStateChange();
+ xmlHttp.abort();
cancelTimer();
}
@@ -176,19 +231,19 @@
return false;
}
- int readyState = XMLHTTPRequest.getReadyState(xmlHttpRequest);
+ int readyState = xmlHttpRequest.getReadyState();
/*
* 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 not *technically* true since open implies that the
+ * open although it is nottechnically true since open implies that the
* request has not been sent.
*/
switch (readyState) {
- case XMLHTTPRequest.OPEN:
- case XMLHTTPRequest.SENT:
- case XMLHTTPRequest.RECEIVING:
+ case XMLHttpRequest.OPENED:
+ case XMLHttpRequest.HEADERS_RECEIVED:
+ case XMLHttpRequest.LOADING:
return true;
}
@@ -196,6 +251,19 @@
}
/*
+ * Method called when the JavaScript XmlHttpRequest object's readyState
+ * reaches 4 (LOADED).
+ */
+ void fireOnResponseReceived(RequestCallback callback) {
+ UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
+ if (handler != null) {
+ fireOnResponseReceivedAndCatch(handler, callback);
+ } else {
+ fireOnResponseReceivedImpl(callback);
+ }
+ }
+
+ /*
* Stops the current HTTPRequest timer if there is one.
*/
private void cancelTimer() {
@@ -204,22 +272,6 @@
}
}
- /*
- * Method called when the JavaScript XmlHttpRequest object's readyState
- * reaches 4 (LOADED).
- *
- * NOTE: this method is called from JSNI
- */
- @SuppressWarnings("unused")
- private void fireOnResponseReceived(RequestCallback callback) {
- UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
- if (handler != null) {
- fireOnResponseReceivedAndCatch(handler, callback);
- } else {
- fireOnResponseReceivedImpl(callback);
- }
- }
-
private void fireOnResponseReceivedAndCatch(UncaughtExceptionHandler handler,
RequestCallback callback) {
try {
@@ -242,15 +294,15 @@
* JavaScript XmlHttpRequest object so we manually null out our reference to
* the JavaScriptObject
*/
- final JavaScriptObject xmlHttp = xmlHttpRequest;
+ final XMLHttpRequest xhr = xmlHttpRequest;
xmlHttpRequest = null;
- String errorMsg = XMLHTTPRequest.getBrowserSpecificFailure(xmlHttp);
+ String errorMsg = getBrowserSpecificFailure(xhr);
if (errorMsg != null) {
Throwable exception = new RuntimeException(errorMsg);
callback.onError(this, exception);
} else {
- Response response = createResponse(xmlHttp);
+ Response response = createResponse(xhr);
callback.onResponseReceived(this, response);
}
}
@@ -270,4 +322,41 @@
callback.onError(this, new RequestTimeoutException(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.
+ */
+ private native String getBrowserSpecificFailure(
+ XMLHttpRequest xhr) /*-{
+ try {
+ if (xhr.status === undefined) {
+ return "XmlHttpRequest.status == undefined, please see Safari bug " +
+ "http://bugs.webkit.org/show_bug.cgi?id=3810 for more details";
+ }
+ return null;
+ } 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";
+ }
+ }-*/;
}
diff --git a/user/src/com/google/gwt/http/client/RequestBuilder.java b/user/src/com/google/gwt/http/client/RequestBuilder.java
index 91ab448..38a9fb6 100644
--- a/user/src/com/google/gwt/http/client/RequestBuilder.java
+++ b/user/src/com/google/gwt/http/client/RequestBuilder.java
@@ -15,9 +15,9 @@
*/
package com.google.gwt.http.client;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.user.client.impl.HTTPRequestImpl;
+import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.xhr.client.ReadyStateChangeHandler;
+import com.google.gwt.xhr.client.XMLHttpRequest;
import java.util.HashMap;
import java.util.Map;
@@ -36,11 +36,11 @@
* http://bugs.webkit.org/show_bug.cgi?id=3812</a> for more details.
* </p>
*
- * <h3>Required Module</h3>
- * Modules that use this class should inherit
+ * <h3>Required Module</h3> Modules that use this class should inherit
* <code>com.google.gwt.http.HTTP</code>.
*
- * {@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
+ * {@gwt.include
+ * com/google/gwt/examples/http/InheritsExample.gwt.xml}
*
*/
public class RequestBuilder {
@@ -70,8 +70,6 @@
*/
public static final Method POST = new Method("POST");
- private static final HTTPRequestImpl httpRequest = (HTTPRequestImpl) GWT.create(HTTPRequestImpl.class);
-
/**
* The callback to call when the request completes.
*/
@@ -139,11 +137,12 @@
* @throws IllegalArgumentException if the httpMethod or URL are empty
* @throws NullPointerException if the httpMethod or the URL are null
*
- * <p>
- * <b>WARNING:</b>This method is provided in order to allow the creation of
- * HTTP request other than GET and POST to be made. If this is done, the
- * developer must accept that the behavior on Safari is undefined.
- * </p>
+ * <p>
+ * <b>WARNING:</b>This method is provided in order to allow the
+ * creation of HTTP request other than GET and POST to be made. If
+ * this is done, the developer must accept that the behavior on
+ * Safari is undefined.
+ * </p>
*/
protected RequestBuilder(String httpMethod, String url) {
@@ -156,8 +155,8 @@
/**
* Returns the callback previously set by
- * {@link #setCallback(RequestCallback)}, or <code>null</code> if no
- * callback was set.
+ * {@link #setCallback(RequestCallback)}, or <code>null</code> if no callback
+ * was set.
*/
public RequestCallback getCallback() {
return callback;
@@ -165,8 +164,8 @@
/**
* Returns the value of a header previous set by
- * {@link #setHeader(String, String)}, or <code>null</code> if no such
- * header was set.
+ * {@link #setHeader(String, String)}, or <code>null</code> if no such header
+ * was set.
*
* @param header the name of the header
*/
@@ -265,8 +264,7 @@
* @param callback the response handler to be notified when the request fails
* or completes
*
- * @throws NullPointerException if <code>callback</code> is
- * <code>null</code>
+ * @throws NullPointerException if <code>callback</code> is <code>null</code>
*/
public void setCallback(RequestCallback callback) {
StringValidator.throwIfNull("callback", callback);
@@ -367,34 +365,43 @@
* @throws NullPointerException if request data has not been set
* @throws NullPointerException if a request callback has not been set
*/
- private Request doSend(String requestData, RequestCallback callback)
+ private Request doSend(String requestData, final RequestCallback callback)
throws RequestException {
- JavaScriptObject xmlHttpRequest = httpRequest.createXmlHTTPRequest();
- String openError;
- if (user != null && password != null) {
- openError = XMLHTTPRequest.open(xmlHttpRequest, httpMethod, url, true,
- user, password);
- } else if (user != null) {
- openError = XMLHTTPRequest.open(xmlHttpRequest, httpMethod, url, true,
- user);
- } else {
- openError = XMLHTTPRequest.open(xmlHttpRequest, httpMethod, url, true);
- }
- if (openError != null) {
+ XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create();
+
+ try {
+ if (user != null && password != null) {
+ xmlHttpRequest.open(httpMethod, url, user, password);
+ } else if (user != null) {
+ xmlHttpRequest.open(httpMethod, url, user);
+ } else {
+ xmlHttpRequest.open(httpMethod, url);
+ }
+ } catch (JavaScriptException e) {
RequestPermissionException requestPermissionException = new RequestPermissionException(
url);
- requestPermissionException.initCause(new RequestException(openError));
+ requestPermissionException.initCause(new RequestException(e.getMessage()));
throw requestPermissionException;
}
setHeaders(xmlHttpRequest);
- Request request = new Request(xmlHttpRequest, timeoutMillis, callback);
+ final Request request = new Request(xmlHttpRequest, timeoutMillis, callback);
- String sendError = XMLHTTPRequest.send(xmlHttpRequest, request,
- requestData, callback);
- if (sendError != null) {
- throw new RequestException(sendError);
+ // Must set the onreadystatechange handler before calling send().
+ xmlHttpRequest.setOnReadyStateChange(new ReadyStateChangeHandler() {
+ public void onReadyStateChange(XMLHttpRequest xhr) {
+ if (xhr.getReadyState() == XMLHttpRequest.DONE) {
+ xhr.clearOnReadyStateChange();
+ request.fireOnResponseReceived(callback);
+ }
+ }
+ });
+
+ try {
+ xmlHttpRequest.send(requestData);
+ } catch (JavaScriptException e) {
+ throw new RequestException(e.getMessage());
}
return request;
@@ -406,18 +413,18 @@
* the "Content-Type" to "text/plain; charset=utf-8". This is really lining us
* up for integration with RPC.
*/
- private void setHeaders(JavaScriptObject xmlHttpRequest)
+ private void setHeaders(XMLHttpRequest xmlHttpRequest)
throws RequestException {
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> header : headers.entrySet()) {
- String errorMessage = XMLHTTPRequest.setRequestHeader(xmlHttpRequest,
- header.getKey(), header.getValue());
- if (errorMessage != null) {
- throw new RequestException(errorMessage);
+ try {
+ xmlHttpRequest.setRequestHeader(header.getKey(), header.getValue());
+ } catch (JavaScriptException e) {
+ throw new RequestException(e.getMessage());
}
}
} else {
- XMLHTTPRequest.setRequestHeader(xmlHttpRequest, "Content-Type",
+ xmlHttpRequest.setRequestHeader("Content-Type",
"text/plain; charset=utf-8");
}
}
diff --git a/user/src/com/google/gwt/http/client/RequestCallback.java b/user/src/com/google/gwt/http/client/RequestCallback.java
index 14e79e2..7a01893 100644
--- a/user/src/com/google/gwt/http/client/RequestCallback.java
+++ b/user/src/com/google/gwt/http/client/RequestCallback.java
@@ -26,6 +26,7 @@
* {@gwt.include com/google/gwt/examples/http/InheritsExample.gwt.xml}
*/
public interface RequestCallback {
+
/**
* Called when a pending {@link com.google.gwt.http.client.Request} completes
* normally. Note this method is called even when the status code of the
diff --git a/user/src/com/google/gwt/http/client/XMLHTTPRequest.java b/user/src/com/google/gwt/http/client/XMLHTTPRequest.java
deleted file mode 100644
index 32da515..0000000
--- a/user/src/com/google/gwt/http/client/XMLHTTPRequest.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.http.client;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-/**
- * Utility class that serves as the one place where we interact with the
- * JavaScript <code>XmlHttpRequest</code> object.
- */
-final class XMLHTTPRequest {
-
- /*
- * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
- * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler
- * function maybe still be called after it is deleted. The theory is that the
- * callback is cached somewhere. Setting it to null or an empty function does
- * seem to work properly, though.
- *
- * On IE, there are two problems: Setting onreadystatechange to null (as
- * opposed to an empty function) sometimes throws an exception. With
- * particular (rare) versions of jscript.dll, setting onreadystatechange from
- * within onreadystatechange causes a crash. Setting it from within a timeout
- * fixes this bug (see issue 1610).
- *
- * End result: *always* set onreadystatechange to an empty function (never to
- * null). Never set onreadystatechange from within onreadystatechange (always
- * in a setTimeout()).
- */
-
- public static final int UNITIALIZED = 0;
- public static final int OPEN = 1;
- public static final int SENT = 2;
- public static final int RECEIVING = 3;
- public static final int LOADED = 4;
-
- static native void abort(JavaScriptObject xmlHttpRequest) /*-{
- xmlHttpRequest.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
- xmlHttpRequest.abort();
- }-*/;
-
- static native String getAllResponseHeaders(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.getAllResponseHeaders();
- }-*/;
-
- /**
- * 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 xmlHttpRequest 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.
- */
- static native String getBrowserSpecificFailure(
- JavaScriptObject xmlHttpRequest) /*-{
- try {
- if (xmlHttpRequest.status === undefined) {
- return "XmlHttpRequest.status == undefined, please see Safari bug " +
- "http://bugs.webkit.org/show_bug.cgi?id=3810 for more details";
- }
- return null;
- } 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";
- }
- }-*/;
-
- /**
- * 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 Header[] getHeaders(JavaScriptObject xmlHttpRequest) {
- String allHeaders = getAllResponseHeaders(xmlHttpRequest);
- String[] unparsedHeaders = allHeaders.split("\n");
- Header[] parsedHeaders = new 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;
- }
-
- final String name = unparsedHeader.substring(0, endOfNameIdx).trim();
- final String value = unparsedHeader.substring(endOfNameIdx + 1).trim();
- Header header = new Header() {
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String getValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return name + " : " + value;
- }
- };
-
- parsedHeaders[i] = header;
- }
-
- return parsedHeaders;
- }
-
- static native int getReadyState(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.readyState;
- }-*/;
-
- static native String getResponseHeader(JavaScriptObject xmlHttpRequest,
- String header) /*-{
- try {
- return xmlHttpRequest.getResponseHeader(header);
- } catch (e) {
- // purposely ignored
- }
- return null;
- }-*/;
-
- static native String getResponseText(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.responseText;
- }-*/;
-
- static native int getStatusCode(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.status;
- }-*/;
-
- static native String getStatusText(JavaScriptObject xmlHttpRequest) /*-{
- return xmlHttpRequest.statusText;
- }-*/;
-
- static boolean isResponseReady(JavaScriptObject xmlHttpRequest) {
- return getReadyState(xmlHttpRequest) == LOADED;
- }
-
- /**
- * Opens the request and catches any exceptions thrown. If an exception is
- * caught, its string representation will be returned. This is the only signal
- * that an error has occurred.
- *
- * @param xmlHttpRequest JavaScript <code>XmlHttpRequest</code> object
- * @param httpMethod the method to use for open call
- * @param url the URL to use for the open call
- * @param async true if we should do an asynchronous open
- * @return error message if an exception is thrown or null if there is none
- */
- static native String open(JavaScriptObject xmlHttpRequest, String httpMethod,
- String url, boolean async) /*-{
- try {
- xmlHttpRequest.open(httpMethod, url, async);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- /**
- * Opens the request and catches any exceptions thrown. If an exception is
- * caught, its string representation will be returned. This is the only signal
- * that an error has occurred.
- *
- * @param xmlHttpRequest JavaScript <code>XmlHttpRequest</code> object
- * @param httpMethod the method to use for open call
- * @param url the URL to use for the open call
- * @param async true if we should do an asynchronous open
- * @param user user to use in the URL
- * @return error message if an exception is thrown or null if there is none
- */
- static native String open(JavaScriptObject xmlHttpRequest, String httpMethod,
- String url, boolean async, String user) /*-{
- try {
- xmlHttpRequest.open(httpMethod, url, async, user);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- /**
- * Opens the request and catches any exceptions thrown. If an exception is
- * caught, its string representation will be returned. This is the only signal
- * that an error has occurred.
- *
- * @param xmlHttpRequest JavaScript <code>XmlHttpRequest</code> object
- * @param httpMethod the method to use for open call
- * @param url the URL to use for the open call
- * @param async true if we should do an asynchronous open
- * @param user user to use in the URL
- * @param password password to use in the URL
- * @return error message if an exception is thrown or null if there is none
- */
- static native String open(JavaScriptObject xmlHttpRequest, String httpMethod,
- String url, boolean async, String user, String password) /*-{
- try {
- xmlHttpRequest.open(httpMethod, url, async, user, password);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- /*
- * Creates a closure that calls the HTTPRequest::fireOnResponseRecieved method
- * when the server's response is received and sends the data.
- */
- static native String send(JavaScriptObject xmlHttpRequest, Request httpRequest,
- String requestData, RequestCallback callback) /*-{
- xmlHttpRequest.onreadystatechange = function() {
- if (xmlHttpRequest.readyState == @com.google.gwt.http.client.XMLHTTPRequest::LOADED) {
- $wnd.setTimeout(function() {
- xmlHttpRequest.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
- }, 0);
- httpRequest.@com.google.gwt.http.client.Request::fireOnResponseReceived(Lcom/google/gwt/http/client/RequestCallback;)(callback);
- }
- };
- try {
- xmlHttpRequest.send(requestData);
- return null;
- } catch (e) {
- xmlHttpRequest.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
- return e.message || e.toString();
- }
- }-*/;
-
- static native String setRequestHeader(JavaScriptObject xmlHttpRequest,
- String header, String value) /*-{
- try {
- xmlHttpRequest.setRequestHeader(header, value);
- return null;
- } catch (e) {
- return e.message || e.toString();
- }
- }-*/;
-
- private XMLHTTPRequest() {
- }
-}
diff --git a/user/src/com/google/gwt/user/HTTPRequest.gwt.xml b/user/src/com/google/gwt/user/HTTPRequest.gwt.xml
index 3401614..f0f5133 100644
--- a/user/src/com/google/gwt/user/HTTPRequest.gwt.xml
+++ b/user/src/com/google/gwt/user/HTTPRequest.gwt.xml
@@ -18,16 +18,5 @@
<!-- -->
<module>
<inherits name="com.google.gwt.core.Core"/>
- <inherits name="com.google.gwt.user.UserAgent"/>
-
- <!-- Fall through to this rule is the browser isn't IE -->
- <replace-with class="com.google.gwt.user.client.impl.HTTPRequestImpl">
- <when-type-is class="com.google.gwt.user.client.impl.HTTPRequestImpl"/>
- </replace-with>
-
- <!-- IE differs slightly in how XmlHttpRequest gets instantiated -->
- <replace-with class="com.google.gwt.user.client.impl.HTTPRequestImplIE6">
- <when-type-is class="com.google.gwt.user.client.impl.HTTPRequestImpl"/>
- <when-property-is name="user.agent" value="ie6"/>
- </replace-with>
+ <inherits name="com.google.gwt.xhr.XMLHttpRequest"/>
</module>
diff --git a/user/src/com/google/gwt/user/client/HTTPRequest.java b/user/src/com/google/gwt/user/client/HTTPRequest.java
index 0ff0e44..50acb62 100644
--- a/user/src/com/google/gwt/user/client/HTTPRequest.java
+++ b/user/src/com/google/gwt/user/client/HTTPRequest.java
@@ -15,9 +15,6 @@
*/
package com.google.gwt.user.client;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.impl.HTTPRequestImpl;
-
/**
* This class allows you to make asynchronous HTTP requests to the originating
* server.
@@ -28,8 +25,6 @@
@Deprecated
public class HTTPRequest {
- private static final HTTPRequestImpl httpRequest = GWT.create(HTTPRequestImpl.class);
-
/**
* Makes an asynchronous HTTP GET to a remote server.
*
@@ -39,7 +34,7 @@
* @return <code>false</code> if the invocation fails to issue
*/
public static boolean asyncGet(String url, ResponseTextHandler handler) {
- return httpRequest.asyncGet(url, handler);
+ return asyncGetImpl(null, null, url, handler);
}
/**
@@ -52,7 +47,7 @@
*/
public static boolean asyncGet(String user, String pwd, String url,
ResponseTextHandler handler) {
- return httpRequest.asyncGet(user, pwd, url, handler);
+ return asyncGetImpl(user, pwd, url, handler);
}
/**
@@ -66,7 +61,7 @@
*/
public static boolean asyncPost(String url, String postData,
ResponseTextHandler handler) {
- return httpRequest.asyncPost(url, postData, handler);
+ return asyncPostImpl(null, null, url, postData, handler);
}
/**
@@ -80,6 +75,51 @@
*/
public static boolean asyncPost(String user, String pwd, String url,
String postData, ResponseTextHandler handler) {
- return httpRequest.asyncPost(user, pwd, url, postData, handler);
+ return asyncPostImpl(user, pwd, url, postData, handler);
}
+
+ private static native boolean asyncGetImpl(String user, String pwd, String url,
+ ResponseTextHandler handler) /*-{
+ var xmlHttp = @com.google.gwt.xhr.client.XMLHttpRequest::create()();
+ try {
+ xmlHttp.open("GET", url, true);
+ xmlHttp.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ xmlHttp.onreadystatechange = function() {
+ if (xmlHttp.readyState == 4) {
+ $wnd.setTimeout(function() {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ }, 0);
+ handler.@com.google.gwt.user.client.ResponseTextHandler::onCompletion(Ljava/lang/String;)(xmlHttp.responseText || "");
+ }
+ };
+ xmlHttp.send('');
+ return true;
+ } catch (e) {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ return false;
+ }
+ }-*/;
+
+ private static native boolean asyncPostImpl(String user, String pwd, String url,
+ String postData, ResponseTextHandler handler) /*-{
+ var xmlHttp = @com.google.gwt.xhr.client.XMLHttpRequest::create()();
+ try {
+ xmlHttp.open("POST", url, true);
+ xmlHttp.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ xmlHttp.onreadystatechange = function() {
+ if (xmlHttp.readyState == 4) {
+ $wnd.setTimeout(function() {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ }, 0);
+ handler.@com.google.gwt.user.client.ResponseTextHandler::onCompletion(Ljava/lang/String;)(xmlHttp.responseText || "");
+ }
+ };
+ xmlHttp.send(postData);
+ return true;
+ }
+ catch (e) {
+ xmlHttp.onreadystatechange = @com.google.gwt.user.client.impl.HTTPRequestImpl::nullFunc;
+ return false;
+ }
+ }-*/;
}
diff --git a/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java b/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
deleted file mode 100644
index 1bea53c..0000000
--- a/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.impl;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-/**
- * Internet Explorer 6 implementation of {@link HTTPRequestImpl}.
- */
-class HTTPRequestImplIE6 extends HTTPRequestImpl {
-
- @Override
- protected native JavaScriptObject doCreateXmlHTTPRequest() /*-{
- if ($wnd.XMLHttpRequest) {
- return new XMLHttpRequest();
- } else {
- try {
- return new ActiveXObject('MSXML2.XMLHTTP.3.0');
- } catch (e) {
- return new ActiveXObject("Microsoft.XMLHTTP");
- }
- }
- }-*/;
-}
diff --git a/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml b/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
new file mode 100644
index 0000000..214dc42
--- /dev/null
+++ b/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
@@ -0,0 +1,22 @@
+<!-- -->
+<!-- Copyright 2009 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- Types and resources required to support HTTP requests. -->
+<!-- -->
+<!-- Any user application that wishes to use the types declared in the http -->
+<!-- package must inherit this module. -->
+<!-- -->
+<module>
+ <inherits name="com.google.gwt.core.Core"/>
+</module>
diff --git a/user/src/com/google/gwt/xhr/client/ReadyStateChangeHandler.java b/user/src/com/google/gwt/xhr/client/ReadyStateChangeHandler.java
new file mode 100644
index 0000000..feec633
--- /dev/null
+++ b/user/src/com/google/gwt/xhr/client/ReadyStateChangeHandler.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.xhr.client;
+
+/**
+ * A ready-state callback for an {@Link XMLHttpRequest} object.
+ */
+public interface ReadyStateChangeHandler {
+
+ /**
+ * This is called whenever the state of the XMLHttpRequest changes. See
+ * {@link XMLHttpRequest#setOnReadyStateHandler}.
+ *
+ * @param xhr the object whose state has changed.
+ */
+ void onReadyStateChange(XMLHttpRequest xhr);
+}
diff --git a/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java b/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
new file mode 100644
index 0000000..868a429
--- /dev/null
+++ b/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.xhr.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.http.client.RequestBuilder;
+
+/**
+ * The native XMLHttpRequest object. Most applications should use the higher-
+ * level {@link RequestBuilder} class unless they need specific functionality
+ * provided by the XMLHttpRequest object.
+ *
+ * @see http://www.w3.org/TR/XMLHttpRequest/
+ */
+public class XMLHttpRequest extends JavaScriptObject {
+
+ /*
+ * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
+ * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler
+ * function maybe still be called after it is deleted. The theory is that the
+ * callback is cached somewhere. Setting it to null or an empty function does
+ * seem to work properly, though.
+ *
+ * On IE, there are two problems: Setting onreadystatechange to null (as
+ * opposed to an empty function) sometimes throws an exception. With
+ * particular (rare) versions of jscript.dll, setting onreadystatechange from
+ * within onreadystatechange causes a crash. Setting it from within a timeout
+ * fixes this bug (see issue 1610).
+ *
+ * End result: *always* set onreadystatechange to an empty function (never to
+ * null). Never set onreadystatechange from within onreadystatechange (always
+ * in a setTimeout()).
+ */
+
+ /**
+ * When constructed, the XMLHttpRequest object must be in the UNSENT state.
+ */
+ public static final int UNSENT = 0;
+
+ /**
+ * The OPENED state is the state of the object when the open() method has been
+ * successfully invoked. During this state request headers can be set using
+ * setRequestHeader() and the request can be made using send().
+ */
+ public static final int OPENED = 1;
+
+ /**
+ * The HEADERS_RECEIVED state is the state of the object when all response
+ * headers have been received.
+ */
+ public static final int HEADERS_RECEIVED = 2;
+
+ /**
+ * The LOADING state is the state of the object when the response entity body
+ * is being received.
+ */
+ public static final int LOADING = 3;
+
+ /**
+ * The DONE state is the state of the object when either the data transfer has
+ * been completed or something went wrong during the transfer (infinite
+ * redirects for instance).
+ */
+ public static final int DONE = 4;
+
+ /**
+ * Creates an XMLHttpRequest object.
+ *
+ * @return the created object
+ */
+ public static native XMLHttpRequest create() /*-{
+ if ($wnd.XMLHttpRequest) {
+ return new XMLHttpRequest();
+ } else {
+ try {
+ return new ActiveXObject('MSXML2.XMLHTTP.3.0');
+ } catch (e) {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ }
+ }-*/;
+
+ protected XMLHttpRequest() {
+ }
+
+ /**
+ * Aborts the current request.
+ *
+ * @see http://www.w3.org/TR/XMLHttpRequest/#abort
+ */
+ public final native void abort() /*-{
+ this.abort();
+ }-*/;
+
+ /**
+ * Clears the {@link ReadyStateChangeHandler}.
+ *
+ * @see #clearOnReadyStateChange()
+ * @see http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange
+ */
+ public final native void clearOnReadyStateChange() /*-{
+ $wnd.setTimeout(function() {
+ this.onreadystatechange = function(){};
+ }, 0);
+ }-*/;
+
+ /**
+ * Gets all the HTTP response headers, as a single string.
+ *
+ * @return the response headers.
+ * @see http://www.w3.org/TR/XMLHttpRequest/#getallresponseheaders
+ */
+ public final native String getAllResponseHeaders() /*-{
+ return this.getAllResponseHeaders();
+ }-*/;
+
+ /**
+ * Get's the current ready-state.
+ *
+ * @return the ready-state constant
+ * @see http://www.w3.org/TR/XMLHttpRequest/#readystate
+ */
+ public final native int getReadyState() /*-{
+ return this.readyState;
+ }-*/;
+
+ /**
+ * Gets an HTTP response header.
+ *
+ * @param header the response header to be retrieved
+ * @return the header value
+ * @see http://www.w3.org/TR/XMLHttpRequest/#getresponseheader
+ */
+ public final native String getResponseHeader(String header) /*-{
+ return this.getResponseHeader(header);
+ }-*/;
+
+ /**
+ * Gets the response text.
+ *
+ * @return the response text
+ * @see http://www.w3.org/TR/XMLHttpRequest/#responsetext
+ */
+ public final native String getResponseText() /*-{
+ return this.responseText;
+ }-*/;
+
+ /**
+ * Gets the status code.
+ *
+ * @return the status code
+ * @see http://www.w3.org/TR/XMLHttpRequest/#status
+ */
+ public final native int getStatus() /*-{
+ return this.status;
+ }-*/;
+
+ /**
+ * Gets the status text.
+ *
+ * @return the status text
+ * @see http://www.w3.org/TR/XMLHttpRequest/#statustext
+ */
+ public final native String getStatusText() /*-{
+ return this.statusText;
+ }-*/;
+
+ /**
+ * Opens an asynchronous connection.
+ *
+ * @param httpMethod the HTTP method to use
+ * @param url the URL to be opened
+ * @see http://www.w3.org/TR/XMLHttpRequest/#open
+ */
+ public final native void open(String httpMethod, String url) /*-{
+ this.open(httpMethod, url, true);
+ }-*/;
+
+ /**
+ * Opens an asynchronous connection.
+ *
+ * @param httpMethod the HTTP method to use
+ * @param url the URL to be opened
+ * @param user user to use in the URL
+ * @see http://www.w3.org/TR/XMLHttpRequest/#open
+ */
+ public final native void open(String httpMethod, String url, String user) /*-{
+ this.open(httpMethod, url, true, user);
+ }-*/;
+
+ /**
+ * Opens an asynchronous connection.
+ *
+ * @param httpMethod the HTTP method to use
+ * @param url the URL to be opened
+ * @param user user to use in the URL
+ * @param password password to use in the URL
+ * @see http://www.w3.org/TR/XMLHttpRequest/#open
+ */
+ public final native void open(String httpMethod, String url, String user,
+ String password) /*-{
+ this.open(httpMethod, url, true, user, password);
+ }-*/;
+
+ /**
+ * Initiates a request.
+ *
+ * @see http://www.w3.org/TR/XMLHttpRequest/#send
+ */
+ public final native void send() /*-{
+ this.send();
+ }-*/;
+
+ /**
+ * Initiates a request with data.
+ *
+ * @param requestData the data to be sent with the request
+ * @see http://www.w3.org/TR/XMLHttpRequest/#send
+ */
+ public final native void send(String requestData) /*-{
+ this.send(requestData);
+ }-*/;
+
+ /**
+ * Sets the {@link ReadyStateChangeHandler} to be notified when the object's
+ * ready-state changes.
+ *
+ * <p>
+ * Note: Applications <em>must</em> call {@link #clearOnReadyStateChange()}
+ * when they no longer need this object, to ensure that it is cleaned up
+ * properly. Failure to do so will result in memory leaks on some browsers.
+ * </p>
+ *
+ * @param handler the handler to be called when the ready state changes
+ * @see #clearOnReadyStateChange()
+ * @see http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange
+ */
+ public final native void setOnReadyStateChange(ReadyStateChangeHandler handler) /*-{
+ // The 'this' context is always supposed to point to the xhr object in the
+ // onreadystatechange handler, but we reference it via closure to be extra sure.
+ var _this = this;
+ this.onreadystatechange = function() {
+ handler.@com.google.gwt.xhr.client.ReadyStateChangeHandler::onReadyStateChange(Lcom/google/gwt/xhr/client/XMLHttpRequest;)(_this);
+ };
+ }-*/;
+
+ /**
+ * Sets a request header.
+ *
+ * @param header the header to be set
+ * @param value the header's value
+ * @see http://www.w3.org/TR/XMLHttpRequest/#setrequestheader
+ */
+ public final native void setRequestHeader(String header, String value) /*-{
+ this.setRequestHeader(header, value);
+ }-*/;
+}
diff --git a/user/test/com/google/gwt/http/HTTPSuite.java b/user/test/com/google/gwt/http/HTTPSuite.java
index 379a093..b7659bc 100644
--- a/user/test/com/google/gwt/http/HTTPSuite.java
+++ b/user/test/com/google/gwt/http/HTTPSuite.java
@@ -15,14 +15,15 @@
*/
package com.google.gwt.http;
+import junit.framework.Test;
+
+import com.google.gwt.http.client.HTTPRequestTest;
import com.google.gwt.http.client.RequestBuilderTest;
import com.google.gwt.http.client.RequestTest;
import com.google.gwt.http.client.ResponseTest;
import com.google.gwt.http.client.URLTest;
import com.google.gwt.junit.tools.GWTTestSuite;
-import junit.framework.Test;
-
/**
* TODO: document me.
*/
@@ -31,6 +32,7 @@
GWTTestSuite suite = new GWTTestSuite(
"Test for suite for the com.google.gwt.http module");
+ suite.addTestSuite(HTTPRequestTest.class);
suite.addTestSuite(URLTest.class);
suite.addTestSuite(RequestBuilderTest.class);
suite.addTestSuite(RequestTest.class);
diff --git a/user/test/com/google/gwt/http/client/HTTPRequestTest.java b/user/test/com/google/gwt/http/client/HTTPRequestTest.java
new file mode 100644
index 0000000..f689406
--- /dev/null
+++ b/user/test/com/google/gwt/http/client/HTTPRequestTest.java
@@ -0,0 +1,42 @@
+package com.google.gwt.http.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.HTTPRequest;
+import com.google.gwt.user.client.ResponseTextHandler;
+
+public class HTTPRequestTest extends GWTTestCase {
+
+ private static final int TEST_TIMEOUT = 10000;
+
+ private static String getTestBaseURL() {
+ return GWT.getModuleBaseURL() + "testRequestBuilder/";
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.http.RequestBuilderTest";
+ }
+
+ public void testAsyncGet() {
+ delayTestFinish(TEST_TIMEOUT);
+ HTTPRequest.asyncGet(getTestBaseURL() + "send_GET",
+ new ResponseTextHandler() {
+ public void onCompletion(String responseText) {
+ assertEquals(RequestBuilderTest.SERVLET_GET_RESPONSE, responseText);
+ finishTest();
+ }
+ });
+ }
+
+ public void testAsyncPost() {
+ delayTestFinish(TEST_TIMEOUT);
+ HTTPRequest.asyncPost(getTestBaseURL() + "simplePost",
+ "method=test+request", new ResponseTextHandler() {
+ public void onCompletion(String responseText) {
+ assertEquals(RequestBuilderTest.SERVLET_POST_RESPONSE, responseText);
+ finishTest();
+ }
+ });
+ }
+}
diff --git a/user/test/com/google/gwt/http/client/RequestBuilderTest.java b/user/test/com/google/gwt/http/client/RequestBuilderTest.java
index 5a7d84e..5ade8cd 100644
--- a/user/test/com/google/gwt/http/client/RequestBuilderTest.java
+++ b/user/test/com/google/gwt/http/client/RequestBuilderTest.java
@@ -24,6 +24,11 @@
public class RequestBuilderTest extends GWTTestCase {
private static final int TEST_FINISH_DELAY = 10000;
+ public static final String SERVLET_GET_RESPONSE = "get";
+ public static final String SERVLET_POST_RESPONSE = "post";
+ public static final String SERVLET_HEAD_RESPONSE = "head";
+ public static final String SERVLET_PUT_RESPONSE = "put";
+
private static String getTestBaseURL() {
return GWT.getModuleBaseURL() + "testRequestBuilder/";
}
@@ -155,6 +160,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -177,6 +183,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_POST_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -200,6 +207,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -222,6 +230,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_POST_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -316,6 +325,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -345,6 +355,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
finishTest();
}
@@ -374,6 +385,7 @@
}
public void onResponseReceived(Request request, Response response) {
+ assertEquals(SERVLET_GET_RESPONSE, response.getText());
assertEquals(200, response.getStatusCode());
fail("Test did not timeout");
}
diff --git a/user/test/com/google/gwt/http/client/RequestTest.java b/user/test/com/google/gwt/http/client/RequestTest.java
index b0c52df..8f3121f 100644
--- a/user/test/com/google/gwt/http/client/RequestTest.java
+++ b/user/test/com/google/gwt/http/client/RequestTest.java
@@ -17,7 +17,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.user.client.impl.HTTPRequestImpl;
+import com.google.gwt.xhr.client.XMLHttpRequest;
/**
* TODO: document me.
@@ -76,29 +76,28 @@
};
try {
- Request request = new Request(null, 0, callback);
+ new Request(null, 0, callback);
fail();
} catch (NullPointerException ex) {
- // Success.
+ // Success (The Request ctor explicitly throws an NPE).
}
- HTTPRequestImpl impl = (HTTPRequestImpl) GWT.create(HTTPRequestImpl.class);
try {
- Request request = new Request(impl.createXmlHTTPRequest(), -1, callback);
+ new Request(XMLHttpRequest.create(), -1, callback);
fail();
} catch (IllegalArgumentException ex) {
// Success.
}
try {
- Request request = new Request(impl.createXmlHTTPRequest(), -1, null);
+ new Request(XMLHttpRequest.create(), -1, null);
fail();
} catch (NullPointerException ex) {
- // Success.
+ // Success (The Request ctor explicitly throws an NPE).
}
try {
- Request request = new Request(impl.createXmlHTTPRequest(), 0, callback);
+ new Request(XMLHttpRequest.create(), 0, callback);
} catch (Throwable ex) {
fail(ex.getMessage());
}
diff --git a/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java b/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
index f0efd75..7adda6d 100644
--- a/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
+++ b/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
@@ -22,6 +22,8 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import com.google.gwt.http.client.RequestBuilderTest;
+
/**
* Servlet component of the
* {@link com.google.gwt.http.client.RequestBuilderTest RequestBuilderTest}.
@@ -41,42 +43,46 @@
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
- String method = request.getMethod();
String pathInfo = request.getPathInfo();
if (pathInfo.equals(getPathInfoBase() + "setRequestHeader")) {
String value = request.getHeader("Foo");
- response.getWriter().print("Hello");
if (value.equals("Bar1")) {
response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
} else if (pathInfo.equals(getPathInfoBase() + "send_GET")) {
response.setStatus(HttpServletResponse.SC_OK);
- response.getWriter().write("<html><body>hello</body></html>");
- response.setContentType("text/html");
+ response.getWriter().write(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else if (pathInfo.equals(getPathInfoBase() + "sendRequest_GET")) {
response.setStatus(HttpServletResponse.SC_OK);
- response.getWriter().write("<html><body>hello</body></html>");
- response.setContentType("text/html");
+ response.getWriter().write(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else if (pathInfo.equals(getPathInfoBase() + "setTimeout/timeout")) {
// cause a timeout on the client
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
- e.printStackTrace();
}
response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
} else if (pathInfo.equals(getPathInfoBase() + "setTimeout/noTimeout")) {
// wait but not long enough to timeout
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
}
- response.getWriter().print("setTimeout/noTimeout");
response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
+ } else if (pathInfo.equals(getPathInfoBase() + "user/pass")) {
+ String auth = request.getHeader("Authorization");
+ if (auth == null) {
+ response.setHeader("WWW-Authenticate", "BASIC");
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ } else {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE);
+ }
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
@@ -84,27 +90,35 @@
@Override
protected void doHead(HttpServletRequest request, HttpServletResponse response) {
- response.setStatus(HttpServletResponse.SC_OK);
+ try {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().print(RequestBuilderTest.SERVLET_HEAD_RESPONSE);
+ } catch (IOException e) {
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
- String parameter = request.getParameter("method");
- if ("test request".equals(parameter)) {
- try {
+ try {
+ String parameter = request.getParameter("method");
+ if ("test request".equals(parameter)) {
/*
* On Safari 2.0.4, if the HTTP response does not include any response
* text the status message will be undefined. So, we make sure that the
* post returns some data. See
* http://bugs.webkit.org/show_bug.cgi?id=3810.
*/
- response.getWriter().println("Hello");
+ response.getWriter().print(RequestBuilderTest.SERVLET_POST_RESPONSE);
response.setStatus(HttpServletResponse.SC_OK);
- } catch (IOException e) {
- response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ } else if (request.getPathInfo().equals(getPathInfoBase() + "simplePost")) {
+ response.getWriter().print(RequestBuilderTest.SERVLET_POST_RESPONSE);
+ response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
- } else {
- response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ } catch (IOException e) {
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
@@ -114,6 +128,7 @@
BufferedReader reader = request.getReader();
String content = reader.readLine();
if (content.equals("<html><body>Put Me</body></html>")) {
+ response.getWriter().print(RequestBuilderTest.SERVLET_PUT_RESPONSE);
response.setStatus(HttpServletResponse.SC_OK);
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);