Bug 1837494 [wpt PR 40457] - Ignore urllib3's warnings when run on LibreSSL, a=testonly
[gecko.git] / toolkit / modules / Http.sys.mjs
blobfaa487abe68d6bc0af1bb74e7571bdee909a7ba4
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/. */
5 // Strictly follow RFC 3986 when encoding URI components.
6 // Accepts a unescaped string and returns the URI encoded string for use in
7 // an HTTP request.
8 export function percentEncode(aString) {
9   return encodeURIComponent(aString)
10     .replace(/[!'()]/g, escape)
11     .replace(/\*/g, "%2A");
15  * aOptions can have a variety of fields:
16  *  headers, an array of headers
17  *  postData, this can be:
18  *    a string: send it as is
19  *    an array of parameters: encode as form values
20  *    null/undefined: no POST data.
21  *  method, GET, POST or PUT (this is set automatically if postData exists).
22  *  onLoad, a function handle to call when the load is complete, it takes two
23  *          parameters: the responseText and the XHR object.
24  *  onError, a function handle to call when an error occcurs, it takes three
25  *          parameters: the error, the responseText and the XHR object.
26  *  logger, an object that implements the debug and log methods (e.g. Log.sys.mjs).
27  *
28  * Headers or post data are given as an array of arrays, for each each inner
29  * array the first value is the key and the second is the value, e.g.
30  *  [["key1", "value1"], ["key2", "value2"]].
31  */
32 export function httpRequest(aUrl, aOptions) {
33   let xhr = new XMLHttpRequest();
34   xhr.mozBackgroundRequest = true; // no error dialogs
35   xhr.open(aOptions.method || (aOptions.postData ? "POST" : "GET"), aUrl);
36   xhr.channel.loadFlags =
37     Ci.nsIChannel.LOAD_ANONYMOUS | // don't send cookies
38     Ci.nsIChannel.LOAD_BYPASS_CACHE |
39     Ci.nsIChannel.INHIBIT_CACHING;
40   xhr.onerror = function (aProgressEvent) {
41     if (aOptions.onError) {
42       // adapted from toolkit/mozapps/extensions/nsBlocklistService.js
43       let request = aProgressEvent.target;
44       let status;
45       try {
46         // may throw (local file or timeout)
47         status = request.status;
48       } catch (e) {
49         request = request.channel.QueryInterface(Ci.nsIRequest);
50         status = request.status;
51       }
52       // When status is 0 we don't have a valid channel.
53       let statusText = status ? request.statusText : "offline";
54       aOptions.onError(statusText, null, this);
55     }
56   };
57   xhr.onload = function (aRequest) {
58     try {
59       let target = aRequest.target;
60       if (aOptions.logger) {
61         aOptions.logger.debug("Received response: " + target.responseText);
62       }
63       if (target.status < 200 || target.status >= 300) {
64         let errorText = target.responseText;
65         if (!errorText || /<(ht|\?x)ml\b/i.test(errorText)) {
66           errorText = target.statusText;
67         }
68         throw new Error(target.status + " - " + errorText);
69       }
70       if (aOptions.onLoad) {
71         aOptions.onLoad(target.responseText, this);
72       }
73     } catch (e) {
74       if (aOptions.onError) {
75         aOptions.onError(e, aRequest.target.responseText, this);
76       }
77     }
78   };
80   if (aOptions.headers) {
81     aOptions.headers.forEach(function (header) {
82       xhr.setRequestHeader(header[0], header[1]);
83     });
84   }
86   // Handle adding postData as defined above.
87   let POSTData = aOptions.postData || null;
88   if (POSTData && Array.isArray(POSTData)) {
89     xhr.setRequestHeader(
90       "Content-Type",
91       "application/x-www-form-urlencoded; charset=utf-8"
92     );
93     POSTData = POSTData.map(p => p[0] + "=" + percentEncode(p[1])).join("&");
94   }
96   if (aOptions.logger) {
97     aOptions.logger.log(
98       "sending request to " + aUrl + " (POSTData = " + POSTData + ")"
99     );
100   }
101   xhr.send(POSTData);
102   return xhr;