From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../extensions/test/xpcshell/test_ext_cache_api.js | 296 +++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_cache_api.js (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_cache_api.js') diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_cache_api.js b/toolkit/components/extensions/test/xpcshell/test_ext_cache_api.js new file mode 100644 index 0000000000..14fa8a342a --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_cache_api.js @@ -0,0 +1,296 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ + +"use strict"; + +AddonTestUtils.init(this); +AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "1", + "42" +); + +const server = createHttpServer({ + hosts: ["example.com", "anotherdomain.com"], +}); +server.registerPathHandler("/dummy", (request, response) => { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html", false); + response.write("test_ext_cache_api.js"); +}); + +add_setup(() => { + // NOTE: Services.io.offline shouldn't be set to offline, + // otherwise we would hit an unexpected behavior when + // the extension worker tries to fetch from an + // http url or cache an http url response, see Bug 1845317. + Assert.ok( + !Services.io.offline, + "Services.io.offline should not be set to true while running this test" + ); +}); + +add_task(async function test_cache_api_http_resource_allowed() { + async function background() { + try { + const BASE_URL = `http://example.com/dummy`; + + const cache = await window.caches.open("test-cache-api"); + browser.test.assertTrue( + await window.caches.has("test-cache-api"), + "CacheStorage.has should resolve to true" + ); + + // Test that adding and requesting cached http urls + // works as well. + await cache.add(BASE_URL); + browser.test.assertEq( + "test_ext_cache_api.js", + await cache.match(BASE_URL).then(res => res?.text()), + "Got the expected content from the cached http url" + ); + + // Test that the http urls that the cache API is allowed + // to fetch and cache are limited by the host permissions + // associated to the extensions (same as when the extension + // for fetch from those urls using fetch or XHR). + await browser.test.assertRejects( + cache.add(`http://anotherdomain.com/dummy`), + "NetworkError when attempting to fetch resource.", + "Got the expected rejection of requesting an http not allowed by host permissions" + ); + + // Test that deleting the cache storage works as expected. + browser.test.assertTrue( + await window.caches.delete("test-cache-api"), + "Cache deleted successfully" + ); + browser.test.assertTrue( + !(await window.caches.has("test-cache-api")), + "CacheStorage.has should resolve to false" + ); + } catch (err) { + browser.test.fail(`Unexpected error on using Cache API: ${err}`); + throw err; + } finally { + browser.test.sendMessage("test-cache-api-allowed"); + } + } + + // Verify that Cache API support for http urls is available + // regardless of extensions.backgroundServiceWorker.enabled pref. + const extension = ExtensionTestUtils.loadExtension({ + manifest: { permissions: ["http://example.com/*"] }, + background, + }); + + await extension.startup(); + + await extension.awaitMessage("test-cache-api-allowed"); + await extension.unload(); +}); + +// This test is similar to `test_cache_api_http_resource_allowed` but it does +// exercise the Cache API from a moz-extension shared worker. +// We expect the cache API calls to be successfull when it is being used to +// cache an HTTP url that is allowed for the extensions based on its host +// permission, but to fail if the extension doesn't have the required host +// permission to fetch data from that url. +add_task(async function test_cache_api_from_ext_shared_worker() { + if (!WebExtensionPolicy.useRemoteWebExtensions) { + // Ensure RemoteWorkerService has been initialized in the main + // process. + Services.obs.notifyObservers(null, "profile-after-change"); + } + + const background = async function () { + const BASE_URL_OK = `http://example.com/dummy`; + const BASE_URL_KO = `http://anotherdomain.com/dummy`; + const worker = new SharedWorker("worker.js"); + const { data: resultOK } = await new Promise(resolve => { + worker.port.onmessage = resolve; + worker.port.postMessage(["worker-cacheapi-test-allowed", BASE_URL_OK]); + }); + browser.test.assertDeepEq( + ["worker-cacheapi-test-allowed:result", { success: true }], + resultOK, + "Got success result from extension worker for allowed host url" + ); + const { data: resultKO } = await new Promise(resolve => { + worker.port.onmessage = resolve; + worker.port.postMessage(["worker-cacheapi-test-disallowed", BASE_URL_KO]); + }); + browser.test.assertDeepEq( + [ + "worker-cacheapi-test-disallowed:result", + { error: "NetworkError when attempting to fetch resource." }, + ], + resultKO, + "Got result from extension worker for disallowed host url" + ); + + browser.test.assertTrue( + await window.caches.has("test-cache-api"), + "CacheStorage.has should resolve to true" + ); + const cache = await window.caches.open("test-cache-api"); + browser.test.assertEq( + "test_ext_cache_api.js", + await cache.match(BASE_URL_OK).then(res => res?.text()), + "Got the expected content from the cached http url" + ); + browser.test.assertEq( + true, + await cache.match(BASE_URL_KO).then(res => res == undefined), + "Got no match for the http url that isn't allowed by host permissions" + ); + + browser.test.sendMessage("test-cacheapi-sharedworker:done"); + }; + + const extension = ExtensionTestUtils.loadExtension({ + background, + manifest: { permissions: ["http://example.com/*"] }, + files: { + "worker.js": function () { + self.onconnect = evt => { + const port = evt.ports[0]; + port.onmessage = async evt => { + let result = {}; + let message; + try { + const [msg, BASE_URL] = evt.data; + message = msg; + const cache = await self.caches.open("test-cache-api"); + await cache.add(BASE_URL); + result.success = true; + } catch (err) { + result.error = err.message; + throw err; + } finally { + port.postMessage([`${message}:result`, result]); + } + }; + }; + }, + }, + }); + + await extension.startup(); + await extension.awaitMessage("test-cacheapi-sharedworker:done"); + await extension.unload(); +}); + +add_task(async function test_cache_storage_evicted_on_addon_uninstalled() { + async function background() { + try { + const BASE_URL = `http://example.com/dummy`; + + const cache = await window.caches.open("test-cache-api"); + browser.test.assertTrue( + await window.caches.has("test-cache-api"), + "CacheStorage.has should resolve to true" + ); + + // Test that adding and requesting cached http urls + // works as well. + await cache.add(BASE_URL); + browser.test.assertEq( + "test_ext_cache_api.js", + await cache.match(BASE_URL).then(res => res?.text()), + "Got the expected content from the cached http url" + ); + } catch (err) { + browser.test.fail(`Unexpected error on using Cache API: ${err}`); + throw err; + } finally { + browser.test.sendMessage("cache-storage-created"); + } + } + + const extension = ExtensionTestUtils.loadExtension({ + manifest: { permissions: ["http://example.com/*"] }, + background, + // Necessary to be sure the expected extension stored data cleanup callback + // will be called when the extension is uninstalled from an AddonManager + // perspective. + useAddonManager: "temporary", + }); + + await AddonTestUtils.promiseStartupManager(); + await extension.startup(); + await extension.awaitMessage("cache-storage-created"); + + const extURL = `moz-extension://${extension.extension.uuid}`; + const extPrincipal = Services.scriptSecurityManager.createContentPrincipal( + Services.io.newURI(extURL), + {} + ); + let extCacheStorage = new CacheStorage("content", extPrincipal); + + ok( + await extCacheStorage.has("test-cache-api"), + "Got the expected extension cache storage" + ); + + await extension.unload(); + + ok( + !(await extCacheStorage.has("test-cache-api")), + "The extension cache storage data should have been evicted on addon uninstall" + ); +}); + +add_task( + { + // Pref used to allow to use the Cache WebAPI related to a page loaded from http + // (otherwise Gecko will throw a SecurityError when trying to access the webpage + // cache storage from the content script, unless the webpage is loaded from https). + pref_set: [["dom.caches.testing.enabled", true]], + }, + async function test_cache_put_from_contentscript() { + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://example.com/*"], + js: ["content.js"], + }, + ], + }, + files: { + "content.js": async function () { + const cache = await caches.open("test-cachestorage"); + const request = "http://example.com"; + const response = await fetch(request); + await cache.put(request, response).catch(err => { + browser.test.sendMessage("cache-put-error", { + name: err.name, + message: err.message, + }); + }); + }, + }, + }); + + await extension.startup(); + + const page = await ExtensionTestUtils.loadContentPage("http://example.com"); + const actualError = await extension.awaitMessage("cache-put-error"); + equal( + actualError.name, + "SecurityError", + "Got a security error from cache.put call as expected" + ); + ok( + /Disallowed on WebExtension ContentScript Request/.test( + actualError.message + ), + `Got the expected error message: ${actualError.message}` + ); + + await page.close(); + await extension.unload(); + } +); -- cgit v1.2.3