1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/modules/Http.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,100 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +const EXPORTED_SYMBOLS = ["httpRequest", "percentEncode"]; 1.9 + 1.10 +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; 1.11 + 1.12 +// Strictly follow RFC 3986 when encoding URI components. 1.13 +// Accepts a unescaped string and returns the URI encoded string for use in 1.14 +// an HTTP request. 1.15 +function percentEncode(aString) 1.16 + encodeURIComponent(aString).replace(/[!'()]/g, escape).replace(/\*/g, "%2A"); 1.17 + 1.18 +/* 1.19 + * aOptions can have a variety of fields: 1.20 + * headers, an array of headers 1.21 + * postData, this can be: 1.22 + * a string: send it as is 1.23 + * an array of parameters: encode as form values 1.24 + * null/undefined: no POST data. 1.25 + * method, GET, POST or PUT (this is set automatically if postData exists). 1.26 + * onLoad, a function handle to call when the load is complete, it takes two 1.27 + * parameters: the responseText and the XHR object. 1.28 + * onError, a function handle to call when an error occcurs, it takes three 1.29 + * parameters: the error, the responseText and the XHR object. 1.30 + * logger, an object that implements the debug and log methods (e.g. log.jsm). 1.31 + * 1.32 + * Headers or post data are given as an array of arrays, for each each inner 1.33 + * array the first value is the key and the second is the value, e.g. 1.34 + * [["key1", "value1"], ["key2", "value2"]]. 1.35 + */ 1.36 +function httpRequest(aUrl, aOptions) { 1.37 + let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] 1.38 + .createInstance(Ci.nsIXMLHttpRequest); 1.39 + xhr.mozBackgroundRequest = true; // no error dialogs 1.40 + xhr.open(aOptions.method || (aOptions.postData ? "POST" : "GET"), aUrl); 1.41 + xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS | // don't send cookies 1.42 + Ci.nsIChannel.LOAD_BYPASS_CACHE | 1.43 + Ci.nsIChannel.INHIBIT_CACHING; 1.44 + xhr.onerror = function(aProgressEvent) { 1.45 + if (aOptions.onError) { 1.46 + // adapted from toolkit/mozapps/extensions/nsBlocklistService.js 1.47 + let request = aProgressEvent.target; 1.48 + let status; 1.49 + try { 1.50 + // may throw (local file or timeout) 1.51 + status = request.status; 1.52 + } 1.53 + catch (e) { 1.54 + request = request.channel.QueryInterface(Ci.nsIRequest); 1.55 + status = request.status; 1.56 + } 1.57 + // When status is 0 we don't have a valid channel. 1.58 + let statusText = status ? request.statusText : "offline"; 1.59 + aOptions.onError(statusText, null, this); 1.60 + } 1.61 + }; 1.62 + xhr.onload = function(aRequest) { 1.63 + try { 1.64 + let target = aRequest.target; 1.65 + if (aOptions.logger) 1.66 + aOptions.logger.debug("Received response: " + target.responseText); 1.67 + if (target.status < 200 || target.status >= 300) { 1.68 + let errorText = target.responseText; 1.69 + if (!errorText || /<(ht|\?x)ml\b/i.test(errorText)) 1.70 + errorText = target.statusText; 1.71 + throw target.status + " - " + errorText; 1.72 + } 1.73 + if (aOptions.onLoad) 1.74 + aOptions.onLoad(target.responseText, this); 1.75 + } catch (e) { 1.76 + Cu.reportError(e); 1.77 + if (aOptions.onError) 1.78 + aOptions.onError(e, aRequest.target.responseText, this); 1.79 + } 1.80 + }; 1.81 + 1.82 + if (aOptions.headers) { 1.83 + aOptions.headers.forEach(function(header) { 1.84 + xhr.setRequestHeader(header[0], header[1]); 1.85 + }); 1.86 + } 1.87 + 1.88 + // Handle adding postData as defined above. 1.89 + let POSTData = aOptions.postData || ""; 1.90 + if (Array.isArray(POSTData)) { 1.91 + xhr.setRequestHeader("Content-Type", 1.92 + "application/x-www-form-urlencoded; charset=utf-8"); 1.93 + POSTData = POSTData.map(function(p) p[0] + "=" + percentEncode(p[1])) 1.94 + .join("&"); 1.95 + } 1.96 + 1.97 + if (aOptions.logger) { 1.98 + aOptions.logger.log("sending request to " + aUrl + " (POSTData = " + 1.99 + POSTData + ")"); 1.100 + } 1.101 + xhr.send(POSTData); 1.102 + return xhr; 1.103 +}