// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview * Simple utilities for making XHRs more pleasant. */ 'use strict'; /** @suppress {duplicate} */ var remoting = remoting || {}; /** Namespace for XHR functions */ /** @type {Object} */ remoting.xhr = remoting.xhr || {}; /** * Takes an associative array of parameters and urlencodes it. * * @param {Object.<string>} paramHash The parameter key/value pairs. * @return {string} URLEncoded version of paramHash. */ remoting.xhr.urlencodeParamHash = function(paramHash) { var paramArray = []; for (var key in paramHash) { paramArray.push(encodeURIComponent(key) + '=' + encodeURIComponent(paramHash[key])); } if (paramArray.length > 0) { return paramArray.join('&'); } return ''; }; /** * Execute an XHR GET asynchronously. * * @param {string} url The base URL to GET, excluding parameters. * @param {function(XMLHttpRequest):void} onDone The function to call on * completion. * @param {(string|Object.<string>)=} opt_parameters The request parameters, * either as an associative array, or a string. If it is a string, do * not include the ? and be sure it is correctly URLEncoded. * @param {Object.<string>=} opt_headers Additional headers to include on the * request. * @param {boolean=} opt_withCredentials Set the withCredentials flags in the * XHR. * @return {XMLHttpRequest} The request object. */ remoting.xhr.get = function(url, onDone, opt_parameters, opt_headers, opt_withCredentials) { return remoting.xhr.doMethod('GET', url, onDone, opt_parameters, opt_headers, opt_withCredentials); }; /** * Execute an XHR POST asynchronously. * * @param {string} url The base URL to POST, excluding parameters. * @param {function(XMLHttpRequest):void} onDone The function to call on * completion. * @param {(string|Object.<string>)=} opt_parameters The request parameters, * either as an associative array, or a string. If it is a string, be * sure it is correctly URLEncoded. * @param {Object.<string>=} opt_headers Additional headers to include on the * request. * @param {boolean=} opt_withCredentials Set the withCredentials flags in the * XHR. * @return {XMLHttpRequest} The request object. */ remoting.xhr.post = function(url, onDone, opt_parameters, opt_headers, opt_withCredentials) { return remoting.xhr.doMethod('POST', url, onDone, opt_parameters, opt_headers, opt_withCredentials); }; /** * Execute an XHR DELETE asynchronously. * * @param {string} url The base URL to DELETE, excluding parameters. * @param {function(XMLHttpRequest):void} onDone The function to call on * completion. * @param {(string|Object.<string>)=} opt_parameters The request parameters, * either as an associative array, or a string. If it is a string, be * sure it is correctly URLEncoded. * @param {Object.<string>=} opt_headers Additional headers to include on the * request. * @param {boolean=} opt_withCredentials Set the withCredentials flags in the * XHR. * @return {XMLHttpRequest} The request object. */ remoting.xhr.remove = function(url, onDone, opt_parameters, opt_headers, opt_withCredentials) { return remoting.xhr.doMethod('DELETE', url, onDone, opt_parameters, opt_headers, opt_withCredentials); }; /** * Execute an XHR PUT asynchronously. * * @param {string} url The base URL to PUT, excluding parameters. * @param {function(XMLHttpRequest):void} onDone The function to call on * completion. * @param {(string|Object.<string>)=} opt_parameters The request parameters, * either as an associative array, or a string. If it is a string, be * sure it is correctly URLEncoded. * @param {Object.<string>=} opt_headers Additional headers to include on the * request. * @param {boolean=} opt_withCredentials Set the withCredentials flags in the * XHR. * @return {XMLHttpRequest} The request object. */ remoting.xhr.put = function(url, onDone, opt_parameters, opt_headers, opt_withCredentials) { return remoting.xhr.doMethod('PUT', url, onDone, opt_parameters, opt_headers, opt_withCredentials); }; /** * Execute an arbitrary HTTP method asynchronously. * * @param {string} methodName The HTTP method name, e.g. "GET", "POST" etc. * @param {string} url The base URL, excluding parameters. * @param {function(XMLHttpRequest):void} onDone The function to call on * completion. * @param {(string|Object.<string>)=} opt_parameters The request parameters, * either as an associative array, or a string. If it is a string, be * sure it is correctly URLEncoded. * @param {Object.<string>=} opt_headers Additional headers to include on the * request. * @param {boolean=} opt_withCredentials Set the withCredentials flags in the * XHR. * @return {XMLHttpRequest} The XMLHttpRequest object. */ remoting.xhr.doMethod = function(methodName, url, onDone, opt_parameters, opt_headers, opt_withCredentials) { /** @type {XMLHttpRequest} */ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState != 4) { return; } onDone(xhr); }; var parameterString = ''; if (typeof(opt_parameters) === 'string') { parameterString = opt_parameters; } else if (typeof(opt_parameters) === 'object') { parameterString = remoting.xhr.urlencodeParamHash(opt_parameters); } else if (opt_parameters === undefined) { // No problem here. Do nothing. } else { throw 'opt_parameters must be string or associated array.'; } var useBody = (methodName == 'POST') || (methodName == 'PUT'); if (!useBody && parameterString != '') { url = url + '?' + parameterString; } xhr.open(methodName, url, true); if (methodName == 'POST' && (typeof opt_headers !== 'object' || typeof opt_headers['Content-type'] !== 'string')) { xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } // Add in request headers. if (typeof(opt_headers) === 'object') { for (var key in opt_headers) { xhr.setRequestHeader(key, opt_headers[key]); } } else if (opt_headers === undefined) { // No problem here. Do nothing. } else { throw 'opt_headers must be associative array.'; } if (opt_withCredentials) { xhr.withCredentials = true; } xhr.send(useBody ? parameterString : null); return xhr; };