Bug 1280370 - Allow any scheme in targetUrlPatterns r=mixedpuppy
authorRob Wu <rob@robwu.nl>
Tue, 24 Jul 2018 17:26:23 +0200
changeset 430601 d01b3ac48bdc327764b63c21400e6abb7d53cb85
parent 430600 0134a212426692593c68d6f40c718377f13e2087
child 430602 72dd828f24817614cd30c1156b99b58b73f9f5e7
push id67542
push userrob@robwu.nl
push dateThu, 09 Aug 2018 02:00:24 +0000
treeherderautoland@72dd828f2481 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1280370
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1280370 - Allow any scheme in targetUrlPatterns r=mixedpuppy MozReview-Commit-ID: KupQIiAkz0h
browser/components/extensions/parent/ext-menus.js
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_contextMenus_targetUrlPatterns.js
--- a/browser/components/extensions/parent/ext-menus.js
+++ b/browser/components/extensions/parent/ext-menus.js
@@ -550,17 +550,17 @@ MenuItem.prototype = {
       this[propName] = createProperties[propName];
     }
 
     if (createProperties.documentUrlPatterns != null) {
       this.documentUrlMatchPattern = new MatchPatternSet(this.documentUrlPatterns);
     }
 
     if (createProperties.targetUrlPatterns != null) {
-      this.targetUrlMatchPattern = new MatchPatternSet(this.targetUrlPatterns);
+      this.targetUrlMatchPattern = new MatchPatternSet(this.targetUrlPatterns, {restrictSchemes: false});
     }
 
     // If a child MenuItem does not specify any contexts, then it should
     // inherit the contexts specified from its parent.
     if (createProperties.parentId && !createProperties.contexts) {
       this.contexts = this.parent.contexts;
     }
   },
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -78,16 +78,17 @@ skip-if = (verify && (os == 'linux' || o
 [browser_ext_connect_and_move_tabs.js]
 [browser_ext_contentscript_connect.js]
 [browser_ext_contextMenus.js]
 [browser_ext_contextMenus_checkboxes.js]
 [browser_ext_contextMenus_commands.js]
 [browser_ext_contextMenus_icons.js]
 [browser_ext_contextMenus_onclick.js]
 [browser_ext_contextMenus_radioGroups.js]
+[browser_ext_contextMenus_targetUrlPatterns.js]
 [browser_ext_contextMenus_uninstall.js]
 [browser_ext_contextMenus_urlPatterns.js]
 [browser_ext_currentWindow.js]
 [browser_ext_devtools_inspectedWindow.js]
 [browser_ext_devtools_inspectedWindow_eval_bindings.js]
 [browser_ext_devtools_inspectedWindow_reload.js]
 [browser_ext_devtools_network.js]
 [browser_ext_devtools_page.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_targetUrlPatterns.js
@@ -0,0 +1,191 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(async function unsupportedSchemes() {
+  const testcases = [{
+    // Link to URL with query string parameters only.
+    testUrl: "magnet:?xt=urn:btih:somesha1hash&dn=displayname.txt",
+    matchingPatterns: [
+      "magnet:*",
+      "magnet:?xt=*",
+      "magnet:?xt=*txt",
+      "magnet:*?xt=*txt",
+    ],
+    nonmatchingPatterns: [
+      // Although <all_urls> matches unsupported schemes in Chromium,
+      // we have specified that <all_urls> only matches all supported
+      // schemes. To match any scheme, an extension should not set the
+      // targetUrlPatterns field - this is checked below in subtest
+      // unsupportedSchemeWithoutTargetUrlPatterns.
+      "<all_urls>",
+      "agnet:*",
+      "magne:*",
+    ],
+  }, {
+    // Link to bookmarklet.
+    testUrl: "javascript:-URL",
+    matchingPatterns: [
+      "javascript:*",
+      "javascript:*URL",
+      "javascript:-URL",
+    ],
+    nonmatchingPatterns: [
+      "<all_urls>",
+      "javascript://-URL",
+      "javascript:javascript:-URL",
+    ],
+  }, {
+    // Link to bookmarklet with comment.
+    testUrl: "javascript://-URL",
+    matchingPatterns: [
+      "javascript:*",
+      "javascript://-URL",
+      "javascript:*URL",
+    ],
+    nonmatchingPatterns: [
+      "<all_urls>",
+      "javascript:-URL",
+    ],
+  }, {
+    // Link to data-URI.
+    testUrl: "data:application/foo,bar",
+    matchingPatterns: [
+      "<all_urls>",
+      "data:application/foo,bar",
+      "data:*,*",
+      "data:*",
+    ],
+    nonmatchingPatterns: [
+      "data:,bar",
+      "data:application/foo,",
+    ],
+  }, {
+    // Extension page.
+    testUrl: "moz-extension://uuid/manifest.json",
+    matchingPatterns: [
+      "moz-extension://*/*",
+    ],
+    nonmatchingPatterns: [
+      "<all_urls>",
+      "moz-extension://uuid/not/manifest.json*",
+    ],
+  }];
+
+  async function testScript(testcases) {
+    let testcase;
+
+    browser.contextMenus.onShown.addListener(({menuIds, linkUrl}) => {
+      browser.test.assertEq(testcase.testUrl, linkUrl, "Expected linkUrl");
+      for (let pattern of testcase.matchingPatterns) {
+        browser.test.assertTrue(
+          menuIds.includes(pattern),
+          `Menu item with targetUrlPattern="${pattern}" should be shown at ${testcase.testUrl}`);
+      }
+      for (let pattern of testcase.nonmatchingPatterns) {
+        browser.test.assertFalse(
+          menuIds.includes(pattern),
+          `Menu item with targetUrlPattern="${pattern}" should not be shown at ${testcase.testUrl}`);
+      }
+      testcase = null;
+      browser.test.sendMessage("onShown_checked");
+    });
+
+    browser.test.onMessage.addListener(async (msg, params) => {
+      browser.test.assertEq("setupTest", msg, "Expected message");
+
+      // Save test case in global variable for use in the onShown event.
+      testcase = params;
+      browser.test.log(`Running test for link with URL: ${testcase.testUrl}`);
+      document.getElementById("test_link_element").href = testcase.testUrl;
+      await browser.contextMenus.removeAll();
+      for (let targetUrlPattern of [...testcase.matchingPatterns, ...testcase.nonmatchingPatterns]) {
+        await new Promise(resolve => {
+          browser.test.log(`Creating menu with "${targetUrlPattern}"`);
+          browser.contextMenus.create({
+            id: targetUrlPattern,
+            contexts: ["link"],
+            title: "Some menu item",
+            targetUrlPatterns: [targetUrlPattern],
+          }, resolve);
+        });
+      }
+      browser.test.sendMessage("setupTest_ready");
+    });
+    browser.test.sendMessage("ready");
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["contextMenus"],
+    },
+    background() {
+      browser.tabs.create({url: "testrunner.html"});
+    },
+    files: {
+      "testrunner.js": `(${testScript})()`,
+      "testrunner.html": `
+        <!DOCTYPE html><meta charset="utf-8">
+        <body>
+        <a id="test_link_element">Test link</a>
+        <script src="testrunner.js"></script>
+        </body>
+      `,
+    },
+  });
+
+  await extension.startup();
+  await extension.awaitMessage("ready");
+  for (let testcase of testcases) {
+    extension.sendMessage("setupTest", testcase);
+    await extension.awaitMessage("setupTest_ready");
+
+    await openExtensionContextMenu("#test_link_element");
+    await extension.awaitMessage("onShown_checked");
+    await closeContextMenu();
+  }
+  await extension.unload();
+});
+
+// Tests that a menu item is shown on links with an unsupported scheme if
+// targetUrlPatterns is not set.
+add_task(async function unsupportedSchemeWithoutPattern() {
+  function background() {
+    let menuId;
+    browser.contextMenus.onShown.addListener(({menuIds, linkUrl}) => {
+      browser.test.assertEq(1, menuIds.length, "Expected number of menus");
+      browser.test.assertEq(menuId, menuIds[0], "Expected menu ID");
+      browser.test.assertEq("unsupported-scheme:data", linkUrl, "Expected linkUrl");
+      browser.test.sendMessage("done");
+    });
+    menuId = browser.contextMenus.create({
+      contexts: ["link"],
+      title: "Test menu item without targetUrlPattern",
+    }, () => {
+      browser.tabs.create({url: "testpage.html"});
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["contextMenus"],
+    },
+    background,
+    files: {
+      "testpage.js": `browser.test.sendMessage("ready")`,
+      "testpage.html": `
+        <!DOCTYPE html><meta charset="utf-8">
+        <a id="test_link_element" href="unsupported-scheme:data">Test link</a>
+        <script src="testpage.js"></script>
+      `,
+    },
+  });
+
+  await extension.startup();
+  await extension.awaitMessage("ready");
+  await openExtensionContextMenu("#test_link_element");
+  await extension.awaitMessage("done");
+  await closeContextMenu();
+
+  await extension.unload();
+});