toolkit/modules/Http.jsm

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:630b93159651
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 const EXPORTED_SYMBOLS = ["httpRequest", "percentEncode"];
6
7 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
8
9 // Strictly follow RFC 3986 when encoding URI components.
10 // Accepts a unescaped string and returns the URI encoded string for use in
11 // an HTTP request.
12 function percentEncode(aString)
13 encodeURIComponent(aString).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
14
15 /*
16 * aOptions can have a variety of fields:
17 * headers, an array of headers
18 * postData, this can be:
19 * a string: send it as is
20 * an array of parameters: encode as form values
21 * null/undefined: no POST data.
22 * method, GET, POST or PUT (this is set automatically if postData exists).
23 * onLoad, a function handle to call when the load is complete, it takes two
24 * parameters: the responseText and the XHR object.
25 * onError, a function handle to call when an error occcurs, it takes three
26 * parameters: the error, the responseText and the XHR object.
27 * logger, an object that implements the debug and log methods (e.g. log.jsm).
28 *
29 * Headers or post data are given as an array of arrays, for each each inner
30 * array the first value is the key and the second is the value, e.g.
31 * [["key1", "value1"], ["key2", "value2"]].
32 */
33 function httpRequest(aUrl, aOptions) {
34 let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
35 .createInstance(Ci.nsIXMLHttpRequest);
36 xhr.mozBackgroundRequest = true; // no error dialogs
37 xhr.open(aOptions.method || (aOptions.postData ? "POST" : "GET"), aUrl);
38 xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS | // don't send cookies
39 Ci.nsIChannel.LOAD_BYPASS_CACHE |
40 Ci.nsIChannel.INHIBIT_CACHING;
41 xhr.onerror = function(aProgressEvent) {
42 if (aOptions.onError) {
43 // adapted from toolkit/mozapps/extensions/nsBlocklistService.js
44 let request = aProgressEvent.target;
45 let status;
46 try {
47 // may throw (local file or timeout)
48 status = request.status;
49 }
50 catch (e) {
51 request = request.channel.QueryInterface(Ci.nsIRequest);
52 status = request.status;
53 }
54 // When status is 0 we don't have a valid channel.
55 let statusText = status ? request.statusText : "offline";
56 aOptions.onError(statusText, null, this);
57 }
58 };
59 xhr.onload = function(aRequest) {
60 try {
61 let target = aRequest.target;
62 if (aOptions.logger)
63 aOptions.logger.debug("Received response: " + target.responseText);
64 if (target.status < 200 || target.status >= 300) {
65 let errorText = target.responseText;
66 if (!errorText || /<(ht|\?x)ml\b/i.test(errorText))
67 errorText = target.statusText;
68 throw target.status + " - " + errorText;
69 }
70 if (aOptions.onLoad)
71 aOptions.onLoad(target.responseText, this);
72 } catch (e) {
73 Cu.reportError(e);
74 if (aOptions.onError)
75 aOptions.onError(e, aRequest.target.responseText, this);
76 }
77 };
78
79 if (aOptions.headers) {
80 aOptions.headers.forEach(function(header) {
81 xhr.setRequestHeader(header[0], header[1]);
82 });
83 }
84
85 // Handle adding postData as defined above.
86 let POSTData = aOptions.postData || "";
87 if (Array.isArray(POSTData)) {
88 xhr.setRequestHeader("Content-Type",
89 "application/x-www-form-urlencoded; charset=utf-8");
90 POSTData = POSTData.map(function(p) p[0] + "=" + percentEncode(p[1]))
91 .join("&");
92 }
93
94 if (aOptions.logger) {
95 aOptions.logger.log("sending request to " + aUrl + " (POSTData = " +
96 POSTData + ")");
97 }
98 xhr.send(POSTData);
99 return xhr;
100 }

mercurial