Bug 1546296 - Correctly clear Service Workers by hostname. r=baku

Differential Revision: https://phabricator.services.mozilla.com/D30455

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Johann Hofmann 2019-05-13 21:32:53 +00:00
Родитель 167de4a58d
Коммит 8aaf3c05e3
6 изменённых файлов: 175 добавлений и 12 удалений

Просмотреть файл

@ -362,13 +362,10 @@ const QuotaCleaner = {
// Clear sessionStorage
Services.obs.notifyObservers(null, "browser:purge-sessionStorage", aHost);
let exceptionThrown = false;
// ServiceWorkers: they must be removed before cleaning QuotaManager.
return Promise.all([
ServiceWorkerCleanUp.removeFromHost("http://" + aHost).catch(_ => { exceptionThrown = true; }),
ServiceWorkerCleanUp.removeFromHost("https://" + aHost).catch(_ => { exceptionThrown = true; }),
]).then(() => {
return ServiceWorkerCleanUp.removeFromHost(aHost)
.then(_ => /* exceptionThrown = */ false, _ => /* exceptionThrown = */ true)
.then(exceptionThrown => {
// QuotaManager: In the event of a failure, we call reject to propagate
// the error upwards.

Просмотреть файл

@ -102,12 +102,16 @@ var SiteDataTestUtils = {
// eslint-disable-next-line no-undef
let r = await content.navigator.serviceWorker.register(p);
return new Promise(resolve => {
let worker = r.installing;
worker.addEventListener("statechange", () => {
if (worker.state === "installed") {
resolve();
}
});
let worker = r.installing || r.waiting || r.active;
if (worker.state == "activated") {
resolve();
} else {
worker.addEventListener("statechange", () => {
if (worker.state == "activated") {
resolve();
}
});
}
});
});
});
@ -166,6 +170,60 @@ var SiteDataTestUtils = {
return false;
},
/**
* Waits for a ServiceWorker to be registered.
*
* @param {String} the url of the ServiceWorker to wait for
*
* @returns a Promise that resolves when a ServiceWorker at the
* specified location has been registered.
*/
promiseServiceWorkerRegistered(url) {
if (!(url instanceof Ci.nsIURI)) {
url = Services.io.newURI(url);
}
return new Promise(resolve => {
let listener = {
onRegister: registration => {
if (registration.principal.URI.host != url.host) {
return;
}
swm.removeListener(listener);
resolve(registration);
},
};
swm.addListener(listener);
});
},
/**
* Waits for a ServiceWorker to be unregistered.
*
* @param {String} the url of the ServiceWorker to wait for
*
* @returns a Promise that resolves when a ServiceWorker at the
* specified location has been unregistered.
*/
promiseServiceWorkerUnregistered(url) {
if (!(url instanceof Ci.nsIURI)) {
url = Services.io.newURI(url);
}
return new Promise(resolve => {
let listener = {
onUnregister: registration => {
if (registration.principal.URI.host != url.host) {
return;
}
swm.removeListener(listener);
resolve(registration);
},
};
swm.addListener(listener);
});
},
/**
* Gets the current quota usage for the specified origin.
*

Просмотреть файл

@ -25,6 +25,8 @@ XPCOM_MANIFESTS += [
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
include('/ipc/chromium/chromium-config.mozbuild')
with Files('**'):

Просмотреть файл

@ -0,0 +1,2 @@
[browser_serviceworkers.js]
support-files = worker.js

Просмотреть файл

@ -0,0 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {SiteDataTestUtils} = ChromeUtils.import("resource://testing-common/SiteDataTestUtils.jsm");
async function addServiceWorker(origin) {
let swURL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) + "worker.js";
let registered = SiteDataTestUtils.promiseServiceWorkerRegistered(swURL);
await SiteDataTestUtils.addServiceWorker(swURL);
await registered;
ok(true, `${origin} has a service worker`);
}
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.testing.enabled", true],
]});
});
add_task(async function test_deleteFromHost() {
await addServiceWorker("https://example.com");
await addServiceWorker("https://example.org");
let unregistered = SiteDataTestUtils.promiseServiceWorkerUnregistered("https://example.com");
await new Promise(aResolve => {
Services.clearData.deleteDataFromHost("example.com", true, Ci.nsIClearDataService.CLEAR_DOM_QUOTA, value => {
Assert.equal(value, 0);
aResolve();
});
});
await unregistered;
ok(!SiteDataTestUtils.hasServiceWorkers("https://example.com"), "example.com has no service worker");
ok(SiteDataTestUtils.hasServiceWorkers("https://example.org"), "example.org has a service worker");
unregistered = SiteDataTestUtils.promiseServiceWorkerUnregistered("https://example.org");
await new Promise(aResolve => {
Services.clearData.deleteDataFromHost("example.org", true, Ci.nsIClearDataService.CLEAR_DOM_QUOTA, value => {
Assert.equal(value, 0);
aResolve();
});
});
await unregistered;
ok(!SiteDataTestUtils.hasServiceWorkers("https://example.org"), "example.org has no service worker");
ok(!SiteDataTestUtils.hasServiceWorkers("https://example.com"), "example.com has no service worker");
});
add_task(async function test_deleteFromPrincipal() {
await addServiceWorker("https://test1.example.com");
await addServiceWorker("https://test1.example.org");
let unregistered = SiteDataTestUtils.promiseServiceWorkerUnregistered("https://test1.example.com");
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("https://test1.example.com/");
await new Promise(aResolve => {
Services.clearData.deleteDataFromPrincipal(principal, true, Ci.nsIClearDataService.CLEAR_DOM_QUOTA, value => {
Assert.equal(value, 0);
aResolve();
});
});
await unregistered;
ok(!SiteDataTestUtils.hasServiceWorkers("https://test1.example.com"), "test1.example.com has no service worker");
ok(SiteDataTestUtils.hasServiceWorkers("https://test1.example.org"), "test1.example.org has a service worker");
unregistered = SiteDataTestUtils.promiseServiceWorkerUnregistered("https://test1.example.org");
principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("https://test1.example.org/");
await new Promise(aResolve => {
Services.clearData.deleteDataFromPrincipal(principal, true, Ci.nsIClearDataService.CLEAR_DOM_QUOTA, value => {
Assert.equal(value, 0);
aResolve();
});
});
await unregistered;
ok(!SiteDataTestUtils.hasServiceWorkers("https://test1.example.org"), "test1.example.org has no service worker");
ok(!SiteDataTestUtils.hasServiceWorkers("https://test1.example.com"), "test1.example.com has no service worker");
});
add_task(async function test_deleteAll() {
await addServiceWorker("https://test2.example.com");
await addServiceWorker("https://test2.example.org");
let unregistered = SiteDataTestUtils.promiseServiceWorkerUnregistered("https://test2.example.com");
await new Promise(aResolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOM_QUOTA, value => {
Assert.equal(value, 0);
aResolve();
});
});
await unregistered;
ok(!SiteDataTestUtils.hasServiceWorkers("https://test2.example.com"), "test2.example.com has no service worker");
ok(!SiteDataTestUtils.hasServiceWorkers("https://test2.example.org"), "test2.example.org has no service worker");
await SiteDataTestUtils.clear();
});

Просмотреть файл

@ -0,0 +1 @@
// Empty script for testing service workers