Bug 1257565 - Reload from disk when kinto blocklist was updated r=mossop draft
authorMathieu Leplatre <mathieu@mozilla.com>
Thu, 27 Apr 2017 23:27:58 +0200
changeset 655876 ec694449eb74d5b785647ef23af52df7ac4ceb86
parent 655875 a6e455380cdbffe70f270203921765eae3c16f33
child 655877 1f143c049ecc6dc49e83350b10a8b877e5822675
push id76975
push usermleplatre@mozilla.com
push dateWed, 30 Aug 2017 12:43:51 +0000
reviewersmossop
bugs1257565
milestone57.0a1
Bug 1257565 - Reload from disk when kinto blocklist was updated r=mossop MozReview-Commit-ID: JPrDybWvbGc
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_json.js
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -289,16 +289,17 @@ function Blocklist() {
   gBlocklistLevel = Math.min(getPref("getIntPref", PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
                                      MAX_BLOCK_LEVEL);
   gPref.addObserver("extensions.blocklist.", this);
   gPref.addObserver(PREF_EM_LOGGING_ENABLED, this);
   this.wrappedJSObject = this;
   // requests from child processes come in here, see receiveMessage.
   Services.ppmm.addMessageListener("Blocklist:getPluginBlocklistState", this);
   Services.ppmm.addMessageListener("Blocklist:content-blocklist-updated", this);
+  Services.ppmm.addMessageListener("Blocklist:reload-from-disk", this);
 }
 
 Blocklist.prototype = {
   /**
    * Extension ID -> array of Version Ranges
    * Each value in the version range array is a JS Object that has the
    * following properties:
    *   "minVersion"  The minimum version in a version range (default = 0)
@@ -315,16 +316,17 @@ Blocklist.prototype = {
   _addonEntries: null,
   _gfxEntries: null,
   _pluginEntries: null,
 
   shutdown() {
     Services.obs.removeObserver(this, "xpcom-shutdown");
     Services.ppmm.removeMessageListener("Blocklist:getPluginBlocklistState", this);
     Services.ppmm.removeMessageListener("Blocklist:content-blocklist-updated", this);
+    Services.ppmm.removeMessageListener("Blocklist:reload-from-disk", this);
     gPref.removeObserver("extensions.blocklist.", this);
     gPref.removeObserver(PREF_EM_LOGGING_ENABLED, this);
   },
 
   observe(aSubject, aTopic, aData) {
     switch (aTopic) {
     case "xpcom-shutdown":
       this.shutdown();
@@ -360,16 +362,30 @@ Blocklist.prototype = {
 
   // Message manager message handlers
   receiveMessage(aMsg) {
     switch (aMsg.name) {
       case "Blocklist:getPluginBlocklistState":
         return this.getPluginBlocklistState(aMsg.data.addonData,
                                             aMsg.data.appVersion,
                                             aMsg.data.toolkitVersion);
+      case "Blocklist:reload-from-disk":
+        // If blocklist updates are managed via Kinto, reload the new blocklist
+        // content from the recently updated files.
+        // Certificates are not concerned, their revokation is updated in
+        // OneCRLBlocklistClient from services/common/blocklist-clients.js.
+        if (!gBlocklistFromXML) {
+          const oldAddonEntries = this._addonEntries;
+          const oldPluginEntries = this._pluginEntries;
+          // Read JSON files from disk.
+          this._loadBlocklist();
+          // Update status of addons/plugins (mimic what happens in onXMLLoad()).
+          this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
+        }
+        break;
       case "Blocklist:content-blocklist-updated":
         Services.obs.notifyObservers(null, "content-blocklist-updated");
         break;
       default:
         throw new Error("Unknown blocklist message received from content: " + aMsg.name);
     }
     return undefined;
   },
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_json.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_json.js
@@ -326,16 +326,77 @@ add_task(function* load_uses_preloaded_j
 
   // Data loaded comes from preloaded content.
   equal(blocklist._addonEntries[0].blockID, SAMPLE_ADDON_RECORD.blockID);
   equal(blocklist._gfxEntries[0].blockID, SAMPLE_GFX_RECORD.blockID);
   equal(blocklist._pluginEntries[0].blockID, SAMPLE_PLUGIN_RECORD.blockID);
 });
 
 
+add_task(function* test_blocklist_is_reloaded_when_message_is_received() {
+  const blocklist = Blocklist();
+
+  blocklist._loadBlocklist();
+
+  // Write a fake JSON file in profile dir.
+  copyToProfile(SAMPLE_FILE, "addons");
+
+  // Send message.
+  yield Services.cpmm.sendAsyncMessage("Blocklist:reload-from-disk");
+
+  // Since message is loaded asynchronously, wait for its reception.
+  yield new Promise((resolve) => {
+    Services.obs.addObserver(function() {
+      Services.obs.removeObserver(arguments.callee, "blocklist-updated");
+      resolve();
+    }, "blocklist-updated");
+  });
+
+  // Blocklist was reloaded with the content from file.
+  equal(blocklist._addonEntries[0].blockID, "i53923");
+});
+
+
+add_task(function* test_message_is_sent_when_blocklist_is_refreshed() {
+  Services.prefs.setCharPref("services.settings.server",
+                             `http://localhost:${gPort}/v1`);
+  Services.prefs.setBoolPref("services.blocklist.signing.enforced", false);
+
+  testserver.registerPathHandler("/v1/", (request, response) => response.write(`{}`));
+  testserver.registerPathHandler("/v1/buckets/monitor/collections/changes/records", (request, response) => {
+    response.write(`{"data": [{"bucket": "blocklists", "collection": "addons"}]}`);
+  });
+  testserver.registerPathHandler("/v1/buckets/blocklists/collections/addons", (request, response) => {
+    response.write(`{"data": {}}`);
+  });
+  testserver.registerPathHandler("/v1/buckets/blocklists/collections/addons/records", (request, response) => {
+    response.write(`{"data": [${JSON.stringify(SAMPLE_ADDON_RECORD)}]}`);
+  });
+
+  const blocklist = Blocklist();
+
+  const filename = yield new Promise((resolve) => {
+    const event = "Blocklist:reload-from-disk";
+    const observer = {
+      receiveMessage(aMsg) {
+        if (aMsg.name == event) {
+          Services.ppmm.removeMessageListener(event, this);
+          resolve(aMsg.data.filename);
+        }
+      }
+    };
+    Services.ppmm.addMessageListener(event, observer);
+
+    blocklist.notify(null);
+  });
+
+  ok(/addons.json/.test(filename));
+});
+
+
 add_task(function* test_read_json_from_app_or_profile() {
   const blocklist = Blocklist();
 
   // Reads from app dir by default.
   clearProfile("addons");
   blocklist._loadBlocklist();
   ok(blocklist._addonEntries.length >= 416);