"use strict"; const { PermissionTestUtils } = ChromeUtils.importESModule( "resource://testing-common/PermissionTestUtils.sys.mjs" ); const BASE_URI = "http://mochi.test:8888/browser/dom/serviceworkers/test/"; const PAGE_URI = BASE_URI + "empty.html"; const SCOPE = PAGE_URI + "?storage_permission"; const SW_SCRIPT = BASE_URI + "empty.js"; add_setup(async function () { await SpecialPowers.pushPrefEnv({ set: [ // Until the e10s refactor is complete, use a single process to avoid // service worker propagation race. ["dom.ipc.processCount", 1], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ], }); let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); await SpecialPowers.spawn( browser, [{ script: SW_SCRIPT, scope: SCOPE }], async function (opts) { let reg = await content.navigator.serviceWorker.register(opts.script, { scope: opts.scope, }); let worker = reg.installing || reg.waiting || reg.active; await new Promise(resolve => { if (worker.state === "activated") { resolve(); return; } worker.addEventListener("statechange", function onStateChange() { if (worker.state === "activated") { worker.removeEventListener("statechange", onStateChange); resolve(); } }); }); } ); BrowserTestUtils.removeTab(tab); }); add_task(async function test_allow_permission() { PermissionTestUtils.add( PAGE_URI, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW ); let tab = BrowserTestUtils.addTab(gBrowser, SCOPE); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); let controller = await SpecialPowers.spawn(browser, [], async function () { return content.navigator.serviceWorker.controller; }); ok(!!controller, "page should be controlled with storage allowed"); BrowserTestUtils.removeTab(tab); }); add_task(async function test_deny_permission() { PermissionTestUtils.add( PAGE_URI, "cookie", Ci.nsICookiePermission.ACCESS_DENY ); let tab = BrowserTestUtils.addTab(gBrowser, SCOPE); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); let controller = await SpecialPowers.spawn(browser, [], async function () { return content.navigator.serviceWorker.controller; }); is(controller, null, "page should be not controlled with storage denied"); BrowserTestUtils.removeTab(tab); PermissionTestUtils.remove(PAGE_URI, "cookie"); }); add_task(async function test_session_permission() { PermissionTestUtils.add( PAGE_URI, "cookie", Ci.nsICookiePermission.ACCESS_SESSION ); let tab = BrowserTestUtils.addTab(gBrowser, SCOPE); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); let controller = await SpecialPowers.spawn(browser, [], async function () { return content.navigator.serviceWorker.controller; }); is(controller, null, "page should be not controlled with session storage"); BrowserTestUtils.removeTab(tab); PermissionTestUtils.remove(PAGE_URI, "cookie"); }); // Test to verify an about:blank iframe successfully inherits the // parent's controller when storage is blocked between opening the // parent page and creating the iframe. add_task(async function test_block_storage_before_blank_iframe() { PermissionTestUtils.remove(PAGE_URI, "cookie"); let tab = BrowserTestUtils.addTab(gBrowser, SCOPE); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); let controller = await SpecialPowers.spawn(browser, [], async function () { return content.navigator.serviceWorker.controller; }); ok(!!controller, "page should be controlled with storage allowed"); let controller2 = await SpecialPowers.spawn(browser, [], async function () { let f = content.document.createElement("iframe"); content.document.body.appendChild(f); await new Promise(resolve => (f.onload = resolve)); return !!f.contentWindow.navigator.serviceWorker.controller; }); ok(!!controller2, "page should be controlled with storage allowed"); await SpecialPowers.pushPrefEnv({ set: [ ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT], ], }); let controller3 = await SpecialPowers.spawn(browser, [], async function () { let f = content.document.createElement("iframe"); content.document.body.appendChild(f); await new Promise(resolve => (f.onload = resolve)); return !!f.contentWindow.navigator.serviceWorker.controller; }); ok(!!controller3, "page should be controlled with storage allowed"); await SpecialPowers.popPrefEnv(); BrowserTestUtils.removeTab(tab); }); // Test to verify a blob URL iframe successfully inherits the // parent's controller when storage is blocked between opening the // parent page and creating the iframe. add_task(async function test_block_storage_before_blob_iframe() { PermissionTestUtils.remove(PAGE_URI, "cookie"); let tab = BrowserTestUtils.addTab(gBrowser, SCOPE); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); let controller = await SpecialPowers.spawn(browser, [], async function () { return content.navigator.serviceWorker.controller; }); ok(!!controller, "page should be controlled with storage allowed"); let controller2 = await SpecialPowers.spawn(browser, [], async function () { let b = new content.Blob([""], { type: "text/html", }); let f = content.document.createElement("iframe"); // No need to call revokeObjectURL() since the window will be closed shortly. f.src = content.URL.createObjectURL(b); content.document.body.appendChild(f); await new Promise(resolve => (f.onload = resolve)); return !!f.contentWindow.navigator.serviceWorker.controller; }); ok(!!controller2, "page should be controlled with storage allowed"); await SpecialPowers.pushPrefEnv({ set: [ ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT], ], }); let controller3 = await SpecialPowers.spawn(browser, [], async function () { let b = new content.Blob([""], { type: "text/html", }); let f = content.document.createElement("iframe"); // No need to call revokeObjectURL() since the window will be closed shortly. f.src = content.URL.createObjectURL(b); content.document.body.appendChild(f); await new Promise(resolve => (f.onload = resolve)); return !!f.contentWindow.navigator.serviceWorker.controller; }); ok(!!controller3, "page should be controlled with storage allowed"); await SpecialPowers.popPrefEnv(); BrowserTestUtils.removeTab(tab); }); // Test to verify a blob worker script does not hit our service // worker storage assertions when storage is blocked between opening // the parent page and creating the worker. Note, we cannot // explicitly check if the worker is controlled since we don't expose // WorkerNavigator.serviceWorkers.controller yet. add_task(async function test_block_storage_before_blob_worker() { PermissionTestUtils.remove(PAGE_URI, "cookie"); let tab = BrowserTestUtils.addTab(gBrowser, SCOPE); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); let controller = await SpecialPowers.spawn(browser, [], async function () { return content.navigator.serviceWorker.controller; }); ok(!!controller, "page should be controlled with storage allowed"); let scriptURL = await SpecialPowers.spawn(browser, [], async function () { let b = new content.Blob( ["self.postMessage(self.location.href);self.close()"], { type: "application/javascript" } ); // No need to call revokeObjectURL() since the window will be closed shortly. let u = content.URL.createObjectURL(b); let w = new content.Worker(u); return await new Promise(resolve => { w.onmessage = e => resolve(e.data); }); }); ok(scriptURL.startsWith("blob:"), "blob URL worker should run"); await SpecialPowers.pushPrefEnv({ set: [ ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT], ], }); let scriptURL2 = await SpecialPowers.spawn(browser, [], async function () { let b = new content.Blob( ["self.postMessage(self.location.href);self.close()"], { type: "application/javascript" } ); // No need to call revokeObjectURL() since the window will be closed shortly. let u = content.URL.createObjectURL(b); let w = new content.Worker(u); return await new Promise(resolve => { w.onmessage = e => resolve(e.data); }); }); ok(scriptURL2.startsWith("blob:"), "blob URL worker should run"); await SpecialPowers.popPrefEnv(); BrowserTestUtils.removeTab(tab); }); add_task(async function cleanup() { PermissionTestUtils.remove(PAGE_URI, "cookie"); let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI); let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); await SpecialPowers.spawn(browser, [SCOPE], async function (uri) { let reg = await content.navigator.serviceWorker.getRegistration(uri); let worker = reg.active; await reg.unregister(); await new Promise(resolve => { if (worker.state === "redundant") { resolve(); return; } worker.addEventListener("statechange", function onStateChange() { if (worker.state === "redundant") { worker.removeEventListener("statechange", onStateChange); resolve(); } }); }); }); BrowserTestUtils.removeTab(tab); });