Home | History | Annotate | Download | only in webapp
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @fileoverview
      7  * Simple utilities for making XHRs more pleasant.
      8  */
      9 
     10 'use strict';
     11 
     12 /** @suppress {duplicate} */
     13 var remoting = remoting || {};
     14 
     15 /** Namespace for XHR functions */
     16 /** @type {Object} */
     17 remoting.xhr = remoting.xhr || {};
     18 
     19 /**
     20  * Takes an associative array of parameters and urlencodes it.
     21  *
     22  * @param {Object.<string>} paramHash The parameter key/value pairs.
     23  * @return {string} URLEncoded version of paramHash.
     24  */
     25 remoting.xhr.urlencodeParamHash = function(paramHash) {
     26   var paramArray = [];
     27   for (var key in paramHash) {
     28     paramArray.push(encodeURIComponent(key) +
     29                      '=' + encodeURIComponent(paramHash[key]));
     30   }
     31   if (paramArray.length > 0) {
     32     return paramArray.join('&');
     33   }
     34   return '';
     35 };
     36 
     37 /**
     38  * Execute an XHR GET asynchronously.
     39  *
     40  * @param {string} url The base URL to GET, excluding parameters.
     41  * @param {function(XMLHttpRequest):void} onDone The function to call on
     42  *     completion.
     43  * @param {(string|Object.<string>)=} opt_parameters The request parameters,
     44  *     either as an associative array, or a string.  If it is a string, do
     45  *     not include the ? and be sure it is correctly URLEncoded.
     46  * @param {Object.<string>=} opt_headers Additional headers to include on the
     47  *     request.
     48  * @param {boolean=} opt_withCredentials Set the withCredentials flags in the
     49  *     XHR.
     50  * @return {XMLHttpRequest} The request object.
     51  */
     52 remoting.xhr.get = function(url, onDone, opt_parameters, opt_headers,
     53                             opt_withCredentials) {
     54   return remoting.xhr.doMethod('GET', url, onDone, opt_parameters,
     55                                opt_headers, opt_withCredentials);
     56 };
     57 
     58 /**
     59  * Execute an XHR POST asynchronously.
     60  *
     61  * @param {string} url The base URL to POST, excluding parameters.
     62  * @param {function(XMLHttpRequest):void} onDone The function to call on
     63  *     completion.
     64  * @param {(string|Object.<string>)=} opt_parameters The request parameters,
     65  *     either as an associative array, or a string.  If it is a string, be
     66  *     sure it is correctly URLEncoded.
     67  * @param {Object.<string>=} opt_headers Additional headers to include on the
     68  *     request.
     69  * @param {boolean=} opt_withCredentials Set the withCredentials flags in the
     70  *     XHR.
     71  * @return {XMLHttpRequest} The request object.
     72  */
     73 remoting.xhr.post = function(url, onDone, opt_parameters, opt_headers,
     74                              opt_withCredentials) {
     75   return remoting.xhr.doMethod('POST', url, onDone, opt_parameters,
     76                                opt_headers, opt_withCredentials);
     77 };
     78 
     79 /**
     80  * Execute an XHR DELETE asynchronously.
     81  *
     82  * @param {string} url The base URL to DELETE, excluding parameters.
     83  * @param {function(XMLHttpRequest):void} onDone The function to call on
     84  *     completion.
     85  * @param {(string|Object.<string>)=} opt_parameters The request parameters,
     86  *     either as an associative array, or a string.  If it is a string, be
     87  *     sure it is correctly URLEncoded.
     88  * @param {Object.<string>=} opt_headers Additional headers to include on the
     89  *     request.
     90  * @param {boolean=} opt_withCredentials Set the withCredentials flags in the
     91  *     XHR.
     92  * @return {XMLHttpRequest} The request object.
     93  */
     94 remoting.xhr.remove = function(url, onDone, opt_parameters, opt_headers,
     95                              opt_withCredentials) {
     96   return remoting.xhr.doMethod('DELETE', url, onDone, opt_parameters,
     97                                opt_headers, opt_withCredentials);
     98 };
     99 
    100 /**
    101  * Execute an XHR PUT asynchronously.
    102  *
    103  * @param {string} url The base URL to PUT, excluding parameters.
    104  * @param {function(XMLHttpRequest):void} onDone The function to call on
    105  *     completion.
    106  * @param {(string|Object.<string>)=} opt_parameters The request parameters,
    107  *     either as an associative array, or a string.  If it is a string, be
    108  *     sure it is correctly URLEncoded.
    109  * @param {Object.<string>=} opt_headers Additional headers to include on the
    110  *     request.
    111  * @param {boolean=} opt_withCredentials Set the withCredentials flags in the
    112  *     XHR.
    113  * @return {XMLHttpRequest} The request object.
    114  */
    115 remoting.xhr.put = function(url, onDone, opt_parameters, opt_headers,
    116                              opt_withCredentials) {
    117   return remoting.xhr.doMethod('PUT', url, onDone, opt_parameters,
    118                                opt_headers, opt_withCredentials);
    119 };
    120 
    121 /**
    122  * Execute an arbitrary HTTP method asynchronously.
    123  *
    124  * @param {string} methodName The HTTP method name, e.g. "GET", "POST" etc.
    125  * @param {string} url The base URL, excluding parameters.
    126  * @param {function(XMLHttpRequest):void} onDone The function to call on
    127  *     completion.
    128  * @param {(string|Object.<string>)=} opt_parameters The request parameters,
    129  *     either as an associative array, or a string.  If it is a string, be
    130  *     sure it is correctly URLEncoded.
    131  * @param {Object.<string>=} opt_headers Additional headers to include on the
    132  *     request.
    133  * @param {boolean=} opt_withCredentials Set the withCredentials flags in the
    134  *     XHR.
    135  * @return {XMLHttpRequest} The XMLHttpRequest object.
    136  */
    137 remoting.xhr.doMethod = function(methodName, url, onDone,
    138                                  opt_parameters, opt_headers,
    139                                  opt_withCredentials) {
    140   /** @type {XMLHttpRequest} */
    141   var xhr = new XMLHttpRequest();
    142   xhr.onreadystatechange = function() {
    143     if (xhr.readyState != 4) {
    144       return;
    145     }
    146     onDone(xhr);
    147   };
    148 
    149   var parameterString = '';
    150   if (typeof(opt_parameters) === 'string') {
    151     parameterString = opt_parameters;
    152   } else if (typeof(opt_parameters) === 'object') {
    153     parameterString = remoting.xhr.urlencodeParamHash(opt_parameters);
    154   } else if (opt_parameters === undefined) {
    155     // No problem here. Do nothing.
    156   } else {
    157     throw 'opt_parameters must be string or associated array.';
    158   }
    159 
    160   var useBody = (methodName == 'POST') || (methodName == 'PUT');
    161 
    162   if (!useBody && parameterString != '') {
    163     url = url + '?' + parameterString;
    164   }
    165 
    166   xhr.open(methodName, url, true);
    167   if (methodName == 'POST' &&
    168       (typeof opt_headers !== 'object' ||
    169        typeof opt_headers['Content-type'] !== 'string')) {
    170     xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    171   }
    172   // Add in request headers.
    173   if (typeof(opt_headers) === 'object') {
    174     for (var key in opt_headers) {
    175       xhr.setRequestHeader(key, opt_headers[key]);
    176     }
    177   } else if (opt_headers === undefined) {
    178     // No problem here. Do nothing.
    179   } else {
    180     throw 'opt_headers must be associative array.';
    181   }
    182 
    183   if (opt_withCredentials) {
    184     xhr.withCredentials = true;
    185   }
    186 
    187   xhr.send(useBody ? parameterString : null);
    188   return xhr;
    189 };
    190