Bug 806534 - Support regular expressions in extension id for blocklist entries. r=Mossop, a=akeybl
authorBlair McBride <bmcbride@mozilla.com>
Fri, 07 Dec 2012 12:23:04 -0800
changeset 109913 b693c6e5139025594691e4870ebe90f5979b0fd8
parent 109912 618ffd249ae7b755a33ea6808c5a9b1c553c0808
child 109914 99313a46008c0f24f92fa07b1e293419a29be044
push id52
push userryanvm@gmail.com
push dateMon, 10 Dec 2012 15:53:32 +0000
reviewersMossop, akeybl
bugs806534
milestone17.0.1esrpre
Bug 806534 - Support regular expressions in extension id for blocklist entries. r=Mossop, a=akeybl
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/addons/blocklist_regexp1_1/install.rdf
toolkit/mozapps/extensions/test/addons/blocklist_regexp1_2/install.rdf
toolkit/mozapps/extensions/test/addons/blocklist_regexp1_3/install.rdf
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -271,16 +271,32 @@ function getDistributionPrefValue(aPrefN
   } catch (e) {
     // use default when pref not found
   }
 
   return prefValue;
 }
 
 /**
+ * Parse a string representation of a regular expression. Needed because we
+ * use the /pattern/flags form (because it's detectable), which is only
+ * supported as a literal in JS.
+ *
+ * @param  aStr
+ *         String representation of regexp
+ * @return RegExp instance
+ */
+function parseRegExp(aStr) {
+  let lastSlash = aStr.lastIndexOf("/");
+  let pattern = aStr.slice(1, lastSlash);
+  let flags = aStr.slice(lastSlash + 1);
+  return new RegExp(pattern, flags);
+}
+
+/**
  * Manages the Blocklist. The Blocklist is a representation of the contents of
  * blocklist.xml and allows us to remotely disable / re-enable blocklisted
  * items managed by the Extension Manager with an item's appDisabled property.
  * It also blocklists plugins with data from blocklist.xml.
  */
 
 function Blocklist() {
   let os = getObserverService();
@@ -372,37 +388,50 @@ Blocklist.prototype = {
     if (!gBlocklistEnabled)
       return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
 
     if (!appVersion)
       appVersion = gApp.version;
     if (!toolkitVersion)
       toolkitVersion = gApp.platformVersion;
 
-    var blItem = addonEntries[id];
+    var blItem = this._findMatchingAddonEntry(addonEntries, id);
     if (!blItem)
       return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
 
-    for (let currentblItem of blItem) {
+    for (let currentblItem of blItem.versions) {
       if (currentblItem.includesItem(version, appVersion, toolkitVersion))
         return currentblItem.severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED :
                                                        Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
     }
     return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
   },
 
+  _findMatchingAddonEntry: function Blocklist_findMatchingAddonEntry(aAddonEntries,
+                                                                     aId) {
+    for (let entry of aAddonEntries) {
+      if (entry.id instanceof RegExp) {
+        if (entry.id.test(aId))
+          return entry;
+      } else if (entry.id == aId) {
+        return entry;
+      }
+    }
+    return null;
+  },
+
   /* See nsIBlocklistService */
   getAddonBlocklistURL: function(id, version, appVersion, toolkitVersion) {
     if (!gBlocklistEnabled)
       return "";
 
     if (!this._addonEntries)
       this._loadBlocklist();
 
-    let blItem = this._addonEntries[id];
+    let blItem = this._findMatchingAddonEntry(this._addonEntries, id);
     if (!blItem || !blItem.blockID)
       return null;
 
     return this._createBlocklistURL(blItem.blockID);
   },
 
   _createBlocklistURL: function(id) {
     let url = Services.urlFormatter.formatURLPref(PREF_BLOCKLIST_ITEM_URL);
@@ -544,18 +573,18 @@ Blocklist.prototype = {
     if (blocklistFile.exists())
       blocklistFile.remove(false);
     var fos = FileUtils.openSafeFileOutputStream(blocklistFile);
     fos.write(request.responseText, request.responseText.length);
     FileUtils.closeSafeFileOutputStream(fos);
 
     var oldAddonEntries = this._addonEntries;
     var oldPluginEntries = this._pluginEntries;
-    this._addonEntries = { };
-    this._pluginEntries = { };
+    this._addonEntries = [];
+    this._pluginEntries = [];
     this._loadBlocklistFromFile(FileUtils.getFile(KEY_PROFILEDIR,
                                                   [FILE_BLOCKLIST]));
 
     this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
   },
 
   onXMLError: function(aEvent) {
     try {
@@ -579,18 +608,18 @@ Blocklist.prototype = {
         statusText);
   },
 
   /**
    * Finds the newest blocklist file from the application and the profile and
    * load it or does nothing if neither exist.
    */
   _loadBlocklist: function() {
-    this._addonEntries = { };
-    this._pluginEntries = { };
+    this._addonEntries = [];
+    this._pluginEntries = [];
     var profFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
     if (profFile.exists()) {
       this._loadBlocklistFromFile(profFile);
       return;
     }
     var appFile = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
     if (appFile.exists()) {
       this._loadBlocklistFromFile(appFile);
@@ -634,17 +663,17 @@ Blocklist.prototype = {
 #          </versionRange>
 #        </emItem>
 #        <emItem id="item_4@domain" blockID="i3">
 #          <versionRange>
 #            <targetApplication>
 #              <versionRange minVersion="1.5" maxVersion="1.5.*"/>
 #            </targetApplication>
 #          </versionRange>
-#        <emItem id="item_5@domain"/>
+#        <emItem id="/@badperson\.com$/"/>
 #      </emItems>
 #      <pluginItems>
 #        <pluginItem blockID="i4">
 #          <!-- All match tags must match a plugin to blocklist a plugin -->
 #          <match name="name" exp="some plugin"/>
 #          <match name="description" exp="1[.]2[.]3"/>
 #        </pluginItem>
 #      </pluginItems>
@@ -716,33 +745,45 @@ Blocklist.prototype = {
     }
     return result;
   },
 
   _handleEmItemNode: function(blocklistElement, result) {
     if (!matchesOSABI(blocklistElement))
       return;
 
+    let blockEntry = {
+      id: null,
+      versions: [],
+      blockID: null
+    };
+
     var versionNodes = blocklistElement.childNodes;
     var id = blocklistElement.getAttribute("id");
-    result[id] = [];
+    // Add-on IDs cannot contain '/', so an ID starting with '/' must be a regex
+    if (id.startsWith("/"))
+      id = parseRegExp(id);
+    blockEntry.id = id;
+
     for (var x = 0; x < versionNodes.length; ++x) {
       var versionRangeElement = versionNodes.item(x);
       if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
           versionRangeElement.localName != "versionRange")
         continue;
 
-      result[id].push(new BlocklistItemData(versionRangeElement));
+      blockEntry.versions.push(new BlocklistItemData(versionRangeElement));
     }
     // if only the extension ID is specified block all versions of the
     // extension for the current application.
-    if (result[id].length == 0)
-      result[id].push(new BlocklistItemData(null));
+    if (blockEntry.versions.length == 0)
+      blockEntry.versions.push(new BlocklistItemData(null));
 
-    result[id].blockID = blocklistElement.getAttribute("blockID");
+    blockEntry.blockID = blocklistElement.getAttribute("blockID");
+
+    result.push(blockEntry);
   },
 
   _handlePluginItemNode: function(blocklistElement, result) {
     if (!matchesOSABI(blocklistElement))
       return;
 
     var matchNodes = blocklistElement.childNodes;
     var blockEntry = {
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/blocklist_regexp1_1/install.rdf
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>regexpblock@tests.mozilla.org</em:id>
+    <em:version>1.0</em:version>
+    <em:name>RegExp-blocked add-on</em:name>
+    <em:updateURL>http://localhost:4444/data/addon_update1.rdf</em:updateURL>
+    <em:targetApplication>
+      <Description>
+        <em:id>xpcshell@tests.mozilla.org</em:id>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>3</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/blocklist_regexp1_2/install.rdf
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>regexpblock@tests.mozilla.org</em:id>
+    <em:version>2.0</em:version>
+    <em:name>RegExp-blocked add-on</em:name>
+    <em:updateURL>http://localhost:4444/data/addon_update2.rdf</em:updateURL>
+    <em:targetApplication>
+      <Description>
+        <em:id>xpcshell@tests.mozilla.org</em:id>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>3</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/blocklist_regexp1_3/install.rdf
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>regexpblock@tests.mozilla.org</em:id>
+    <em:version>3.0</em:version>
+    <em:name>RegExp-blocked add-on</em:name>
+    <em:updateURL>http://localhost:4444/data/addon_update3.rdf</em:updateURL>
+    <em:targetApplication>
+      <Description>
+        <em:id>xpcshell@tests.mozilla.org</em:id>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>3</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+  </Description>
+</RDF>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml
@@ -15,10 +15,17 @@
       <versionRange severity="1" minVersion="2" maxVersion="3"/>
     </emItem>
     <emItem id="softblock5@tests.mozilla.org">
       <versionRange severity="1" minVersion="2" maxVersion="3"/>
     </emItem>
     <emItem id="hardblock@tests.mozilla.org">
       <versionRange minVersion="2" maxVersion="3"/>
     </emItem>
+    <!-- Two RegExp matches, so test flags work - first shouldn't match. -->
+    <emItem id="/^RegExp/">
+      <versionRange severity="1" minVersion="2" maxVersion="3"/>
+    </emItem>
+    <emItem id="/^RegExp/i">
+      <versionRange severity="2" minVersion="2" maxVersion="3"/>
+    </emItem>
   </emItems>
 </blocklist>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf
@@ -116,9 +116,29 @@
                 <em:updateLink>http://localhost:4444/addons/blocklist_hard1_2.xpi</em:updateLink>
               </RDF:Description>
             </em:targetApplication>
           </RDF:Description>
         </RDF:li>
       </RDF:Seq>
     </em:updates>
   </RDF:Description>
+
+  <RDF:Description about="urn:mozilla:extension:regexpblock@tests.mozilla.org">
+    <em:updates>
+      <RDF:Seq>
+        <RDF:li>
+          <RDF:Description>
+            <em:version>2</em:version>
+            <em:targetApplication>
+              <RDF:Description>
+                <em:id>toolkit@mozilla.org</em:id>
+                <em:minVersion>0</em:minVersion>
+                <em:maxVersion>*</em:maxVersion>
+                <em:updateLink>http://localhost:4444/addons/blocklist_regexp1_2.xpi</em:updateLink>
+              </RDF:Description>
+            </em:targetApplication>
+          </RDF:Description>
+        </RDF:li>
+      </RDF:Seq>
+    </em:updates>
+  </RDF:Description>
 </RDF:RDF>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf
@@ -116,9 +116,29 @@
                 <em:updateLink>http://localhost:4444/addons/blocklist_hard1_3.xpi</em:updateLink>
               </RDF:Description>
             </em:targetApplication>
           </RDF:Description>
         </RDF:li>
       </RDF:Seq>
     </em:updates>
   </RDF:Description>
+
+  <RDF:Description about="urn:mozilla:extension:regexpblock@tests.mozilla.org">
+    <em:updates>
+      <RDF:Seq>
+        <RDF:li>
+          <RDF:Description>
+            <em:version>3</em:version>
+            <em:targetApplication>
+              <RDF:Description>
+                <em:id>toolkit@mozilla.org</em:id>
+                <em:minVersion>0</em:minVersion>
+                <em:maxVersion>*</em:maxVersion>
+                <em:updateLink>http://localhost:4444/addons/blocklist_regexp1_3.xpi</em:updateLink>
+              </RDF:Description>
+            </em:targetApplication>
+          </RDF:Description>
+        </RDF:li>
+      </RDF:Seq>
+    </em:updates>
+  </RDF:Description>
 </RDF:RDF>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf
@@ -116,9 +116,29 @@
                 <em:updateLink>http://localhost:4444/addons/blocklist_hard1_1.xpi</em:updateLink>
               </RDF:Description>
             </em:targetApplication>
           </RDF:Description>
         </RDF:li>
       </RDF:Seq>
     </em:updates>
   </RDF:Description>
+
+  <RDF:Description about="urn:mozilla:extension:regexpblock@tests.mozilla.org">
+    <em:updates>
+      <RDF:Seq>
+        <RDF:li>
+          <RDF:Description>
+            <em:version>4</em:version>
+            <em:targetApplication>
+              <RDF:Description>
+                <em:id>toolkit@mozilla.org</em:id>
+                <em:minVersion>0</em:minVersion>
+                <em:maxVersion>*</em:maxVersion>
+                <em:updateLink>http://localhost:4444/addons/blocklist_regexp1_1.xpi</em:updateLink>
+              </RDF:Description>
+            </em:targetApplication>
+          </RDF:Description>
+        </RDF:li>
+      </RDF:Seq>
+    </em:updates>
+  </RDF:Description>
 </RDF:RDF>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml
@@ -39,10 +39,24 @@
     </emItem>
     <emItem id="hardblock@tests.mozilla.org">
       <versionRange>
         <targetApplication id="xpcshell@tests.mozilla.org">
           <versionRange minVersion="2" maxVersion="2.*"/>
         </targetApplication>
       </versionRange>
     </emItem>
+    <emItem id="/^RegExp/">
+      <versionRange severity="1">
+        <targetApplication id="xpcshell@tests.mozilla.org">
+          <versionRange minVersion="2" maxVersion="2.*"/>
+        </targetApplication>
+      </versionRange>
+    </emItem>
+    <emItem id="/^RegExp/i">
+      <versionRange>
+        <targetApplication id="xpcshell@tests.mozilla.org">
+          <versionRange minVersion="2" maxVersion="2.*"/>
+        </targetApplication>
+      </versionRange>
+    </emItem>
   </emItems>
 </blocklist>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml
@@ -13,10 +13,14 @@
     </emItem>
     <emItem id="softblock4@tests.mozilla.org">
       <versionRange severity="1"/>
     </emItem>
     <emItem id="softblock5@tests.mozilla.org">
       <versionRange severity="1"/>
     </emItem>
     <emItem id="hardblock@tests.mozilla.org"/>
+    <emItem id="/^RegExp/">
+      <versionRange severity="1"/>
+    </emItem>
+    <emItem id="/^RegExp/i"/>
   </emItems>
 </blocklist>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml
@@ -15,10 +15,13 @@
       <versionRange severity="1" minVersion="1" maxVersion="2"/>
     </emItem>
     <emItem id="softblock5@tests.mozilla.org">
       <versionRange severity="1" minVersion="1" maxVersion="2"/>
     </emItem>
     <emItem id="hardblock@tests.mozilla.org">
       <versionRange minVersion="1" maxVersion="2"/>
     </emItem>
+    <emItem id="/^RegExp/i">
+      <versionRange minVersion="1" maxVersion="2"/>
+    </emItem>
   </emItems>
 </blocklist>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
+  <emItems>
+    <emItem id="/block1/">
+      <versionRange severity="1">
+        <targetApplication id="xpcshell@tests.mozilla.org">
+          <versionRange minVersion="1" maxVersion="2.*"/>
+        </targetApplication>
+      </versionRange>
+    </emItem>
+    <emItem id="/block1/">
+      <versionRange severity="2">
+        <targetApplication id="xpcshell@tests.mozilla.org">
+          <versionRange minVersion="1" maxVersion="2.*"/>
+        </targetApplication>
+      </versionRange>
+    </emItem>
+  </emItems>
+</blocklist>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
@@ -0,0 +1,123 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Checks that blocklist entries using RegExp work as expected. This only covers
+// behavior specific to RegExp entries - general behavior is already tested 
+// in test_blocklistchange.js.
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
+
+Cu.import("resource://testing-common/httpd.js");
+var testserver;
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+// Don't need the full interface, attempts to call other methods will just
+// throw which is just fine
+var WindowWatcher = {
+  openWindow: function(parent, url, name, features, arguments) {
+    // Should be called to list the newly blocklisted items
+    do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
+
+    // Simulate auto-disabling any softblocks
+    var list = arguments.wrappedJSObject.list;
+    list.forEach(function(aItem) {
+      if (!aItem.blocked)
+        aItem.disable = true;
+    });
+
+    //run the code after the blocklist is closed
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
+
+  },
+
+  QueryInterface: function(iid) {
+    if (iid.equals(Ci.nsIWindowWatcher)
+     || iid.equals(Ci.nsISupports))
+      return this;
+
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  }
+};
+
+var WindowWatcherFactory = {
+  createInstance: function createInstance(outer, iid) {
+    if (outer != null)
+      throw Cr.NS_ERROR_NO_AGGREGATION;
+    return WindowWatcher.QueryInterface(iid);
+  }
+};
+
+var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
+                          "Fake Window Watcher",
+                          "@mozilla.org/embedcomp/window-watcher;1",
+                          WindowWatcherFactory);
+
+
+function load_blocklist(aFile, aCallback) {
+  Services.obs.addObserver(function() {
+    Services.obs.removeObserver(arguments.callee, "blocklist-updated");
+
+    do_execute_soon(aCallback);
+  }, "blocklist-updated", false);
+
+  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + aFile);
+  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
+                  getService(Ci.nsITimerCallback);
+  blocklist.notify(null);
+}
+
+
+function end_test() {
+  testserver.stop(do_test_finished);
+}
+
+
+function run_test() {
+  testserver = new HttpServer();
+  testserver.registerDirectory("/data/", do_get_file("data"));
+  testserver.start(4444);
+
+  do_test_pending();
+
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+
+  writeInstallRDFForExtension({
+    id: "block1@tests.mozilla.org",
+    version: "1.0",
+    name: "RegExp blocked add-on",
+    targetApplications: [{
+      id: "xpcshell@tests.mozilla.org",
+      minVersion: "1",
+      maxVersion: "3"
+    }]
+  }, profileDir);
+
+  startupManager();
+
+  AddonManager.getAddonsByIDs(["block1@tests.mozilla.org"], function([a1]) {
+    do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+    run_test_1();
+  });
+}
+
+function run_test_1() {
+  load_blocklist("test_blocklist_regexp_1.xml", function() {
+    restartManager();
+
+    AddonManager.getAddonsByIDs(["block1@tests.mozilla.org"], function([a1]) {
+      // Blocklist contains two entries that will match this addon - ensure
+      // that the first one is applied.
+      do_check_neq(a1, null);
+      do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+
+      end_test();
+    });
+  });
+}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
@@ -268,22 +268,59 @@ var hardblock_3 = {
   updateURL: "http://localhost:4444/data/addon_update3.rdf",
   targetApplications: [{
     id: "xpcshell@tests.mozilla.org",
     minVersion: "1",
     maxVersion: "3"
   }]
 };
 
+var regexpblock_1 = {
+  id: "regexpblock@tests.mozilla.org",
+  version: "1.0",
+  name: "RegExp-blocked add-on",
+  updateURL: "http://localhost:4444/data/addon_update1.rdf",
+  targetApplications: [{
+    id: "xpcshell@tests.mozilla.org",
+    minVersion: "1",
+    maxVersion: "3"
+  }]
+};
+
+var regexpblock_2 = {
+  id: "regexpblock@tests.mozilla.org",
+  version: "2.0",
+  name: "RegExp-blocked add-on",
+  updateURL: "http://localhost:4444/data/addon_update2.rdf",
+  targetApplications: [{
+    id: "xpcshell@tests.mozilla.org",
+    minVersion: "1",
+    maxVersion: "3"
+  }]
+};
+
+var regexpblock_3 = {
+  id: "regexpblock@tests.mozilla.org",
+  version: "3.0",
+  name: "RegExp-blocked add-on",
+  updateURL: "http://localhost:4444/data/addon_update3.rdf",
+  targetApplications: [{
+    id: "xpcshell@tests.mozilla.org",
+    minVersion: "1",
+    maxVersion: "3"
+  }]
+};
+
 const ADDON_IDS = ["softblock1@tests.mozilla.org",
                    "softblock2@tests.mozilla.org",
                    "softblock3@tests.mozilla.org",
                    "softblock4@tests.mozilla.org",
                    "softblock5@tests.mozilla.org",
-                   "hardblock@tests.mozilla.org"];
+                   "hardblock@tests.mozilla.org",
+                   "regexpblock@tests.mozilla.org"];
 
 // Don't need the full interface, attempts to call other methods will just
 // throw which is just fine
 var WindowWatcher = {
   openWindow: function(parent, url, name, features, arguments) {
     // Should be called to list the newly blocklisted items
     do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
 
@@ -423,68 +460,73 @@ function manual_update(aVersion, aCallba
                                       function(aInstall) {
           installs.push(aInstall);
           AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_soft5_" + aVersion + ".xpi",
                                         function(aInstall) {
             installs.push(aInstall);
             AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_hard1_" + aVersion + ".xpi",
                                           function(aInstall) {
               installs.push(aInstall);
-
-              Services.obs.addObserver(function(aSubject, aTopic, aData) {
-                Services.obs.removeObserver(arguments.callee, "addon-install-blocked");
+              AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_regexp1_" + aVersion + ".xpi",
+                                            function(aInstall) {
+                installs.push(aInstall);
 
-                aSubject.QueryInterface(Ci.amIWebInstallInfo);
+                Services.obs.addObserver(function(aSubject, aTopic, aData) {
+                  Services.obs.removeObserver(arguments.callee, "addon-install-blocked");
 
-                var installCount = aSubject.installs.length;
+                  aSubject.QueryInterface(Ci.amIWebInstallInfo);
 
-                var listener = {
-                  installComplete: function() {
-                    installCount--;
-                    if (installCount)
-                      return;
+                  var installCount = aSubject.installs.length;
 
-                    do_execute_soon(aCallback);
-                  },
+                  var listener = {
+                    installComplete: function() {
+                      installCount--;
+                      if (installCount)
+                        return;
+
+                      do_execute_soon(aCallback);
+                    },
 
-                  onDownloadCancelled: function(aInstall) {
-                    this.installComplete();
-                  },
+                    onDownloadCancelled: function(aInstall) {
+                      this.installComplete();
+                    },
 
-                  onInstallEnded: function(aInstall) {
-                    this.installComplete();
-                  }
-                };
+                    onInstallEnded: function(aInstall) {
+                      this.installComplete();
+                    }
+                  };
 
-                aSubject.installs.forEach(function(aInstall) {
-                  aInstall.addListener(listener);
-                });
+                  aSubject.installs.forEach(function(aInstall) {
+                    aInstall.addListener(listener);
+                  });
 
-                aSubject.install();
-              }, "addon-install-blocked", false);
+                  aSubject.install();
+                }, "addon-install-blocked", false);
 
-              AddonManager.installAddonsFromWebpage("application/x-xpinstall", null,
-                                                    NetUtil.newURI("http://localhost:4444/"),
-                                                    installs);
+                AddonManager.installAddonsFromWebpage("application/x-xpinstall", null,
+                                                      NetUtil.newURI("http://localhost:4444/"),
+                                                      installs);
+              }, "application/x-xpinstall");
             }, "application/x-xpinstall");
           }, "application/x-xpinstall");
         }, "application/x-xpinstall");
       }, "application/x-xpinstall");
     }, "application/x-xpinstall");
   }, "application/x-xpinstall");
 }
 
 // Checks that an add-ons properties match expected values
 function check_addon(aAddon, aExpectedVersion, aExpectedUserDisabled,
                      aExpectedSoftDisabled, aExpectedState) {
   dump("Testing " + aAddon.id + " version " + aAddon.version + "\n");
   dump(aAddon.userDisabled + " " + aAddon.softDisabled + "\n");
 
   do_check_neq(aAddon, null);
   do_check_eq(aAddon.version, aExpectedVersion);
+  do_check_eq(aAddon.blocklistState, aExpectedState);
   do_check_eq(aAddon.userDisabled, aExpectedUserDisabled);
   do_check_eq(aAddon.softDisabled, aExpectedSoftDisabled);
   if (aAddon.softDisabled)
     do_check_true(aAddon.userDisabled);
 
   if (aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) {
     do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
     do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
@@ -494,17 +536,16 @@ function check_addon(aAddon, aExpectedVe
     do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
   }
   else {
     do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
     if (aAddon.type != "theme")
       do_check_true(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
   }
   do_check_eq(aAddon.appDisabled, aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED);
-  do_check_eq(aAddon.blocklistState, aExpectedState);
 
   let willBeActive = aAddon.isActive;
   if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_DISABLE))
     willBeActive = false;
   else if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_ENABLE))
     willBeActive = true;
 
   if (aExpectedUserDisabled || aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) {
@@ -527,19 +568,20 @@ function run_test() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
   writeInstallRDFForExtension(default_theme, profileDir);
   writeInstallRDFForExtension(softblock1_1, profileDir);
   writeInstallRDFForExtension(softblock2_1, profileDir);
   writeInstallRDFForExtension(softblock3_1, profileDir);
   writeInstallRDFForExtension(softblock4_1, profileDir);
   writeInstallRDFForExtension(softblock5_1, profileDir);
   writeInstallRDFForExtension(hardblock_1, profileDir);
+  writeInstallRDFForExtension(regexpblock_1, profileDir);
   startupManager();
 
-  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
     s4.userDisabled = true;
     s5.userDisabled = false;
     restartManager();
 
     run_app_update_test();
   });
 }
 
@@ -549,67 +591,71 @@ function end_test() {
 
 // Starts with add-ons unblocked and then switches application versions to
 // change add-ons to blocked and back
 function run_app_update_test() {
   dump(arguments.callee.name + "\n");
   load_blocklist("app_update.xml", function() {
     restartManager();
 
-    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
       check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+      check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
 
       restartManager("2");
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
         do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
         s2.userDisabled = false;
         s2.userDisabled = true;
         check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         s3.userDisabled = false;
         check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         restartManager();
 
         restartManager("2.5");
 
-        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
           check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+          check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
           do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
           restartManager("1");
 
-          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
             check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+            check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
             s1.userDisabled = false;
             s2.userDisabled = false;
             s5.userDisabled = false;
             run_app_update_schema_test();
           });
         });
@@ -620,43 +666,45 @@ function run_app_update_test() {
 
 // Starts with add-ons unblocked and then switches application versions to
 // change add-ons to blocked and back. A DB schema change is faked to force a
 // rebuild when the application version changes
 function run_app_update_schema_test() {
   dump(arguments.callee.name + "\n");
   restartManager();
 
-  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
     check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+    check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
 
     shutdownManager();
     var dbfile = gProfD.clone();
     dbfile.append("extensions.sqlite");
     var db = Services.storage.openDatabase(dbfile);
     db.schemaVersion = 100;
     db.close();
     gAppInfo.version = "2";
     startupManager(true);
 
-    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
       check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+      check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
       do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
       s2.userDisabled = false;
       s2.userDisabled = true;
       check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       s3.userDisabled = false;
       check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       restartManager();
@@ -665,61 +713,64 @@ function run_app_update_schema_test() {
       var dbfile = gProfD.clone();
       dbfile.append("extensions.sqlite");
       var db = Services.storage.openDatabase(dbfile);
       db.schemaVersion = 100;
       db.close();
       gAppInfo.version = "2.5";
       startupManager(true);
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
         do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
         shutdownManager();
         var dbfile = gProfD.clone();
         dbfile.append("extensions.sqlite");
         var db = Services.storage.openDatabase(dbfile);
         db.schemaVersion = 100;
         db.close();
         startupManager(false);
 
-        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
           check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+          check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
           do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
           shutdownManager();
           var dbfile = gProfD.clone();
           dbfile.append("extensions.sqlite");
           var db = Services.storage.openDatabase(dbfile);
           db.schemaVersion = 100;
           db.close();
           gAppInfo.version = "1";
           startupManager(true);
 
-          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
             check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+            check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
             s1.userDisabled = false;
             s2.userDisabled = false;
             s5.userDisabled = false;
             run_blocklist_update_test();
           });
         });
@@ -730,70 +781,74 @@ function run_app_update_schema_test() {
 
 // Starts with add-ons unblocked and then loads new blocklists to change add-ons
 // to blocked and back again.
 function run_blocklist_update_test() {
   dump(arguments.callee.name + "\n");
   load_blocklist("blocklist_update1.xml", function() {
     restartManager();
 
-    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
       check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+      check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
 
       load_blocklist("blocklist_update2.xml", function() {
         restartManager();
 
-        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
           check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+          check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
           do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
           s2.userDisabled = false;
           s2.userDisabled = true;
           check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           s3.userDisabled = false;
           check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           restartManager();
 
           load_blocklist("blocklist_update2.xml", function() {
             restartManager();
 
-            AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+            AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
               check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
               check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
               check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
               check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
               check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
               check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+              check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
               do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
               load_blocklist("blocklist_update1.xml", function() {
                 restartManager();
 
-                AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+                AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
                   check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
                   check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
                   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
                   check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
                   check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
                   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+                  check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
                   do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
                   s1.userDisabled = false;
                   s2.userDisabled = false;
                   s5.userDisabled = false;
                   run_addon_change_test();
                 });
               });
@@ -807,51 +862,55 @@ function run_blocklist_update_test() {
 
 // Starts with add-ons unblocked and then new versions are installed outside of
 // the app to change them to blocked and back again.
 function run_addon_change_test() {
   dump(arguments.callee.name + "\n");
   load_blocklist("addon_change.xml", function() {
     restartManager();
 
-    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
       check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+      check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
       do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
 
       shutdownManager();
 
       writeInstallRDFForExtension(softblock1_2, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_2.id), Date.now() + 10000);
       writeInstallRDFForExtension(softblock2_2, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_2.id), Date.now() + 10000);
       writeInstallRDFForExtension(softblock3_2, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_2.id), Date.now() + 10000);
       writeInstallRDFForExtension(softblock4_2, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_2.id), Date.now() + 10000);
       writeInstallRDFForExtension(softblock5_2, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_2.id), Date.now() + 10000);
       writeInstallRDFForExtension(hardblock_2, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_2.id), Date.now() + 10000);
+      writeInstallRDFForExtension(regexpblock_2, profileDir);
+      setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_2.id), Date.now() + 10000);
 
       startupManager(false);
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s5, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+        check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
         do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
         s2.userDisabled = false;
         s2.userDisabled = true;
         check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         s3.userDisabled = false;
         check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         restartManager();
@@ -865,54 +924,60 @@ function run_addon_change_test() {
         writeInstallRDFForExtension(softblock3_3, profileDir);
         setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_3.id), Date.now() + 20000);
         writeInstallRDFForExtension(softblock4_3, profileDir);
         setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_3.id), Date.now() + 20000);
         writeInstallRDFForExtension(softblock5_3, profileDir);
         setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_3.id), Date.now() + 20000);
         writeInstallRDFForExtension(hardblock_3, profileDir);
         setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 20000);
+        writeInstallRDFForExtension(regexpblock_3, profileDir);
+        setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_3.id), Date.now() + 20000);
 
         startupManager(false);
 
-        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
           check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s5, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+          check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
           do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
           shutdownManager();
 
           writeInstallRDFForExtension(softblock1_1, profileDir);
           setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_1.id), Date.now() + 30000);
           writeInstallRDFForExtension(softblock2_1, profileDir);
           setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_1.id), Date.now() + 30000);
           writeInstallRDFForExtension(softblock3_1, profileDir);
           setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_1.id), Date.now() + 30000);
           writeInstallRDFForExtension(softblock4_1, profileDir);
           setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_1.id), Date.now() + 30000);
           writeInstallRDFForExtension(softblock5_1, profileDir);
           setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_1.id), Date.now() + 30000);
           writeInstallRDFForExtension(hardblock_1, profileDir);
           setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 30000);
+          writeInstallRDFForExtension(regexpblock_1, profileDir);
+          setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_1.id), Date.now() + 30000);
 
           startupManager(false);
 
-          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
             check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+            check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
 
             s1.userDisabled = false;
             s2.userDisabled = false;
             s5.userDisabled = false;
             run_addon_change_2_test();
           });
         });
@@ -928,35 +993,38 @@ function run_addon_change_2_test() {
   shutdownManager();
 
   getFileForAddon(profileDir, softblock1_1.id).remove(true);
   getFileForAddon(profileDir, softblock2_1.id).remove(true);
   getFileForAddon(profileDir, softblock3_1.id).remove(true);
   getFileForAddon(profileDir, softblock4_1.id).remove(true);
   getFileForAddon(profileDir, softblock5_1.id).remove(true);
   getFileForAddon(profileDir, hardblock_1.id).remove(true);
+  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
 
   startupManager(false);
   shutdownManager();
 
   writeInstallRDFForExtension(softblock1_2, profileDir);
   writeInstallRDFForExtension(softblock2_2, profileDir);
   writeInstallRDFForExtension(softblock3_2, profileDir);
   writeInstallRDFForExtension(softblock4_2, profileDir);
   writeInstallRDFForExtension(softblock5_2, profileDir);
   writeInstallRDFForExtension(hardblock_2, profileDir);
+  writeInstallRDFForExtension(regexpblock_2, profileDir);
 
   startupManager(false);
 
-  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
     check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+    check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
     s2.userDisabled = false;
     s2.userDisabled = true;
     check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     s3.userDisabled = false;
     check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     restartManager();
 
@@ -969,49 +1037,55 @@ function run_addon_change_2_test() {
     writeInstallRDFForExtension(softblock3_3, profileDir);
     setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_3.id), Date.now() + 10000);
     writeInstallRDFForExtension(softblock4_3, profileDir);
     setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_3.id), Date.now() + 10000);
     writeInstallRDFForExtension(softblock5_3, profileDir);
     setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_3.id), Date.now() + 10000);
     writeInstallRDFForExtension(hardblock_3, profileDir);
     setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 10000);
+    writeInstallRDFForExtension(regexpblock_3, profileDir);
+    setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_3.id), Date.now() + 10000);
 
     startupManager(false);
 
-    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
       check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+      check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
       shutdownManager();
 
       writeInstallRDFForExtension(softblock1_1, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_1.id), Date.now() + 20000);
       writeInstallRDFForExtension(softblock2_1, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_1.id), Date.now() + 20000);
       writeInstallRDFForExtension(softblock3_1, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_1.id), Date.now() + 20000);
       writeInstallRDFForExtension(softblock4_1, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_1.id), Date.now() + 20000);
       writeInstallRDFForExtension(softblock5_1, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_1.id), Date.now() + 20000);
       writeInstallRDFForExtension(hardblock_1, profileDir);
       setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 20000);
+      writeInstallRDFForExtension(regexpblock_1, profileDir);
+      setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_1.id), Date.now() + 20000);
 
       startupManager(false);
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
         s1.userDisabled = false;
         s2.userDisabled = false;
         s4.userDisabled = true;
         s5.userDisabled = false;
         run_background_update_test();
       });
     });
@@ -1019,36 +1093,38 @@ function run_addon_change_2_test() {
 }
 
 // Add-ons are initially unblocked then attempts to upgrade to blocked versions
 // in the background which should fail
 function run_background_update_test() {
   dump(arguments.callee.name + "\n");
   restartManager();
 
-  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
     check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
     check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+    check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
     background_update(function() {
       restartManager();
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
         run_background_update_2_test();
       });
     });
   });
 }
 
 // Starts with add-ons blocked and then new versions are detected and installed
@@ -1058,52 +1134,56 @@ function run_background_update_2_test() 
   shutdownManager();
 
   getFileForAddon(profileDir, softblock1_1.id).remove(true);
   getFileForAddon(profileDir, softblock2_1.id).remove(true);
   getFileForAddon(profileDir, softblock3_1.id).remove(true);
   getFileForAddon(profileDir, softblock4_1.id).remove(true);
   getFileForAddon(profileDir, softblock5_1.id).remove(true);
   getFileForAddon(profileDir, hardblock_1.id).remove(true);
+  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
 
   startupManager(false);
   shutdownManager();
 
   writeInstallRDFForExtension(softblock1_3, profileDir);
   writeInstallRDFForExtension(softblock2_3, profileDir);
   writeInstallRDFForExtension(softblock3_3, profileDir);
   writeInstallRDFForExtension(softblock4_3, profileDir);
   writeInstallRDFForExtension(softblock5_3, profileDir);
   writeInstallRDFForExtension(hardblock_3, profileDir);
+  writeInstallRDFForExtension(regexpblock_3, profileDir);
 
   startupManager(false);
 
-  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
     check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(s2, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(s3, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+    check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
     s2.userDisabled = false;
     s2.userDisabled = true;
     check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     s3.userDisabled = false;
     check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     restartManager();
 
     background_update(function() {
       restartManager();
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
         s1.userDisabled = false;
         s2.userDisabled = false;
         s4.userDisabled = true;
         s5.userDisabled = true;
         run_manual_update_test();
       });
     });
@@ -1113,56 +1193,59 @@ function run_background_update_2_test() 
 // Starts with add-ons blocked and then simulates the user upgrading them to
 // unblocked versions.
 function run_manual_update_test() {
   dump(arguments.callee.name + "\n");
   restartManager();
   load_blocklist("manual_update.xml", function() {
     restartManager();
 
-    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+    AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
       check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+      check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
       s2.userDisabled = false;
       s2.userDisabled = true;
       check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       s3.userDisabled = false;
       check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
       restartManager();
 
       manual_update("2", function() {
         restartManager();
 
-        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+        AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
           check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           check_addon(s5, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
           // Can't manually update to a hardblocked add-on
           check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+          check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
           manual_update("3", function() {
             restartManager();
 
-            AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+            AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
               check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
               check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
               check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
               check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
               check_addon(s5, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
               check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+              check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
               run_manual_update_2_test();
             });
           });
         });
       });
     });
   });
@@ -1175,65 +1258,70 @@ function run_manual_update_2_test() {
   shutdownManager();
 
   getFileForAddon(profileDir, softblock1_1.id).remove(true);
   getFileForAddon(profileDir, softblock2_1.id).remove(true);
   getFileForAddon(profileDir, softblock3_1.id).remove(true);
   getFileForAddon(profileDir, softblock4_1.id).remove(true);
   getFileForAddon(profileDir, softblock5_1.id).remove(true);
   getFileForAddon(profileDir, hardblock_1.id).remove(true);
+  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
 
   startupManager(false);
   shutdownManager();
 
   writeInstallRDFForExtension(softblock1_1, profileDir);
   writeInstallRDFForExtension(softblock2_1, profileDir);
   writeInstallRDFForExtension(softblock3_1, profileDir);
   writeInstallRDFForExtension(softblock4_1, profileDir);
   writeInstallRDFForExtension(softblock5_1, profileDir);
   writeInstallRDFForExtension(hardblock_1, profileDir);
+  writeInstallRDFForExtension(regexpblock_1, profileDir);
 
   startupManager(false);
 
-  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+  AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
     check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+    check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
     s2.userDisabled = false;
     s2.userDisabled = true;
     check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     s3.userDisabled = false;
     check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
     restartManager();
 
     manual_update("2", function() {
       restartManager();
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         // Can't manually update to a hardblocked add-on
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
         restartManager();
 
         manual_update("3", function() {
           restartManager();
 
-          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+          AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
             check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
             check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+            check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
             s1.userDisabled = false;
             s2.userDisabled = false;
             s4.userDisabled = true;
             run_local_install_test();
           });
         });
       });
@@ -1247,35 +1335,38 @@ function run_local_install_test() {
   shutdownManager();
 
   getFileForAddon(profileDir, softblock1_1.id).remove(true);
   getFileForAddon(profileDir, softblock2_1.id).remove(true);
   getFileForAddon(profileDir, softblock3_1.id).remove(true);
   getFileForAddon(profileDir, softblock4_1.id).remove(true);
   getFileForAddon(profileDir, softblock5_1.id).remove(true);
   getFileForAddon(profileDir, hardblock_1.id).remove(true);
+  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
 
   startupManager(false);
 
   installAllFiles([
     do_get_file("addons/blocklist_soft1_1.xpi"),
     do_get_file("addons/blocklist_soft2_1.xpi"),
     do_get_file("addons/blocklist_soft3_1.xpi"),
     do_get_file("addons/blocklist_soft4_1.xpi"),
     do_get_file("addons/blocklist_soft5_1.xpi"),
-    do_get_file("addons/blocklist_hard1_1.xpi")
+    do_get_file("addons/blocklist_hard1_1.xpi"),
+    do_get_file("addons/blocklist_regexp1_1.xpi")
   ], function() {
     AddonManager.getAllInstalls(function(aInstalls) {
       // Should have finished all installs without needing to restart
       do_check_eq(aInstalls.length, 0);
 
-      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
+      AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
 
         check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
         check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+        check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
         end_test();
       });
     });
   });
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -12,16 +12,18 @@ skip-if = os == "android"
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_LightweightThemeManager.js]
 [test_backgroundupdate.js]
 [test_badschema.js]
 [test_blocklistchange.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
+[test_blocklist_regexp.js]
+skip-if = os == "android"
 [test_bootstrap.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug299716.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_bug299716_2.js]
 # Bug 676992: test consistently hangs on Android