Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

// META: script=/common/get-host-info.sub.js
// META: script=/service-workers/service-worker/resources/test-helpers.sub.js
//
// The following tests assume the policy `Connection-Allowlist: (response-origin)` has been set.
const port = get_host_info().HTTPS_PORT_ELIDED;
const SUCCESS = true;
const FAILURE = false;
async function service_worker_fetch_test(t, script, origin, expectation, description) {
const scope = 'resources/';
const registration = await service_worker_unregister_and_register(t, script, scope);
await wait_for_state(t, registration.installing, 'activated');
const fetch_url = `${origin}/common/blank-with-cors.html`;
const controller = registration.active;
const result = await new Promise((resolve) => {
navigator.serviceWorker.onmessage = (e) => resolve(e.data.success);
controller.postMessage(fetch_url);
});
if (expectation === SUCCESS) {
assert_true(result, `Fetch to ${origin} should succeed.`);
} else {
assert_false(result, `Fetch to ${origin} should be blocked.`);
}
await registration.unregister();
}
// 1. Same-origin fetch from the service worker should succeed as it is allowlisted via (response-origin).
promise_test(async t => {
await service_worker_fetch_test(
t,
'resources/service-worker-fetch-script.js',
SUCCESS,
"Same-origin fetch from a service worker succeeds."
);
}, "Same-origin fetch from a service worker succeeds.");
// 2. Cross-origin fetch from the service worker should be blocked as it is not allowlisted.
promise_test(async t => {
await service_worker_fetch_test(
t,
'resources/service-worker-fetch-script.js',
FAILURE,
"Cross-origin fetch from a service worker should be blocked by its own policy."
);
}, "Cross-origin fetch from a service worker should be blocked by its own policy.");
// 3. Service worker with empty connection allowlist cannot perform any fetches.
promise_test(async t => {
await service_worker_fetch_test(
t,
'resources/service-worker-fetch-script-empty.js',
get_host_info().HTTPS_ORIGIN,
FAILURE,
"Service worker with empty connection allowlist cannot perform any fetches."
);
}, "Service worker with empty connection allowlist cannot perform any fetches.");
// Tests 4 to 7 are independent of connection allowlists since service workers
// with local schemes are expected to fail.
// 4. Service worker registration with blob: scheme should fail.
promise_test(async t => {
const blob = new Blob(['self.addEventListener("fetch", (e) => {});'], { type: 'text/javascript' });
const url = URL.createObjectURL(blob);
await promise_rejects_js(t, TypeError,
navigator.serviceWorker.register(url),
"Service worker registration with blob: scheme should fail with TypeError.");
}, "Service worker registration with blob: scheme fails.");
// 5. Service worker registration with data: scheme should fail.
promise_test(async t => {
const url = "data:text/javascript,self.addEventListener('fetch', (e) => {});";
await promise_rejects_js(t, TypeError,
navigator.serviceWorker.register(url),
"Service worker registration with data: scheme should fail with TypeError.");
}, "Service worker registration with data: scheme fails.");
// 6. Service worker registration with filesystem: scheme should fail.
promise_test(async t => {
const url = "filesystem:https://{{host}}/temporary/sw.js";
await promise_rejects_js(t, TypeError,
navigator.serviceWorker.register(url),
"Service worker registration with filesystem: scheme should fail with TypeError.");
}, "Service worker registration with filesystem: scheme fails.");
// 7. Service worker registration with about:blank scheme should fail.
promise_test(async t => {
const url = "about:blank";
await promise_rejects_js(t, TypeError,
navigator.serviceWorker.register(url),
"Service worker registration with about:blank scheme should fail with TypeError.");
}, "Service worker registration with about:blank scheme fails.");
// 8. Service worker main script fetch succeeds when it is same-origin and allowlisted.
promise_test(async t => {
const script = 'resources/service-worker-fetch-script.js';
const scope = 'resources/same-origin-allowlisted-scope';
const registration = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(_ => registration.unregister());
assert_not_equals(registration.installing, null, 'worker is installing');
}, "Same-origin service worker main script fetch succeeds with (response-origin) allowlist.");
// 9. Service worker main script fetch is blocked by creator's empty allowlist.
promise_test(async t => {
const iframe = await with_iframe('resources/blank-with-allowlist.html?pipe=header(Connection-Allowlist,\\(\\))');
t.add_cleanup(() => iframe.remove());
const script = 'service-worker-fetch-script.js';
const scope = 'empty-allowlist-scope';
// register() should fail with TypeError because the fetch of the script is blocked by the iframe's empty allowlist.
await promise_rejects_js(t, iframe.contentWindow.TypeError,
iframe.contentWindow.navigator.serviceWorker.register(script, { scope: scope }),
"Service worker registration should fail because main script fetch is blocked by creator's empty allowlist.");
}, "Service worker main script fetch is blocked by creator's empty allowlist.");
// 10. Same-origin service worker main script fetch is blocked by creator's non-matching allowlist.
promise_test(async t => {
const remote_origin = "https://{{hosts[alt][]}}" + port;
const allowlist = encodeURIComponent(`\\("${remote_origin}/*"\\)`);
const iframe = await with_iframe(`resources/blank-with-allowlist.html?pipe=header(Connection-Allowlist,${allowlist})`);
t.add_cleanup(() => iframe.remove());
const script = 'service-worker-fetch-script.js';
const scope = 'non-matching-allowlist-scope';
// register() should fail with TypeError because the fetch of the script (same-origin)
// is blocked by the iframe's allowlist which only permits the remote origin.
await promise_rejects_js(t, iframe.contentWindow.TypeError,
iframe.contentWindow.navigator.serviceWorker.register(script, { scope: scope }),
"Service worker registration should fail because main script fetch is blocked by creator's non-matching allowlist.");
}, "Same-origin service worker main script fetch is blocked by creator's non-matching allowlist.");