Bug 1321303 - Part 8: Implement browsingData serviceWorkers dataType, r=baku
authorBob Silverberg <bsilverberg@mozilla.com>
Fri, 23 Dec 2016 16:27:46 -0500
changeset 377747 4054f1c5e04a012e63ffa95533939a73b911f8ef
parent 377746 8a161e6bae182cd3c39a0b25ebdd18103b3d39db
child 377748 b106d15be0581328e32d3c2b763dc9c995f2efb3
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1321303
milestone53.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 1321303 - Part 8: Implement browsingData serviceWorkers dataType, r=baku MozReview-Commit-ID: 10zSlmaKjIj
browser/components/extensions/ext-browsingData.js
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_browsingData_serviceWorkers.js
browser/components/extensions/test/browser/file_serviceWorker.html
browser/components/extensions/test/browser/serviceWorker.js
--- a/browser/components/extensions/ext-browsingData.js
+++ b/browser/components/extensions/ext-browsingData.js
@@ -1,8 +1,10 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
@@ -10,16 +12,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Preferences.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Sanitizer",
                                   "resource:///modules/Sanitizer.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
                                   "resource://gre/modules/Timer.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
+                                   "@mozilla.org/serviceworkers/manager;1",
+                                   "nsIServiceWorkerManager");
+
 /**
 * A number of iterations after which to yield time back
 * to the system.
 */
 const YIELD_PERIOD = 10;
 
 const PREF_DOMAIN = "privacy.cpd.";
 
@@ -100,16 +106,32 @@ let clearPasswords = Task.async(function
     loginManager.removeAllLogins();
   }
 });
 
 function clearPluginData(options) {
   return sanitizer.items.pluginData.clear(makeRange(options));
 }
 
+let clearServiceWorkers = Task.async(function* () {
+  // Clearing service workers does not support timestamps.
+  let yieldCounter = 0;
+
+  // Iterate through the service workers and remove them.
+  let serviceWorkers = serviceWorkerManager.getAllRegistrations();
+  for (let i = 0; i < serviceWorkers.length; i++) {
+    let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
+    let host = sw.principal.URI.host;
+    serviceWorkerManager.removeAndPropagate(host);
+    if (++yieldCounter % YIELD_PERIOD == 0) {
+      yield new Promise(resolve => setTimeout(resolve, 0)); // Don't block the main thread too long.
+    }
+  }
+});
+
 function doRemoval(options, dataToRemove, extension) {
   if (options.originTypes &&
       (options.originTypes.protectedWeb || options.originTypes.extension)) {
     return Promise.reject(
       {message: "Firefox does not support protectedWeb or extension as originTypes."});
   }
 
   let removalPromises = [];
@@ -133,16 +155,19 @@ function doRemoval(options, dataToRemove
           removalPromises.push(clearHistory(options));
           break;
         case "passwords":
           removalPromises.push(clearPasswords(options));
           break;
         case "pluginData":
           removalPromises.push(clearPluginData(options));
           break;
+        case "serviceWorkers":
+          removalPromises.push(clearServiceWorkers());
+          break;
         default:
           invalidDataTypes.push(dataType);
       }
     }
   }
   if (extension && invalidDataTypes.length) {
     extension.logger.warn(
       `Firefox does not support dataTypes: ${invalidDataTypes.toString()}.`);
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -12,31 +12,34 @@ support-files =
   file_popup_api_injection_b.html
   file_iframe_document.html
   file_iframe_document.sjs
   file_bypass_cache.sjs
   file_language_fr_en.html
   file_language_ja.html
   file_language_tlh.html
   file_dummy.html
+  file_serviceWorker.html
+  serviceWorker.js
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
   ../../../../../toolkit/components/extensions/test/mochitest/head_webrequest.js
 
 [browser_ext_browserAction_context.js]
 [browser_ext_browserAction_disabled.js]
 [browser_ext_browserAction_pageAction_icon.js]
 [browser_ext_browserAction_pageAction_icon_permissions.js]
 [browser_ext_browserAction_popup.js]
 [browser_ext_browserAction_popup_preload.js]
 [browser_ext_browserAction_popup_resize.js]
 [browser_ext_browserAction_simple.js]
 [browser_ext_browsingData_formData.js]
 [browser_ext_browsingData_history.js]
 [browser_ext_browsingData_pluginData.js]
+[browser_ext_browsingData_serviceWorkers.js]
 [browser_ext_commands_execute_browser_action.js]
 [browser_ext_commands_execute_page_action.js]
 [browser_ext_commands_getAll.js]
 [browser_ext_commands_onCommand.js]
 [browser_ext_contentscript_connect.js]
 [browser_ext_contextMenus.js]
 [browser_ext_contextMenus_checkboxes.js]
 [browser_ext_contextMenus_chrome.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_browsingData_serviceWorkers.js
@@ -0,0 +1,89 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* setup() {
+  yield SpecialPowers.pushPrefEnv({
+    set: [["dom.serviceWorkers.exemptFromPerDomainMax", true],
+         ["dom.serviceWorkers.enabled", true],
+         ["dom.serviceWorkers.testing.enabled", true]],
+  });
+});
+
+add_task(function* testServiceWorkers() {
+  function background() {
+    const PAGE = "/browser/browser/components/extensions/test/browser/file_serviceWorker.html";
+
+    browser.runtime.onMessage.addListener(msg => {
+      browser.test.sendMessage("serviceWorkerRegistered");
+    });
+
+    browser.test.onMessage.addListener(async (msg) => {
+      await browser.browsingData.remove({}, {serviceWorkers: true});
+      browser.test.sendMessage("serviceWorkersRemoved");
+    });
+
+    // Create two serviceWorkers.
+    browser.tabs.create({url: `http://mochi.test:8888${PAGE}`});
+    browser.tabs.create({url: `http://example.com${PAGE}`});
+  }
+
+  function contentScript() {
+    window.addEventListener("message", msg => { // eslint-disable-line mozilla/balanced-listeners
+      if (msg.data == "serviceWorkerRegistered") {
+        browser.runtime.sendMessage("serviceWorkerRegistered");
+      }
+    }, true);
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      permissions: ["browsingData", "tabs"],
+      "content_scripts": [{
+        "matches": [
+          "http://mochi.test/*/file_serviceWorker.html",
+          "http://example.com/*/file_serviceWorker.html",
+        ],
+        "js": ["script.js"],
+        "run_at": "document_start",
+      }],
+    },
+    files: {
+      "script.js": contentScript,
+    },
+  });
+
+  let serviceWorkerManager = SpecialPowers.Cc["@mozilla.org/serviceworkers/manager;1"]
+    .getService(SpecialPowers.Ci.nsIServiceWorkerManager);
+
+  let win = yield BrowserTestUtils.openNewBrowserWindow();
+  yield focusWindow(win);
+
+  yield extension.startup();
+  yield extension.awaitMessage("serviceWorkerRegistered");
+  yield extension.awaitMessage("serviceWorkerRegistered");
+
+  let serviceWorkers = [];
+  // Even though we await the registrations by waiting for the messages,
+  // sometimes the serviceWorkers are still not registered at this point.
+  while (serviceWorkers.length < 2) {
+    serviceWorkers = serviceWorkerManager.getAllRegistrations();
+    yield new Promise(resolve => setTimeout(resolve, 1));
+  }
+  is(serviceWorkers.length, 2, "ServiceWorkers have been registered.");
+
+  extension.sendMessage();
+
+  yield extension.awaitMessage("serviceWorkersRemoved");
+
+  // The serviceWorkers and not necessarily removed immediately.
+  while (serviceWorkers.length > 0) {
+    serviceWorkers = serviceWorkerManager.getAllRegistrations();
+    yield new Promise(resolve => setTimeout(resolve, 1));
+  }
+  is(serviceWorkers.length, 0, "ServiceWorkers have been removed.");
+
+  yield extension.unload();
+  yield BrowserTestUtils.closeWindow(win);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/file_serviceWorker.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <script>
+      "use strict";
+
+      navigator.serviceWorker.register("serviceWorker.js").then(() => {
+        window.postMessage("serviceWorkerRegistered", "*");
+      });
+    </script>
+  </head>
+  <body>
+    This is a test page.
+  </body>
+<html>
new file mode 100644