Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
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 // A simple class that encapsulates a request. You'll notice the
6 // style here is different from the rest of the extension; that's
7 // because this was re-used from really old code we had. At some
8 // point it might be nice to replace this with something better
9 // (e.g., something that has explicit onerror handler, ability
10 // to set headers, and so on).
12 /**
13 * Because we might be in a component, we can't just assume that
14 * XMLHttpRequest exists. So we use this tiny factory function to wrap the
15 * XPCOM version.
16 *
17 * @return XMLHttpRequest object
18 */
19 function PROT_NewXMLHttpRequest() {
20 var Cc = Components.classes;
21 var Ci = Components.interfaces;
22 var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
23 .createInstance(Ci.nsIXMLHttpRequest);
24 // Need the following so we get onerror/load/progresschange
25 request.QueryInterface(Ci.nsIJSXMLHttpRequest);
26 return request;
27 }
29 /**
30 * A helper class that does HTTP GETs and calls back a function with
31 * the content it receives. Asynchronous, so uses a closure for the
32 * callback.
33 *
34 * Note, that XMLFetcher is only used for SafeBrowsing, therefore
35 * we inherit from nsILoadContext, so we can use the callbacks on the
36 * channel to separate the safebrowsing cookie based on a reserved
37 * appId.
38 * @constructor
39 */
40 function PROT_XMLFetcher() {
41 this.debugZone = "xmlfetcher";
42 this._request = PROT_NewXMLHttpRequest();
43 // implements nsILoadContext
44 this.appId = Ci.nsIScriptSecurityManager.SAFEBROWSING_APP_ID;
45 this.isInBrowserElement = false;
46 this.usePrivateBrowsing = false;
47 this.isContent = false;
48 }
50 PROT_XMLFetcher.prototype = {
51 /**
52 * Function that will be called back upon fetch completion.
53 */
54 _callback: null,
57 /**
58 * Fetches some content.
59 *
60 * @param page URL to fetch
61 * @param callback Function to call back when complete.
62 */
63 get: function(page, callback) {
64 this._request.abort(); // abort() is asynchronous, so
65 this._request = PROT_NewXMLHttpRequest();
66 this._callback = callback;
67 var asynchronous = true;
68 this._request.open("GET", page, asynchronous);
69 this._request.channel.notificationCallbacks = this;
71 // Create a closure
72 var self = this;
73 this._request.addEventListener("readystatechange", function() {
74 self.readyStateChange(self);
75 }, false);
77 this._request.send(null);
78 },
80 cancel: function() {
81 this._request.abort();
82 this._request = null;
83 },
85 /**
86 * Called periodically by the request to indicate some state change. 4
87 * means content has been received.
88 */
89 readyStateChange: function(fetcher) {
90 if (fetcher._request.readyState != 4)
91 return;
93 // If the request fails, on trunk we get status set to
94 // NS_ERROR_NOT_AVAILABLE. On 1.8.1 branch we get an exception
95 // forwarded from nsIHttpChannel::GetResponseStatus. To be consistent
96 // between branch and trunk, we send back NS_ERROR_NOT_AVAILABLE for
97 // http failures.
98 var responseText = null;
99 var status = Components.results.NS_ERROR_NOT_AVAILABLE;
100 try {
101 G_Debug(this, "xml fetch status code: \"" +
102 fetcher._request.status + "\"");
103 status = fetcher._request.status;
104 responseText = fetcher._request.responseText;
105 } catch(e) {
106 G_Debug(this, "Caught exception trying to read xmlhttprequest " +
107 "status/response.");
108 G_Debug(this, e);
109 }
110 if (fetcher._callback)
111 fetcher._callback(responseText, status);
112 },
114 // nsIInterfaceRequestor
115 getInterface: function(iid) {
116 return this.QueryInterface(iid);
117 },
119 QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor,
120 Ci.nsISupports,
121 Ci.nsILoadContext])
122 };