Bug 1217944 Part 2 Support wildcards in web_accessible_resources r?kmag draft
authorAndrew Swan <aswan@mozilla.com>
Wed, 06 Apr 2016 13:20:23 -0700
changeset 348172 5408a4e33201a9912558951464551bbd64d93785
parent 348171 6d0cd4e057000f00d0351e8dd891c221386e4642
child 517795 022cbe8fcc4d670759892305f1d38ac05ad0f6c6
push id14765
push useraswan@mozilla.com
push dateWed, 06 Apr 2016 20:21:59 +0000
reviewerskmag
bugs1217944
milestone48.0a1
Bug 1217944 Part 2 Support wildcards in web_accessible_resources r?kmag MozReview-Commit-ID: Ln6JJ5lxc3w
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionContent.jsm
toolkit/components/extensions/ExtensionManagement.jsm
toolkit/components/extensions/test/mochitest/test_ext_web_accessible_resources.html
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -27,16 +27,18 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
                                   "resource://devtools/shared/event-emitter.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Locale",
                                   "resource://gre/modules/Locale.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Log",
                                   "resource://gre/modules/Log.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "MatchGlobs",
+                                  "resource://gre/modules/MatchPattern.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MatchPattern",
                                   "resource://gre/modules/MatchPattern.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
@@ -867,17 +869,17 @@ this.Extension = function(addonData) {
 
   this.hasShutdown = false;
   this.onShutdown = new Set();
 
   this.uninstallURL = null;
 
   this.permissions = new Set();
   this.whiteListedHosts = null;
-  this.webAccessibleResources = new Set();
+  this.webAccessibleResources = null;
 
   this.emitter = new EventEmitter();
 };
 
 /**
  * This code is designed to make it easy to test a WebExtension
  * without creating a bunch of files. Everything is contained in a
  * single JSON blob.
@@ -1109,17 +1111,17 @@ Extension.prototype = extend(Object.crea
   serialize() {
     return {
       id: this.id,
       uuid: this.uuid,
       manifest: this.manifest,
       resourceURL: this.addonData.resourceURI.spec,
       baseURL: this.baseURI.spec,
       content_scripts: this.manifest.content_scripts || [],  // eslint-disable-line camelcase
-      webAccessibleResources: this.webAccessibleResources,
+      webAccessibleResources: this.webAccessibleResources.serialize(),
       whiteListedHosts: this.whiteListedHosts.serialize(),
       localeData: this.localeData.serialize(),
     };
   },
 
   broadcast(msg, data) {
     return new Promise(resolve => {
       let count = Services.ppmm.childCount;
@@ -1135,32 +1137,27 @@ Extension.prototype = extend(Object.crea
         }
       });
       Services.ppmm.broadcastAsyncMessage(msg, data);
     });
   },
 
   runManifest(manifest) {
     let permissions = manifest.permissions || [];
-    let webAccessibleResources = manifest.web_accessible_resources || [];
 
     let whitelist = [];
     for (let perm of permissions) {
       this.permissions.add(perm);
       if (!/^\w+(\.\w+)*$/.test(perm)) {
         whitelist.push(perm);
       }
     }
     this.whiteListedHosts = new MatchPattern(whitelist);
 
-    let resources = new Set();
-    for (let url of webAccessibleResources) {
-      resources.add(url);
-    }
-    this.webAccessibleResources = resources;
+    this.webAccessibleResources = new MatchGlobs(manifest.web_accessible_resources || []);
 
     for (let directive in manifest) {
       if (manifest[directive] !== null) {
         Management.emit("manifest_" + directive, directive, this, manifest);
       }
     }
 
     let data = Services.ppmm.initialProcessData;
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -649,17 +649,17 @@ DocumentManager = {
 };
 
 // Represents a browser extension in the content process.
 function BrowserExtensionContent(data) {
   this.id = data.id;
   this.uuid = data.uuid;
   this.data = data;
   this.scripts = data.content_scripts.map(scriptData => new Script(scriptData));
-  this.webAccessibleResources = data.webAccessibleResources;
+  this.webAccessibleResources = new MatchGlobs(data.webAccessibleResources);
   this.whiteListedHosts = new MatchPattern(data.whiteListedHosts);
 
   this.localeData = new LocaleData(data.localeData);
 
   this.manifest = data.manifest;
   this.baseURI = Services.io.newURI(data.baseURL, null, null);
 
   let uri = Services.io.newURI(data.resourceURL, null, null);
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -175,25 +175,25 @@ var Service = {
   },
 
   // Return true if the given URI can be loaded from arbitrary web
   // content. The manifest.json |web_accessible_resources| directive
   // determines this.
   extensionURILoadableByAnyone(uri) {
     let uuid = uri.host;
     let extension = this.uuidMap.get(uuid);
-    if (!extension) {
+    if (!extension || !extension.webAccessibleResources) {
       return false;
     }
 
     let path = uri.QueryInterface(Ci.nsIURL).filePath;
     if (path.length > 0 && path[0] == "/") {
       path = path.substr(1);
     }
-    return extension.webAccessibleResources.has(path);
+    return extension.webAccessibleResources.matches(path);
   },
 
   // Checks whether a given extension can load this URI (typically via
   // an XML HTTP request). The manifest.json |permissions| directive
   // determines this.
   checkAddonMayLoad(extension, uri) {
     return extension.whiteListedHosts.matchesIgnoringPath(uri);
   },
--- a/toolkit/components/extensions/test/mochitest/test_ext_web_accessible_resources.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_web_accessible_resources.html
@@ -28,16 +28,18 @@ add_task(function* test_web_accessible_r
       });
     }
 
     let urls = [
       [browser.extension.getURL("accessible.html"), true],
       [browser.extension.getURL("accessible.html") + "?foo=bar", true],
       [browser.extension.getURL("accessible.html") + "#!foo=bar", true],
       [browser.extension.getURL("forbidden.html"), false],
+      [browser.extension.getURL("wild1.html"), true],
+      [browser.extension.getURL("wild2.htm"), false],
     ];
 
     function runTest() {
       if (!urls.length) {
         browser.test.notifyPass("web-accessible-resources");
         return;
       }
 
@@ -90,16 +92,17 @@ add_task(function* test_web_accessible_r
           "matches": ["http://example.com/"],
           "js": ["content_script.js"],
           "run_at": "document_idle",
         },
       ],
 
       "web_accessible_resources": [
         "accessible.html",
+        "wild*.html",
       ],
     },
 
     background: `(${background})()`,
 
     files: {
       "content_script.js": `(${contentScript})()`,
 
@@ -107,16 +110,26 @@ add_task(function* test_web_accessible_r
         <meta charset="utf-8">
         <script>browser.runtime.sendMessage(["page-script", location.href]);</${"script"}>
       </head></html>`,
 
       "inaccessible.html": `<html><head>
         <meta charset="utf-8">
         <script>browser.runtime.sendMessage(["page-script", location.href]);</${"script"}>
       </head></html>`,
+
+      "wild1.html": `<html><head>
+        <meta charset="utf-8">
+        <script>browser.runtime.sendMessage(["page-script", location.href]);</${"script"}>
+      </head></html>`,
+
+      "wild2.htm": `<html><head>
+        <meta charset="utf-8">
+        <script>browser.runtime.sendMessage(["page-script", location.href]);</${"script"}>
+      </head></html>`,
     },
   });
 
   yield extension.startup();
 
   yield extension.awaitMessage("ready");
 
   let win = window.open("http://example.com/");