michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: // A simple class that encapsulates a request. You'll notice the michael@0: // style here is different from the rest of the extension; that's michael@0: // because this was re-used from really old code we had. At some michael@0: // point it might be nice to replace this with something better michael@0: // (e.g., something that has explicit onerror handler, ability michael@0: // to set headers, and so on). michael@0: michael@0: /** michael@0: * Because we might be in a component, we can't just assume that michael@0: * XMLHttpRequest exists. So we use this tiny factory function to wrap the michael@0: * XPCOM version. michael@0: * michael@0: * @return XMLHttpRequest object michael@0: */ michael@0: function PROT_NewXMLHttpRequest() { michael@0: var Cc = Components.classes; michael@0: var Ci = Components.interfaces; michael@0: var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] michael@0: .createInstance(Ci.nsIXMLHttpRequest); michael@0: // Need the following so we get onerror/load/progresschange michael@0: request.QueryInterface(Ci.nsIJSXMLHttpRequest); michael@0: return request; michael@0: } michael@0: michael@0: /** michael@0: * A helper class that does HTTP GETs and calls back a function with michael@0: * the content it receives. Asynchronous, so uses a closure for the michael@0: * callback. michael@0: * michael@0: * Note, that XMLFetcher is only used for SafeBrowsing, therefore michael@0: * we inherit from nsILoadContext, so we can use the callbacks on the michael@0: * channel to separate the safebrowsing cookie based on a reserved michael@0: * appId. michael@0: * @constructor michael@0: */ michael@0: function PROT_XMLFetcher() { michael@0: this.debugZone = "xmlfetcher"; michael@0: this._request = PROT_NewXMLHttpRequest(); michael@0: // implements nsILoadContext michael@0: this.appId = Ci.nsIScriptSecurityManager.SAFEBROWSING_APP_ID; michael@0: this.isInBrowserElement = false; michael@0: this.usePrivateBrowsing = false; michael@0: this.isContent = false; michael@0: } michael@0: michael@0: PROT_XMLFetcher.prototype = { michael@0: /** michael@0: * Function that will be called back upon fetch completion. michael@0: */ michael@0: _callback: null, michael@0: michael@0: michael@0: /** michael@0: * Fetches some content. michael@0: * michael@0: * @param page URL to fetch michael@0: * @param callback Function to call back when complete. michael@0: */ michael@0: get: function(page, callback) { michael@0: this._request.abort(); // abort() is asynchronous, so michael@0: this._request = PROT_NewXMLHttpRequest(); michael@0: this._callback = callback; michael@0: var asynchronous = true; michael@0: this._request.open("GET", page, asynchronous); michael@0: this._request.channel.notificationCallbacks = this; michael@0: michael@0: // Create a closure michael@0: var self = this; michael@0: this._request.addEventListener("readystatechange", function() { michael@0: self.readyStateChange(self); michael@0: }, false); michael@0: michael@0: this._request.send(null); michael@0: }, michael@0: michael@0: cancel: function() { michael@0: this._request.abort(); michael@0: this._request = null; michael@0: }, michael@0: michael@0: /** michael@0: * Called periodically by the request to indicate some state change. 4 michael@0: * means content has been received. michael@0: */ michael@0: readyStateChange: function(fetcher) { michael@0: if (fetcher._request.readyState != 4) michael@0: return; michael@0: michael@0: // If the request fails, on trunk we get status set to michael@0: // NS_ERROR_NOT_AVAILABLE. On 1.8.1 branch we get an exception michael@0: // forwarded from nsIHttpChannel::GetResponseStatus. To be consistent michael@0: // between branch and trunk, we send back NS_ERROR_NOT_AVAILABLE for michael@0: // http failures. michael@0: var responseText = null; michael@0: var status = Components.results.NS_ERROR_NOT_AVAILABLE; michael@0: try { michael@0: G_Debug(this, "xml fetch status code: \"" + michael@0: fetcher._request.status + "\""); michael@0: status = fetcher._request.status; michael@0: responseText = fetcher._request.responseText; michael@0: } catch(e) { michael@0: G_Debug(this, "Caught exception trying to read xmlhttprequest " + michael@0: "status/response."); michael@0: G_Debug(this, e); michael@0: } michael@0: if (fetcher._callback) michael@0: fetcher._callback(responseText, status); michael@0: }, michael@0: michael@0: // nsIInterfaceRequestor michael@0: getInterface: function(iid) { michael@0: return this.QueryInterface(iid); michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor, michael@0: Ci.nsISupports, michael@0: Ci.nsILoadContext]) michael@0: };