content: /*
   * 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;
  
  /**
   * The native XMLHttpRequest object. Most applications should use the higher-
   * level {@link com.google.gwt.http.client.RequestBuilder} class unless they
   * need specific functionality provided by the XMLHttpRequest object.
   *
   * See <a href="http://www.w3.org/TR/XMLHttpRequest/"
   * >http://www.w3.org/TR/XMLHttpRequest/</a>/
   */
  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() /*-{
      // Don't check window.XMLHttpRequest, because it can
      // cause cross-site problems on IE8 if window's URL
      // is javascript:'' .
      if ($wnd.XMLHttpRequest) {
        return new $wnd.XMLHttpRequest();
      } else {
        try {
          return new $wnd.ActiveXObject('MSXML2.XMLHTTP.3.0');
        } catch (e) {
          return new $wnd.ActiveXObject("Microsoft.XMLHTTP");
        }
      }
    }-*/;
  
    protected XMLHttpRequest() {
    }
  
    /**
     * Aborts the current request.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#abort"
     * >http://www.w3.org/TR/XMLHttpRequest/#abort</a>.
     */
    public final native void abort() /*-{
      this.abort();
    }-*/;
  
    /**
     * Clears the {@link ReadyStateChangeHandler}.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange"
     * >http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange</a>.
     *
     * @see #clearOnReadyStateChange()
     */
    public final native void clearOnReadyStateChange() /*-{
      var self = this;
      $wnd.setTimeout(function() {
        // Using a function literal here leaks memory on ie6
        // Using the same function object kills HtmlUnit
        self.onreadystatechange = new Function();
      }, 0);
    }-*/;
  
    /**
     * Gets all the HTTP response headers, as a single string.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#getallresponseheaders"
     * >http://www.w3.org/TR/XMLHttpRequest/#getallresponseheaders</a>.
     *
     * @return the response headers.
     */
    public final native String getAllResponseHeaders() /*-{
      return this.getAllResponseHeaders();
    }-*/;
  
    /**
     * Get's the current ready-state.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#readystate"
     * >http://www.w3.org/TR/XMLHttpRequest/#readystate</a>.
     *
     * @return the ready-state constant
     */
    public final native int getReadyState() /*-{
      return this.readyState;
    }-*/;
  
    /**
     * Gets an HTTP response header.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#getresponseheader"
     * >http://www.w3.org/TR/XMLHttpRequest/#getresponseheader</a>.
     *
     * @param header the response header to be retrieved
     * @return the header value
     */
    public final native String getResponseHeader(String header) /*-{
      return this.getResponseHeader(header);
    }-*/;
  
    /**
     * Gets the response text.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#responsetext"
     * >http://www.w3.org/TR/XMLHttpRequest/#responsetext</a>.
     *
     * @return the response text
     */
    public final native String getResponseText() /*-{
      return this.responseText;
    }-*/;
  
    /**
     * Gets the status code.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#status"
     * >http://www.w3.org/TR/XMLHttpRequest/#status</a>.
     *
     * @return the status code
     */
    public final native int getStatus() /*-{
      return this.status;
    }-*/;
  
    /**
     * Gets the status text.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#statustext"
     * >http://www.w3.org/TR/XMLHttpRequest/#statustext</a>.
     *
     * @return the status text
     */
    public final native String getStatusText() /*-{
      return this.statusText;
    }-*/;
  
    /**
     * Opens an asynchronous connection.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#open"
     * >http://www.w3.org/TR/XMLHttpRequest/#open</a>.
     *
     * @param httpMethod the HTTP method to use
     * @param url the URL to be opened
     */
    public final native void open(String httpMethod, String url) /*-{
      this.open(httpMethod, url, true);
    }-*/;
  
    /**
     * Opens an asynchronous connection.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#open"
     * >http://www.w3.org/TR/XMLHttpRequest/#open</a>.
     *
     * @param httpMethod the HTTP method to use
     * @param url the URL to be opened
     * @param user user to use in the URL
     */
    public final native void open(String httpMethod, String url, String user) /*-{
      this.open(httpMethod, url, true, user);
    }-*/;
  
    /**
     * Opens an asynchronous connection.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#open"
     * >http://www.w3.org/TR/XMLHttpRequest/#open</a>.
     *
     * @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
     */
    public final native void open(String httpMethod, String url, String user,
        String password) /*-{
      this.open(httpMethod, url, true, user, password);
    }-*/;
  
    /**
     * Initiates a request with no request data. This simply calls
     * {@link #send(String)} with <code>null</code> as an argument, because the
     * no-argument <code>send()</code> method is unavailable on Firefox.
     */
    public final void send() {
      send(null);
    }
  
    /**
     * Initiates a request with data.  If there is no data, specify null.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#send"
     * >http://www.w3.org/TR/XMLHttpRequest/#send</a>.
     *
     * @param requestData the data to be sent with the request
     */
    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>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange"
     * >http://www.w3.org/TR/XMLHttpRequest/#onreadystatechange</a>.
     *
     * <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()
     */
    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 = $entry(function() {
        handler.@com.google.gwt.xhr.client.ReadyStateChangeHandler::onReadyStateChange(Lcom/google/gwt/xhr/client/XMLHttpRequest;)(_this);
      });
    }-*/;
  
    /**
     * Sets a request header.
     * <p>
     * See <a href="http://www.w3.org/TR/XMLHttpRequest/#setrequestheader"
     * >http://www.w3.org/TR/XMLHttpRequest/#setrequestheader</a>.
     *
     * @param header the header to be set
     * @param value the header's value
     */
    public final native void setRequestHeader(String header, String value) /*-{
      this.setRequestHeader(header, value);
    }-*/;
    
    
    
      /**
       * 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 openSync(String httpMethod, String url) /*-{
          this.open(httpMethod, url, false);
      }-*/;
  
      /**
       * 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 openSync(String httpMethod, String url, String user) /*-{
          this.open(httpMethod, url, false, 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 openSync(String httpMethod, String url, String user, String password) /*-{
          this.open(httpMethod, url, false, user, password);
      }-*/;
    
    
  }
  