diff options
Diffstat (limited to 'dom/serviceworkers/test/test_streamfilter.html')
-rw-r--r-- | dom/serviceworkers/test/test_streamfilter.html | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/dom/serviceworkers/test/test_streamfilter.html b/dom/serviceworkers/test/test_streamfilter.html new file mode 100644 index 0000000000..7367fb8b84 --- /dev/null +++ b/dom/serviceworkers/test/test_streamfilter.html @@ -0,0 +1,207 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title> + Test StreamFilter-monitored responses for ServiceWorker-intercepted requests + </title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/ExtensionTestUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<script> +// eslint-disable-next-line mozilla/no-addtask-setup +add_task(async function setup() { + SimpleTest.waitForExplicitFinish(); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.testing.enabled", true], + ], + }); + + const registration = await navigator.serviceWorker.register( + "streamfilter_worker.js" + ); + + SimpleTest.registerCleanupFunction(async function unregisterRegistration() { + await registration.unregister(); + }); + + await new Promise(resolve => { + const serviceWorker = registration.installing; + + serviceWorker.onstatechange = () => { + if (serviceWorker.state == "activated") { + resolve(); + } + }; + }); + + ok(navigator.serviceWorker.controller, "Page is controlled"); +}); + +async function getExtension() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["webRequest", "webRequestBlocking", "<all_urls>"], + }, + + // This WebExtension only proxies a response's data through a StreamFilter; + // it doesn't modify the data itself in any way. + background() { + class FilterWrapper { + constructor(requestId) { + const filter = browser.webRequest.filterResponseData(requestId); + const arrayBuffers = []; + + filter.onstart = () => { + browser.test.sendMessage("start"); + }; + + filter.ondata = ({ data }) => { + arrayBuffers.push(data); + }; + + filter.onstop = () => { + browser.test.sendMessage("stop"); + new Blob(arrayBuffers).arrayBuffer().then(buffer => { + filter.write(buffer); + filter.close(); + }); + }; + + filter.onerror = () => { + // We only ever expect a redirect error here. + browser.test.assertEq(filter.error, "ServiceWorker fallback redirection"); + browser.test.sendMessage("error"); + }; + } + } + + browser.webRequest.onBeforeRequest.addListener( + details => { + new FilterWrapper(details.requestId); + }, + { + urls: ["<all_urls>"], + types: ["xmlhttprequest"], + }, + ["blocking"] + ); + }, + }); + + await extension.startup(); + return extension; +} + +const streamFilterServerUrl = `${location.origin}/tests/dom/serviceworkers/test/streamfilter_server.sjs`; + +const requestUrlForServerQueryString = "syntheticResponse=0"; + +// streamfilter_server.sjs is expected to respond to a request to this URL. +const requestUrlForServer = `${streamFilterServerUrl}?${requestUrlForServerQueryString}`; + +const requestUrlForServiceWorkerQueryString = "syntheticResponse=1"; + +// streamfilter_worker.js is expected to respond to a request to this URL. +const requestUrlForServiceWorker = `${streamFilterServerUrl}?${requestUrlForServiceWorkerQueryString}`; + +// startNetworkerRequestFn must be a function that, when called, starts a +// network request and returns a promise that resolves after the request +// completes (or fails). This function will return the value that that promise +// resolves with (or throw if it rejects). +async function observeFilteredNetworkRequest(startNetworkRequestFn, promises) { + const networkRequestPromise = startNetworkRequestFn(); + await Promise.all(promises); + return networkRequestPromise; +} + +// Returns a promise that resolves with the XHR's response text. +function callXHR(requestUrl, promises) { + return observeFilteredNetworkRequest(() => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.onload = () => { + resolve(xhr.responseText); + }; + xhr.onerror = reject; + xhr.open("GET", requestUrl); + xhr.send(); + }); + }, promises); +} + +// Returns a promise that resolves with the Fetch's response text. +function callFetch(requestUrl, promises) { + return observeFilteredNetworkRequest(() => { + return fetch(requestUrl).then(response => response.text()); + }, promises); +} + +// The expected response text is always the query string (without the leading +// "?") of the request URL. +add_task(async function callXhrExpectServerResponse() { + info(`Performing XHR at ${requestUrlForServer}...`); + let extension = await getExtension(); + is( + await callXHR(requestUrlForServer, [ + extension.awaitMessage("start"), + extension.awaitMessage("error"), + extension.awaitMessage("stop"), + ]), + requestUrlForServerQueryString, + "Server-supplied response for XHR completed successfully" + ); + await extension.unload(); +}); + +add_task(async function callXhrExpectServiceWorkerResponse() { + info(`Performing XHR at ${requestUrlForServiceWorker}...`); + let extension = await getExtension(); + is( + await callXHR(requestUrlForServiceWorker, [ + extension.awaitMessage("start"), + extension.awaitMessage("stop"), + ]), + requestUrlForServiceWorkerQueryString, + "ServiceWorker-supplied response for XHR completed successfully" + ); + await extension.unload(); +}); + +add_task(async function callFetchExpectServerResponse() { + info(`Performing Fetch at ${requestUrlForServer}...`); + let extension = await getExtension(); + is( + await callFetch(requestUrlForServer, [ + extension.awaitMessage("start"), + extension.awaitMessage("error"), + extension.awaitMessage("stop"), + ]), + requestUrlForServerQueryString, + "Server-supplied response for Fetch completed successfully" + ); + await extension.unload(); +}); + +add_task(async function callFetchExpectServiceWorkerResponse() { + info(`Performing Fetch at ${requestUrlForServiceWorker}...`); + let extension = await getExtension(); + is( + await callFetch(requestUrlForServiceWorker, [ + extension.awaitMessage("start"), + extension.awaitMessage("stop"), + ]), + requestUrlForServiceWorkerQueryString, + "ServiceWorker-supplied response for Fetch completed successfully" + ); + await extension.unload(); +}); +</script> +</body> +</html> |