Bug 1325501 - move addons manager from XHR to ServiceRequest r?kmag draft
authorRobert Helmer <rhelmer@mozilla.com>
Thu, 22 Dec 2016 19:54:57 -0800
changeset 453692 bc261b7ac65cf985e7df9d443692ac45a61ea929
parent 453554 10b78c70df4cabdffb0ba5619bbe229a46517e3c
child 453693 d97d8c27fd04f0d5dcdd37eeb3a8d0b7374034a6
push id39728
push userrhelmer@mozilla.com
push dateSat, 24 Dec 2016 09:51:56 +0000
reviewerskmag
bugs1325501
milestone53.0a1
Bug 1325501 - move addons manager from XHR to ServiceRequest r?kmag MozReview-Commit-ID: J0ytKWqDOr3
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/internal/AddonRepository.jsm
toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/browser/browser_metadataTimeout.js
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -37,16 +37,19 @@ const PERSIST_ENABLED = true;
 const PERSIST_BYPASS_CACHE = false;
 const PERSIST_FILES = {
   headerURL: "lightweighttheme-header",
   footerURL: "lightweighttheme-footer"
 };
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer",
   "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
+  "resource://gre/modules/ServiceRequest.jsm");
+
 
 XPCOMUtils.defineLazyGetter(this, "_prefs", () => {
   return Services.prefs.getBranch("lightweightThemes.");
 });
 
 Object.defineProperty(this, "_maxUsedThemes", {
   get: function() {
     delete this._maxUsedThemes;
@@ -249,18 +252,17 @@ this.LightweightThemeManager = {
     } catch (e) {
       return;
     }
 
     var theme = this.currentTheme;
     if (!theme || !theme.updateURL)
       return;
 
-    var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
-                .createInstance(Ci.nsIXMLHttpRequest);
+    var req = new ServiceRequest();
 
     req.mozBackgroundRequest = true;
     req.overrideMimeType("text/plain");
     req.open("GET", theme.updateURL, true);
     // Prevent the request from reading from the cache.
     req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
     // Prevent the request from writing to the cache.
     req.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
--- a/toolkit/mozapps/extensions/internal/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonRepository.jsm
@@ -21,16 +21,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "DeferredSave",
                                   "resource://gre/modules/DeferredSave.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository_SQLiteMigrator",
                                   "resource://gre/modules/addons/AddonRepository_SQLiteMigrator.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
                                   "resource://gre/modules/Preferences.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
+                                  "resource://gre/modules/ServiceRequest.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 
 
 this.EXPORTED_SYMBOLS = [ "AddonRepository" ];
 
 const PREF_GETADDONS_CACHE_ENABLED       = "extensions.getAddons.cache.enabled";
 const PREF_GETADDONS_CACHE_TYPES         = "extensions.getAddons.cache.types";
@@ -95,20 +97,16 @@ const HTML_KEY_MAP = {
 // A map between XML keys to AddonSearchResult keys for integer values
 // that require no extra parsing from XML
 const INTEGER_KEY_MAP = {
   total_downloads:  "totalDownloads",
   weekly_downloads: "weeklyDownloads",
   daily_users:      "dailyUsers"
 };
 
-// Wrap the XHR factory so that tests can override with a mock
-var XHRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1",
-                                       "nsIXMLHttpRequest");
-
 function convertHTMLToPlainText(html) {
   if (!html)
     return html;
   var converter = Cc["@mozilla.org/widget/htmlformatconverter;1"].
                   createInstance(Ci.nsIFormatConverter);
 
   var input = Cc["@mozilla.org/supports-string;1"].
               createInstance(Ci.nsISupportsString);
@@ -1428,17 +1426,17 @@ this.AddonRepository = {
     }
 
     this._searching = true;
     this._callback = aCallback;
     this._maxResults = aMaxResults;
 
     logger.debug("Requesting " + aURI);
 
-    this._request = new XHRequest();
+    this._request = new ServiceRequest();
     this._request.mozBackgroundRequest = true;
     this._request.open("GET", aURI, true);
     this._request.overrideMimeType("text/xml");
     if (aTimeout) {
       this._request.timeout = aTimeout;
     }
 
     this._request.addEventListener("error", aEvent => this._reportFailure(), false);
--- a/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
@@ -30,16 +30,19 @@ Components.utils.import("resource://gre/
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
                                   "resource://gre/modules/addons/AddonRepository.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
+                                  "resource://gre/modules/ServiceRequest.jsm");
+
 
 // Shared code for suppressing bad cert dialogs.
 XPCOMUtils.defineLazyGetter(this, "CertUtils", function() {
   let certUtils = {};
   Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils);
   return certUtils;
 });
 
@@ -573,18 +576,17 @@ function UpdateParser(aId, aUpdateKey, a
   try {
     requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS);
   }
   catch (e) {
   }
 
   logger.debug("Requesting " + aUrl);
   try {
-    this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
-                   createInstance(Ci.nsIXMLHttpRequest);
+    this.request = new ServiceRequest();
     this.request.open("GET", this.url, true);
     this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(!requireBuiltIn);
     this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
     // Prevent the request from writing to cache.
     this.request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
     this.request.overrideMimeType("text/plain");
     this.request.setRequestHeader("Moz-XPI-Update", "1", true);
     this.request.timeout = TIMEOUT;
--- a/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm
+++ b/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm
@@ -37,25 +37,28 @@ Cu.import("resource://gre/modules/osfile
 XPCOMUtils.defineLazyModuleGetter(this, "GMPPrefs",
                                   "resource://gre/modules/GMPUtils.jsm");
 
 /* globals OS */
 
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                   "resource://gre/modules/UpdateUtils.jsm");
 
-var logger = Log.repository.getLogger("addons.productaddons");
+XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
+                                  "resource://gre/modules/ServiceRequest.jsm");
 
 // This exists so that tests can override the XHR behaviour for downloading
 // the addon update XML file.
 var CreateXHR = function() {
   return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
-    createInstance(Ci.nsISupports);
+  createInstance(Ci.nsISupports);
 }
 
+var logger = Log.repository.getLogger("addons.productaddons");
+
 /**
  * Number of milliseconds after which we need to cancel `downloadXML`.
  *
  * Bug 1087674 suggests that the XHR we use in `downloadXML` may
  * never terminate in presence of network nuisances (e.g. strange
  * antivirus behavior). This timeout is a defensive measure to ensure
  * that we fail cleanly in such case.
  */
@@ -108,16 +111,21 @@ function downloadXML(url, allowNonBuiltI
       request = request.wrappedJSObject;
     }
     request.open("GET", url, true);
     request.channel.notificationCallbacks = new BadCertHandler(allowNonBuiltIn);
     // Prevent the request from reading from the cache.
     request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
     // Prevent the request from writing to the cache.
     request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
+    // Use conservative TLS settings. See bug 1325501.
+    // TODO move to ServiceRequest.
+    if (request.channel instanceof Ci.nsIHttpChannelInternal) {
+      request.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true;
+    }
     request.timeout = TIMEOUT_DELAY_MS;
 
     request.overrideMimeType("text/xml");
     // The Cache-Control header is only interpreted by proxies and the
     // final destination. It does not help if a resource is already
     // cached locally.
     request.setRequestHeader("Cache-Control", "no-cache");
     // HTTP/1.0 servers might not implement Cache-Control and
@@ -158,17 +166,17 @@ function downloadXML(url, allowNonBuiltI
     logger.info("sending request to: " + url);
     request.send(null);
   });
 }
 
 function downloadJSON(uri) {
   logger.info("fetching config from: " + uri);
   return new Promise((resolve, reject) => {
-    let xmlHttp = new XMLHttpRequest({mozAnon: true});
+    let xmlHttp = new ServiceRequest({mozAnon: true});
 
     xmlHttp.onload = function(aResponse) {
       resolve(JSON.parse(this.responseText));
     };
 
     xmlHttp.onerror = function(e) {
       reject("Fetching " + uri + " results in error code: " + e.target.status);
     };
@@ -285,18 +293,17 @@ function downloadLocalConfig() {
  *
  * @param  url
  *         The url to download from.
  * @return a promise that resolves to the path of a temporary file or rejects
  *         with a JS exception in case of error.
  */
 function downloadFile(url) {
   return new Promise((resolve, reject) => {
-    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
-                  createInstance(Ci.nsISupports);
+    let xhr = new XMLHttpRequest();
     xhr.onload = function(response) {
       logger.info("downloadXHR File download. status=" + xhr.status);
       if (xhr.status != 200 && xhr.status != 206) {
         reject(Components.Exception("File download failed", xhr.status));
         return;
       }
       Task.spawn(function* () {
         let f = yield OS.File.openUnique(OS.Path.join(OS.Constants.Path.tmpDir, "tmpaddon"));
@@ -318,16 +325,21 @@ function downloadFile(url) {
       reject(ex);
     };
     xhr.addEventListener("error", fail);
     xhr.addEventListener("abort", fail);
 
     xhr.responseType = "arraybuffer";
     try {
       xhr.open("GET", url);
+      // Use conservative TLS settings. See bug 1325501.
+      // TODO move to ServiceRequest.
+      if (xhr.channel instanceof Ci.nsIHttpChannelInternal) {
+        xhr.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true;
+      }
       xhr.send(null);
     } catch (ex) {
       reject(ex);
     }
   });
 }
 
 /**
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -24,16 +24,18 @@ try {
 }
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                   "resource://gre/modules/UpdateUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
+                                  "resource://gre/modules/ServiceRequest.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org";
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_APPDIR                      = "XCurProcD";
 const FILE_BLOCKLIST                  = "blocklist.xml";
 const PREF_BLOCKLIST_LASTUPDATETIME   = "app.update.lastUpdateTime.blocklist-background-update-timer";
@@ -603,18 +605,17 @@ Blocklist.prototype = {
     }
     catch (e) {
       LOG("Blocklist::notify: There was an error creating the blocklist URI\r\n" +
           "for: " + dsURI + ", error: " + e);
       return;
     }
 
     LOG("Blocklist::notify: Requesting " + uri.spec);
-    var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
-                  createInstance(Ci.nsIXMLHttpRequest);
+    let request = new ServiceRequest();
     request.open("GET", uri.spec, true);
     request.channel.notificationCallbacks = new gCertUtils.BadCertHandler();
     request.overrideMimeType("text/xml");
     request.setRequestHeader("Cache-Control", "no-cache");
     request.QueryInterface(Components.interfaces.nsIJSXMLHttpRequest);
 
     request.addEventListener("error", event => this.onXMLError(event), false);
     request.addEventListener("load", event => this.onXMLLoad(event), false);
--- a/toolkit/mozapps/extensions/test/browser/browser_metadataTimeout.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_metadataTimeout.js
@@ -12,18 +12,18 @@ const PREF_METADATA_LASTUPDATE        = 
 Components.utils.import("resource://gre/modules/Promise.jsm");
 
 var repo = {};
 var ARContext = Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm", repo);
 
 // Mock out the XMLHttpRequest factory for AddonRepository so
 // we can reply with a timeout
 var pXHRStarted = Promise.defer();
-var oldXHRConstructor = ARContext.XHRequest;
-ARContext.XHRequest = function() {
+var oldXHRConstructor = ARContext.ServiceRequest;
+ARContext.ServiceRequest = function() {
   this._handlers = new Map();
   this.mozBackgroundRequest = false;
   this.timeout = undefined;
   this.open = function(aMethod, aURI, aAsync) {
       this.method = aMethod;
       this.uri = aURI;
       this.async = aAsync;
       info("Opened XHR for " + aMethod + " " + aURI);
@@ -101,12 +101,12 @@ add_task(function* amo_ping_timeout() {
 
   let xhr = yield pXHRStarted.promise;
   is(xhr.timeout, 30000, "XHR request should have 30 second timeout");
   ok(xhr._handlers.has("timeout"), "Timeout handler set on XHR");
   // call back the timeout handler
   xhr._handlers.get("timeout")();
 
   // Put the old XHR constructor back
-  ARContext.XHRequest = oldXHRConstructor;
+  ARContext.ServiceRequest = oldXHRConstructor;
   // The window should close without further interaction
   yield promise_window_close(compatWindow);
 });