diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/worklets | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/worklets')
57 files changed, 1312 insertions, 0 deletions
diff --git a/testing/web-platform/tests/worklets/META.yml b/testing/web-platform/tests/worklets/META.yml new file mode 100644 index 0000000000..b037fe099b --- /dev/null +++ b/testing/web-platform/tests/worklets/META.yml @@ -0,0 +1,4 @@ +spec: https://html.spec.whatwg.org/multipage/worklets.html +suggested_reviewers: + - bfgeek + - domenic diff --git a/testing/web-platform/tests/worklets/README.md b/testing/web-platform/tests/worklets/README.md new file mode 100644 index 0000000000..b06ea33cd9 --- /dev/null +++ b/testing/web-platform/tests/worklets/README.md @@ -0,0 +1 @@ +These are the tests for the [Worklets](https://html.spec.whatwg.org/multipage/worklets.html) section of the HTML Standard. diff --git a/testing/web-platform/tests/worklets/animation-worklet-credentials.https.html b/testing/web-platform/tests/worklets/animation-worklet-credentials.https.html new file mode 100644 index 0000000000..3ef830a6a2 --- /dev/null +++ b/testing/web-platform/tests/worklets/animation-worklet-credentials.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/credentials-tests.js"></script> +</head> +<body> +<script> + runCredentialsTests("animation"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/animation-worklet-csp.https.html b/testing/web-platform/tests/worklets/animation-worklet-csp.https.html new file mode 100644 index 0000000000..3950ea2094 --- /dev/null +++ b/testing/web-platform/tests/worklets/animation-worklet-csp.https.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>ContentSecurityPolicy for Animation Worklets</title> +<meta name="timeout" content="long"> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/worklet-test-utils.js"></script> +<script src="resources/csp-tests.js"></script> +<script> +runContentSecurityPolicyTests("animation"); +</script> diff --git a/testing/web-platform/tests/worklets/animation-worklet-import.https.html b/testing/web-platform/tests/worklets/animation-worklet-import.https.html new file mode 100644 index 0000000000..98b56d3625 --- /dev/null +++ b/testing/web-platform/tests/worklets/animation-worklet-import.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/import-tests.js"></script> +</head> +<body> +<script> + runImportTests("animation"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/animation-worklet-referrer.https.html b/testing/web-platform/tests/worklets/animation-worklet-referrer.https.html new file mode 100644 index 0000000000..49933dea47 --- /dev/null +++ b/testing/web-platform/tests/worklets/animation-worklet-referrer.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="timeout" content="long"> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/referrer-tests.js"></script> +</head> +<body> +<script> + runReferrerTests("animation"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/animation-worklet-service-worker-interception.https.html b/testing/web-platform/tests/worklets/animation-worklet-service-worker-interception.https.html new file mode 100644 index 0000000000..33000ee860 --- /dev/null +++ b/testing/web-platform/tests/worklets/animation-worklet-service-worker-interception.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/service-worker-interception-tests.js"></script> + <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> +</head> +<body> +<script> + runServiceWorkerInterceptionTests("animation"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/audio-worklet-credentials.https.html b/testing/web-platform/tests/worklets/audio-worklet-credentials.https.html new file mode 100644 index 0000000000..9d867db7ce --- /dev/null +++ b/testing/web-platform/tests/worklets/audio-worklet-credentials.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/credentials-tests.js"></script> +</head> +<body> +<script> + runCredentialsTests("audio"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/audio-worklet-csp.https.html b/testing/web-platform/tests/worklets/audio-worklet-csp.https.html new file mode 100644 index 0000000000..76018705fa --- /dev/null +++ b/testing/web-platform/tests/worklets/audio-worklet-csp.https.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>ContentSecurityPolicy for Audio Worklets</title> +<meta name="timeout" content="long"> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/worklet-test-utils.js"></script> +<script src="resources/csp-tests.js"></script> +<script> +runContentSecurityPolicyTests("audio"); +</script> diff --git a/testing/web-platform/tests/worklets/audio-worklet-import.https.html b/testing/web-platform/tests/worklets/audio-worklet-import.https.html new file mode 100644 index 0000000000..cff063a436 --- /dev/null +++ b/testing/web-platform/tests/worklets/audio-worklet-import.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/import-tests.js"></script> +</head> +<body> +<script> + runImportTests("audio"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/audio-worklet-referrer.https.html b/testing/web-platform/tests/worklets/audio-worklet-referrer.https.html new file mode 100644 index 0000000000..61cb63d75c --- /dev/null +++ b/testing/web-platform/tests/worklets/audio-worklet-referrer.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="timeout" content="long"> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/referrer-tests.js"></script> +</head> +<body> +<script> + runReferrerTests("audio"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/audio-worklet-service-worker-interception.https.html b/testing/web-platform/tests/worklets/audio-worklet-service-worker-interception.https.html new file mode 100644 index 0000000000..479ae176f9 --- /dev/null +++ b/testing/web-platform/tests/worklets/audio-worklet-service-worker-interception.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/service-worker-interception-tests.js"></script> + <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> +</head> +<body> +<script> + runServiceWorkerInterceptionTests("audio"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/idlharness.https.any.js b/testing/web-platform/tests/worklets/idlharness.https.any.js new file mode 100644 index 0000000000..2900b38124 --- /dev/null +++ b/testing/web-platform/tests/worklets/idlharness.https.any.js @@ -0,0 +1,11 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://drafts.css-houdini.org/worklets/ + +'use strict'; + +idl_test( + ['worklets'], + [] +); diff --git a/testing/web-platform/tests/worklets/layout-worklet-credentials.https.html b/testing/web-platform/tests/worklets/layout-worklet-credentials.https.html new file mode 100644 index 0000000000..9468d2da7d --- /dev/null +++ b/testing/web-platform/tests/worklets/layout-worklet-credentials.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/credentials-tests.js"></script> +</head> +<body> +<script> + runCredentialsTests("layout"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/layout-worklet-csp.https.html b/testing/web-platform/tests/worklets/layout-worklet-csp.https.html new file mode 100644 index 0000000000..a670f80265 --- /dev/null +++ b/testing/web-platform/tests/worklets/layout-worklet-csp.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="timeout" content="long"> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/csp-tests.js"></script> +</head> +<body> +<script> + runContentSecurityPolicyTests("layout"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/layout-worklet-import.https.html b/testing/web-platform/tests/worklets/layout-worklet-import.https.html new file mode 100644 index 0000000000..a2f57c221b --- /dev/null +++ b/testing/web-platform/tests/worklets/layout-worklet-import.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/import-tests.js"></script> +</head> +<body> +<script> + runImportTests("layout"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/layout-worklet-referrer.https.html b/testing/web-platform/tests/worklets/layout-worklet-referrer.https.html new file mode 100644 index 0000000000..dc7b84b350 --- /dev/null +++ b/testing/web-platform/tests/worklets/layout-worklet-referrer.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="timeout" content="long"> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/referrer-tests.js"></script> +</head> +<body> +<script> + runReferrerTests("layout"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/layout-worklet-service-worker-interception.https.html b/testing/web-platform/tests/worklets/layout-worklet-service-worker-interception.https.html new file mode 100644 index 0000000000..146dff9e53 --- /dev/null +++ b/testing/web-platform/tests/worklets/layout-worklet-service-worker-interception.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/service-worker-interception-tests.js"></script> + <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> +</head> +<body> +<script> + runServiceWorkerInterceptionTests("layout"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/paint-worklet-credentials.https.html b/testing/web-platform/tests/worklets/paint-worklet-credentials.https.html new file mode 100644 index 0000000000..184a79b6e8 --- /dev/null +++ b/testing/web-platform/tests/worklets/paint-worklet-credentials.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/credentials-tests.js"></script> +</head> +<body> +<script> + runCredentialsTests("paint"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/paint-worklet-csp.https.html b/testing/web-platform/tests/worklets/paint-worklet-csp.https.html new file mode 100644 index 0000000000..61019d19ef --- /dev/null +++ b/testing/web-platform/tests/worklets/paint-worklet-csp.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="timeout" content="long"> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/csp-tests.js"></script> +</head> +<body> +<script> + runContentSecurityPolicyTests("paint"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/paint-worklet-import.https.html b/testing/web-platform/tests/worklets/paint-worklet-import.https.html new file mode 100644 index 0000000000..68e926c8c1 --- /dev/null +++ b/testing/web-platform/tests/worklets/paint-worklet-import.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/import-tests.js"></script> +</head> +<body> +<script> + runImportTests("paint"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/paint-worklet-referrer.https.html b/testing/web-platform/tests/worklets/paint-worklet-referrer.https.html new file mode 100644 index 0000000000..8f3d82a1dd --- /dev/null +++ b/testing/web-platform/tests/worklets/paint-worklet-referrer.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="timeout" content="long"> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/referrer-tests.js"></script> +</head> +<body> +<script> + runReferrerTests("paint"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/paint-worklet-service-worker-interception.https.html b/testing/web-platform/tests/worklets/paint-worklet-service-worker-interception.https.html new file mode 100644 index 0000000000..fdce9ca188 --- /dev/null +++ b/testing/web-platform/tests/worklets/paint-worklet-service-worker-interception.https.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/worklet-test-utils.js"></script> + <script src="resources/service-worker-interception-tests.js"></script> + <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> +</head> +<body> +<script> + runServiceWorkerInterceptionTests("paint"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/resources/addmodule-window.html b/testing/web-platform/tests/worklets/resources/addmodule-window.html new file mode 100644 index 0000000000..6263e6ef8e --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/addmodule-window.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> + <title>Worklet: Referrer</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="worklet-test-utils.js"></script> +</head> +<body> +<script> +// Calls addModule() on a given worklet type with a script url. +// +// [Message Format] +// - type: 'paint' (worklet types defined in get_worklet()) +// - script_url: 'worklet-script.js' +window.onmessage = e => { + const worklet_type = e.data.type; + const script_url = e.data.script_url; + get_worklet(worklet_type).addModule(script_url) + .then(() => window.opener.postMessage('RESOLVED', '*')) + .catch(e => window.opener.postMessage('REJECTED', '*')); +}; + +window.opener.postMessage('LOADED', '*'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/resources/credentials-tests.js b/testing/web-platform/tests/worklets/resources/credentials-tests.js new file mode 100644 index 0000000000..ec0b7014bf --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/credentials-tests.js @@ -0,0 +1,130 @@ +function createCookieValue(settings) { + return settings.credentials + '-' + settings.origin; +} + +function createSetCookieURL(settings) { + const params = new URLSearchParams; + params.append('name', 'cookieName'); + params.append('value', createCookieValue(settings)); + if (settings.origin == 'same') { + return get_host_info().HTTPS_ORIGIN + + '/worklets/resources/set-cookie.py?' + params; + } + if (settings.origin == 'remote') { + return get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/set-cookie.py?' + params; + } + assert_unreached('settings.origin has an invalid value.'); +} + +function createScriptURL(settings) { + const params = new URLSearchParams; + if (settings.expectCredentialsSent) + params.append('value', createCookieValue(settings)); + if (settings.origin == 'same') { + return get_host_info().HTTPS_ORIGIN + + '/worklets/resources/credentials.py?' + params; + } + if (settings.origin == 'remote') { + return get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/credentials.py?' + params; + } + assert_unreached('settings.origin has an invalid value.'); +} + +function createWorkletOptions(settings) { + if (settings.credentials == '') + return {}; + return { credentials: settings.credentials }; +} + +// Run a credentials test with the given settings. +// +// Example: +// settings = { +// workletType: 'paint', +// credentials: 'include', +// origin: 'same', // 'same' or 'remote' +// expectCredentialsSent: true +// }; +function runCredentialsTest(settings) { + const worklet = get_worklet(settings.workletType); + const setCookieURL = createSetCookieURL(settings); + const scriptURL = createScriptURL(settings); + const options = createWorkletOptions(settings); + + // { credentials: 'include' } is necessary for configuring document's cookies + // with the Set-Cookie: header of the response. + return fetch(setCookieURL, { mode: 'cors', credentials: 'include' }) + .then(response => worklet.addModule(scriptURL, options)); +} + +// Runs a series of tests related to credentials on a worklet. +// +// Usage: +// runCredentialsTests("paint"); +function runCredentialsTests(worklet_type) { + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: '', + origin: 'same', + expectCredentialsSent: true }); + }, 'Importing a same-origin script with the default WorkletOptions should ' + + 'send the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: '', + origin: 'remote', + expectCredentialsSent: false }); + }, 'Importing a remote-origin script with the default WorkletOptions ' + + 'should not send the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: 'omit', + origin: 'same', + expectCredentialsSent: false }); + }, 'Importing a same-origin script with credentials=omit should not send ' + + 'the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: 'omit', + origin: 'remote', + expectCredentialsSent: false }); + }, 'Importing a remote-origin script with credentials=omit should not send ' + + 'the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: 'same-origin', + origin: 'same', + expectCredentialsSent: true }); + }, 'Importing a same-origin script with credentials=same-origin should ' + + 'send the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: 'same-origin', + origin: 'remote', + expectCredentialsSent: false }); + }, 'Importing a remote-origin script with credentials=same-origin should ' + + 'not send the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: 'include', + origin: 'same', + expectCredentialsSent: true }); + }, 'Importing a same-origin script with credentials=include should send ' + + 'the credentials'); + + promise_test(() => { + return runCredentialsTest({ workletType: worklet_type, + credentials: 'include', + origin: 'remote', + expectCredentialsSent: true }); + }, 'Importing a remote-origin script with credentials=include should ' + + 'send the credentials'); +} diff --git a/testing/web-platform/tests/worklets/resources/credentials.py b/testing/web-platform/tests/worklets/resources/credentials.py new file mode 100644 index 0000000000..d5fb05aeca --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/credentials.py @@ -0,0 +1,20 @@ +# Returns a valid response when a request has appropriate credentials. +def main(request, response): + cookie = request.cookies.first(b"cookieName", None) + expected_value = request.GET.first(b"value", None) + source_origin = request.headers.get(b"origin", None) + if source_origin is None: + # Same origin GET won't include origin header + source_origin = "%s://%s" % (request.url_parts.scheme, + request.url_parts.netloc) + if request.url_parts.port: + source_origin += ":%s" % request.url_parts.port + + response_headers = [(b"Content-Type", b"text/javascript"), + (b"Access-Control-Allow-Origin", source_origin), + (b"Access-Control-Allow-Credentials", b"true")] + + if cookie == expected_value: + return (200, response_headers, u"") + + return (404, response_headers, u"") diff --git a/testing/web-platform/tests/worklets/resources/csp-tests.js b/testing/web-platform/tests/worklets/resources/csp-tests.js new file mode 100644 index 0000000000..ab698d0efd --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/csp-tests.js @@ -0,0 +1,147 @@ +function openWindow(url) { + return new Promise(resolve => { + const win = window.open(url, '_blank'); + add_result_callback(() => win.close()); + window.onmessage = e => { + assert_equals(e.data, 'LOADED'); + resolve(win); + }; + }); +} + +function openWindowAndExpectResult(windowURL, scriptURL, type, expectation) { + return openWindow(windowURL).then(win => { + const promise = new Promise(r => window.onmessage = r); + win.postMessage({ type: type, script_url: scriptURL }, '*'); + return promise; + }).then(msg_event => assert_equals(msg_event.data, expectation)); +} + +// Runs a series of tests related to content security policy on a worklet. +// +// Usage: +// runContentSecurityPolicyTests("paint"); +function runContentSecurityPolicyTests(workletType) { + runSrcTests(workletType); + runMixedContentTests(workletType); +} + +// script-src and worker-src tests. +function runSrcTests(workletType) { + const kWindowConfigs = [ + { + 'windowURL': + 'resources/addmodule-window.html?pipe=header(' + + 'Content-Security-Policy, script-src \'self\' \'unsafe-inline\')', + 'crossOriginExpectation': 'REJECTED', + 'message': 'should be blocked by the script-src \'self\' directive.' + }, + { + 'windowURL': + 'resources/addmodule-window.html?pipe=header(' + + 'Content-Security-Policy, script-src ' + location.origin + ' ' + + get_host_info().HTTPS_REMOTE_ORIGIN + ' \'unsafe-inline\')', + 'crossOriginExpectation': 'RESOLVED', + 'message': + 'should not be blocked because the script-src directive ' + + 'specifying the origin allows it.' + }, + { + 'windowURL': + 'resources/addmodule-window.html?pipe=header(' + + 'Content-Security-Policy, script-src * \'unsafe-inline\')', + 'crossOriginExpectation': 'RESOLVED', + 'message': + 'should not be blocked because the script-src * directive allows it.' + }, + { + 'windowURL': + 'resources/addmodule-window.html?pipe=header(' + + 'Content-Security-Policy, worker-src \'self\' \'unsafe-inline\')', + 'crossOriginExpectation': 'RESOLVED', + 'message': + 'should not be blocked by the worker-src directive ' + + 'because worklets obey the script-src directive.' + } + ]; + for (const windowConfig of kWindowConfigs) { + promise_test(t => { + const kScriptURL = + get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/empty-worklet-script-with-cors-header.js'; + return openWindowAndExpectResult( + windowConfig.windowURL, kScriptURL, workletType, + windowConfig.crossOriginExpectation); + }, + 'A remote-origin worklet ' + windowConfig.message); + + promise_test(t => { + const kScriptURL = 'import-remote-origin-empty-worklet-script.sub.js'; + return openWindowAndExpectResult( + windowConfig.windowURL, kScriptURL, workletType, + windowConfig.crossOriginExpectation); + }, + 'A same-origin worklet importing a remote-origin script ' + + windowConfig.message); + + promise_test(t => { + // A worklet on HTTPS_REMOTE_ORIGIN will import a child script on + // HTTPS_REMOTE_ORIGIN. + const kScriptURL = + get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/import-empty-worklet-script-with-cors-header.js'; + return openWindowAndExpectResult( + windowConfig.windowURL, kScriptURL, workletType, + windowConfig.crossOriginExpectation); + }, + 'A remote-origin worklet importing a remote-origin script ' + + windowConfig.message); + + promise_test(t => { + const kScriptURL = + '/common/redirect.py?location=' + encodeURIComponent( + get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/empty-worklet-script-with-cors-header.js'); + return openWindowAndExpectResult( + windowConfig.windowURL, kScriptURL, workletType, + windowConfig.crossOriginExpectation); + }, + 'A remote-origin-redirected worklet ' + windowConfig.message); + + promise_test(t => { + const kScriptURL = + 'import-remote-origin-redirected-empty-worklet-script.sub.js'; + return openWindowAndExpectResult( + windowConfig.windowURL, kScriptURL, workletType, + windowConfig.crossOriginExpectation); + }, + 'A same-origin worklet importing a remote-origin-redirected script ' + + windowConfig.message); + } +} + +// Mixed content tests. +function runMixedContentTests(workletType) { + const kInsecureURL = + get_host_info().HTTP_ORIGIN + + '/worklets/resources/empty-worklet-script-with-cors-header.js'; + const kScriptConfigs = [ + {URL: kInsecureURL, + message: 'An insecure-origin worklet'}, + {URL: '/common/redirect.py?location=' + encodeURIComponent(kInsecureURL), + message: 'An insecure-origin-redirected worklet'}, + {URL: 'import-insecure-origin-empty-worklet-script.sub.js', + message: 'A same-origin worklet importing an insecure-origin script'}, + {URL: 'import-insecure-origin-redirected-empty-worklet-script.sub.js', + message: 'A same-origin worklet ' + + 'importing an insecure-origin-redirected script'} + ]; + for (const scriptConfig of kScriptConfigs) { + promise_test(t => { + const kWindowURL = 'resources/addmodule-window.html'; + return openWindowAndExpectResult( + kWindowURL, scriptConfig.URL, workletType, 'REJECTED'); + }, + scriptConfig.message + ' should be blocked because of mixed contents.'); + } +} diff --git a/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js new file mode 100644 index 0000000000..9513071c6f --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js @@ -0,0 +1 @@ +// This file is served with "Access-Control-Allow-Origin" header. diff --git a/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/worklets/resources/empty-worklet-script.js b/testing/web-platform/tests/worklets/resources/empty-worklet-script.js new file mode 100644 index 0000000000..49ceb2648a --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/empty-worklet-script.js @@ -0,0 +1 @@ +// Do nothing. diff --git a/testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js new file mode 100644 index 0000000000..2dc7e0bd3c --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js @@ -0,0 +1 @@ +import './import-cyclic-worklet-script.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js new file mode 100644 index 0000000000..bd04a189b2 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js @@ -0,0 +1,3 @@ +// This file and descendant files are served with "Access-Control-Allow-Origin" +// header. +import './empty-worklet-script-with-cors-header.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js new file mode 100644 index 0000000000..a04a2edf81 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js @@ -0,0 +1,5 @@ +// Some tests rely on some unintuitive cleverness due to WPT's test setup: +// 'Upgrade-Insecure-Requests' does not upgrade the port number, so we use URLs +// in the form `http://[host]:[https-port]`. If the upgrade fails, the load will +// fail, as we don't serve HTTP over the secure port. +import 'http://{{host}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js new file mode 100644 index 0000000000..888d876bff --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js @@ -0,0 +1,5 @@ +// Some tests rely on some unintuitive cleverness due to WPT's test setup: +// 'Upgrade-Insecure-Requests' does not upgrade the port number, so we use URLs +// in the form `http://[host]:[https-port]`. If the upgrade fails, the load will +// fail, as we don't serve HTTP over the secure port. +import '/common/redirect.py?location=http://{{host}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js new file mode 100644 index 0000000000..5fe8d91100 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js @@ -0,0 +1 @@ +import './empty-worklet-script.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js new file mode 100644 index 0000000000..b63685f642 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js @@ -0,0 +1 @@ +import './import-nested-internal-worklet-script.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js new file mode 100644 index 0000000000..0837032f83 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js @@ -0,0 +1 @@ +import './non-existent-worklet-script.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js new file mode 100644 index 0000000000..1dcb6f3bcb --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js @@ -0,0 +1,2 @@ +// Forward GET parameters to the server. +import './referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}'; diff --git a/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js new file mode 100644 index 0000000000..06c1f87618 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js @@ -0,0 +1 @@ +import 'https://{{domains[www1]}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js new file mode 100644 index 0000000000..7afa3523b9 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js @@ -0,0 +1 @@ +import '/common/redirect.py?location=https://{{domains[www1]}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js new file mode 100644 index 0000000000..f301701b1c --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js @@ -0,0 +1,2 @@ +// Forward GET parameters to the server. +import 'https://{{domains[www1]}}:{{ports[https][0]}}/worklets/resources/referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}'; diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js new file mode 100644 index 0000000000..33af2258ff --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js @@ -0,0 +1,2 @@ +// Forward GET parameters to the server. +import '{{GET[requestor_origin]}}/worklets/resources/referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}'; diff --git a/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js new file mode 100644 index 0000000000..1539ad004e --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js @@ -0,0 +1 @@ +import './syntax-error-worklet-script.js'; diff --git a/testing/web-platform/tests/worklets/resources/import-tests.js b/testing/web-platform/tests/worklets/resources/import-tests.js new file mode 100644 index 0000000000..0c631a8a9f --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/import-tests.js @@ -0,0 +1,162 @@ +// Runs a series of tests related to importing scripts on a worklet. +// +// Usage: +// runImportTests("paint"); +function runImportTests(worklet_type) { + const worklet = get_worklet(worklet_type); + + promise_test(() => { + const kScriptURL = 'resources/empty-worklet-script.js'; + return worklet.addModule(kScriptURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined, + 'Promise should resolve with no arguments.'); + }); + }, 'Importing a script resolves the given promise.'); + + promise_test(() => { + const kScriptURL = 'resources/empty-worklet-script.js'; + return Promise.all([ + worklet.addModule(kScriptURL + '?1'), + worklet.addModule(kScriptURL + '?2'), + worklet.addModule(kScriptURL + '?3') + ]).then(undefined_args => { + assert_array_equals(undefined_args, + [undefined, undefined, undefined], + 'Promise should resolve with no arguments.'); + }); + }, 'Importing scripts resolves all the given promises.'); + + promise_test(() => { + const kScriptURL = 'resources/import-nested-worklet-script.js'; + return worklet.addModule(kScriptURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined, + 'Promise should resolve with no arguments.'); + }); + }, 'Importing nested scripts resolves the given promise'); + + promise_test(() => { + const kScriptURL = 'resources/import-cyclic-worklet-script.js'; + return worklet.addModule(kScriptURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined, + 'Promise should resolve with no arguments.'); + }); + }, 'Importing cyclic scripts resolves the given promise'); + + promise_test(() => { + const kScriptURL = 'resources/throwing-worklet-script.js'; + return worklet.addModule(kScriptURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined, + 'Promise should resolve with no arguments.'); + }); + }, 'Importing a script which throws should still resolve the given ' + + 'promise.'); + + promise_test(t => { + const kScriptURL = 'non-existent-worklet-script.js'; + return promise_rejects_dom(t, 'AbortError', + worklet.addModule(kScriptURL)); + }, 'Importing a non-existent script rejects the given promise with an ' + + 'AbortError.'); + + promise_test(t => { + const kInvalidScriptURL = 'http://invalid:123$' + return promise_rejects_dom(t, 'SyntaxError', + worklet.addModule(kInvalidScriptURL)); + }, 'Importing an invalid URL should reject the given promise with a ' + + 'SyntaxError.'); + + promise_test(() => { + const kBlob = new Blob([""], {type: 'text/javascript'}); + const kBlobURL = URL.createObjectURL(kBlob); + return worklet.addModule(kBlobURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined); + }); + }, 'Importing a blob URL should resolve the given promise.'); + + promise_test(t => { + const kFileURL = 'file:///empty-worklet-script.js'; + return promise_rejects_dom(t, 'AbortError', + worklet.addModule(kFileURL)); + }, 'Importing a file:// URL should reject the given promise.'); + + promise_test(() => { + const kDataURL = 'data:text/javascript, // Do nothing.'; + return worklet.addModule(kDataURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined); + }); + }, 'Importing a data URL should resolve the given promise.'); + + promise_test(t => { + const kScriptURL = 'about:blank'; + return promise_rejects_dom(t, 'AbortError', + worklet.addModule(kScriptURL)); + }, 'Importing about:blank should reject the given promise.'); + + promise_test(() => { + // Specify the Access-Control-Allow-Origin header to enable cross origin + // access. + const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/empty-worklet-script.js' + + '?pipe=header(Access-Control-Allow-Origin, *)'; + return worklet.addModule(kScriptURL).then(undefined_arg => { + assert_equals(undefined_arg, undefined); + }); + }, 'Importing a cross origin resource with the ' + + 'Access-Control-Allow-Origin header should resolve the given promise'); + + promise_test(t => { + // Don't specify the Access-Control-Allow-Origin header. addModule() + // should be rejected because of disallowed cross origin access. + const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/empty-worklet-script.js'; + return promise_rejects_dom(t, 'AbortError', + worklet.addModule(kScriptURL)); + }, 'Importing a cross origin resource without the ' + + 'Access-Control-Allow-Origin header should reject the given promise'); + + promise_test(() => { + const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/empty-worklet-script.js' + + '?pipe=header(Access-Control-Allow-Origin, ' + + location.origin + ')'; + return worklet.addModule('/common/redirect.py?location=' + + encodeURIComponent(kScriptURL)) + .then(undefined_arg => { + assert_equals(undefined_arg, undefined); + }); + }, 'Importing a cross-origin-redirected resource with the ' + + 'Access-Control-Allow-Origin header should resolve the given promise'); + + promise_test(t => { + const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/empty-worklet-script.js'; + return promise_rejects_dom(t, 'AbortError', + worklet.addModule( + '/common/redirect.py?location=' + + encodeURIComponent(kScriptURL))); + }, 'Importing a cross-origin-redirected resource without the ' + + 'Access-Control-Allow-Origin header should reject the given promise'); + + promise_test(t => { + const kScriptURL = 'resources/syntax-error-worklet-script.js'; + return promise_rejects_js(t, SyntaxError, + worklet.addModule(kScriptURL)); + }, 'Importing a script that has a syntax error should reject the given ' + + 'promise.'); + + promise_test(t => { + const kScriptURL = 'resources/import-syntax-error-worklet-script.js'; + return promise_rejects_js(t, SyntaxError, + worklet.addModule(kScriptURL)); + }, 'Importing a nested script that has a syntax error should reject the ' + + 'given promise.'); + + promise_test(t => { + const kBlob = new Blob(["import 'invalid-specifier.js';"], + {type: 'text/javascript'}); + const kBlobURL = URL.createObjectURL(kBlob); + return promise_rejects_js(t, TypeError, + worklet.addModule(kBlobURL)); + }, 'Importing a script that imports an invalid identifier should reject ' + + 'the given promise.'); +} diff --git a/testing/web-platform/tests/worklets/resources/referrer-checker.py b/testing/web-platform/tests/worklets/resources/referrer-checker.py new file mode 100644 index 0000000000..4c6ea6e5c2 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/referrer-checker.py @@ -0,0 +1,24 @@ +# Returns a valid response when request's |referrer| matches +# |expected_referrer|. +def main(request, response): + # We want |referrer| to be the referrer header with no query params, + # because |expected_referrer| will not contain any query params, and + # thus cannot be compared with the actual referrer header if it were to + # contain query params. This works fine if the actual referrer has no + # query params too. + referrer = request.headers.get(b"referer", b"").split(b"?")[0] + referrer_policy = request.GET.first(b"referrer_policy") + expected_referrer = request.GET.first(b"expected_referrer", b"") + response_headers = [(b"Content-Type", b"text/javascript"), + (b"Access-Control-Allow-Origin", b"*")] + + if referrer_policy == b"no-referrer" or referrer_policy == b"origin": + if referrer == expected_referrer: + return (200, response_headers, u"") + return (404, response_headers) + + if referrer_policy == b"same-origin": + if referrer == expected_referrer: + return (200, response_headers, u"") + return (404, response_headers) + return (404, response_headers) diff --git a/testing/web-platform/tests/worklets/resources/referrer-tests.js b/testing/web-platform/tests/worklets/resources/referrer-tests.js new file mode 100644 index 0000000000..ab24945f31 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/referrer-tests.js @@ -0,0 +1,201 @@ +function openWindow(t, url) { + return new Promise(resolve => { + let win = window.open(url, '_blank'); + t.add_cleanup(() => win.close()); + window.onmessage = e => { + assert_equals(e.data, 'LOADED'); + resolve(win); + }; + }); +} + +// Run a referrer policy test with the given settings. +// +// Example: +// settings = { +// workletType: 'paint', +// fetchType: 'top-level' or 'descendant', +// referrerPolicy: 'no-referrer', +// scriptsOrigins: { topLevel: 'same', descendant: 'remote' } +// }; +function runReferrerTest(t, settings) { + const kWindowURL = + 'resources/referrer-window.html' + + `?pipe=header(Referrer-Policy,${settings.referrerPolicy})`; + return openWindow(t, kWindowURL).then(win => { + const promise = new Promise(resolve => window.onmessage = resolve); + win.postMessage(settings, '*'); + return promise; + }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED')); +} + +// Runs a series of tests related to the referrer policy on a worklet. +// +// Usage: +// runReferrerTests("paint"); +function runReferrerTests(workletType) { + const worklet = get_worklet(workletType); + + // Tests for top-level script fetch ----------------------------------------- + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'top-level', + referrerPolicy: 'no-referrer', + scriptOrigins: { topLevel: 'same' } }); + }, 'Importing a same-origin script from a page that has "no-referrer" ' + + 'referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'top-level', + referrerPolicy: 'no-referrer', + scriptOrigins: { topLevel: 'remote' } }); + }, 'Importing a remote-origin script from a page that has "no-referrer" ' + + 'referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'top-level', + referrerPolicy: 'origin', + scriptOrigins: { topLevel: 'same' } }); + }, 'Importing a same-origin script from a page that has "origin" ' + + 'referrer policy should send only an origin as referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'top-level', + referrerPolicy: 'origin', + scriptOrigins: { topLevel: 'remote' } }); + }, 'Importing a remote-origin script from a page that has "origin" ' + + 'referrer policy should send only an origin as referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'top-level', + referrerPolicy: 'same-origin', + scriptOrigins: { topLevel: 'same' } }); + }, 'Importing a same-origin script from a page that has "same-origin" ' + + 'referrer policy should send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'top-level', + referrerPolicy: 'same-origin', + scriptOrigins: { topLevel: 'remote' } }); + }, 'Importing a remote-origin script from a page that has "same-origin" ' + + 'referrer policy should not send referrer.'); + + // Tests for descendant script fetch ----------------------------------------- + + // Referrer policy: no-referrer. + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'no-referrer', + scriptOrigins: { topLevel: 'same', + descendant: 'same' } }); + }, 'Importing a same-origin script from a same-origin worklet script that ' + + 'has "no-referrer" referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'no-referrer', + scriptOrigins: { topLevel: 'same', + descendant: 'remote' } }); + }, 'Importing a remote-origin script from a same-origin worklet script ' + + 'that has "no-referrer" referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'no-referrer', + scriptOrigins: { topLevel: 'remote', + descendant: 'same' } }); + }, 'Importing a same-origin script from a remote-origin worklet script ' + + 'that has "no-referrer" referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'no-referrer', + scriptOrigins: { topLevel: 'remote', + descendant: 'remote' } }); + }, 'Importing a remote-origin script from a remote-origin worklet script ' + + 'that has "no-referrer" referrer policy should not send referrer.'); + + // Referrer policy: origin. + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'origin', + scriptOrigins: { topLevel: 'same', + descendant: 'same' } }); + }, 'Importing a same-origin script from a same-origin worklet script that ' + + 'has "origin" referrer policy should send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'origin', + scriptOrigins: { topLevel: 'same', + descendant: 'remote' } }); + }, 'Importing a remote-origin script from a same-origin worklet script ' + + 'that has "origin" referrer policy should send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'origin', + scriptOrigins: { topLevel: 'remote', + descendant: 'same' } }); + }, 'Importing a same-origin script from a remote-origin worklet script ' + + 'that has "origin" referrer policy should send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'origin', + scriptOrigins: { topLevel: 'remote', + descendant: 'remote' } }); + }, 'Importing a remote-origin script from a remote-origin worklet script ' + + 'that has "origin" referrer policy should send referrer.'); + + // Referrer policy: same-origin. + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'same-origin', + scriptOrigins: { topLevel: 'same', + descendant: 'same' } }); + }, 'Importing a same-origin script from a same-origin worklet script that ' + + 'has "same-origin" referrer policy should send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'same-origin', + scriptOrigins: { topLevel: 'same', + descendant: 'remote' } }); + }, 'Importing a remote-origin script from a same-origin worklet script ' + + 'that has "same-origin" referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'same-origin', + scriptOrigins: { topLevel: 'remote', + descendant: 'same' } }); + }, 'Importing a same-origin script from a remote-origin worklet script ' + + 'that has "same-origin" referrer policy should not send referrer.'); + + promise_test(t => { + return runReferrerTest(t, { workletType: workletType, + fetchType: 'descendant', + referrerPolicy: 'same-origin', + scriptOrigins: { topLevel: 'remote', + descendant: 'remote' } }); + }, 'Importing a remote-origin script from a remote-origin worklet script ' + + 'that has "same-origin" referrer policy should send referrer.'); +} diff --git a/testing/web-platform/tests/worklets/resources/referrer-window.html b/testing/web-platform/tests/worklets/resources/referrer-window.html new file mode 100644 index 0000000000..1d8d38b719 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/referrer-window.html @@ -0,0 +1,113 @@ +<!DOCTYPE html> +<html> +<head> + <title>Worklet: Referrer</title> + <script src="/common/get-host-info.sub.js"></script> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="worklet-test-utils.js"></script> +</head> +<body> +<script> +function createScriptURLForTopLevel(scriptOrigin) { + if (scriptOrigin === 'same') + return new URL('referrer-checker.py', location.href); + if (scriptOrigin === 'remote') { + return new URL(get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/referrer-checker.py'); + } + assert_unreached('scriptOrigin should be \'same\' or \'remote\''); +} + +function createScriptURLForDecendant(scriptOrigins) { + if (scriptOrigins.topLevel === 'same' && + scriptOrigins.descendant === 'same') { + return new URL('import-referrer-checker-worklet-script.sub.js', + location.href); + } + if (scriptOrigins.topLevel === 'same' && + scriptOrigins.descendant === 'remote') { + return new URL( + 'import-remote-origin-referrer-checker-worklet-script.sub.js', + location.href); + } + if (scriptOrigins.topLevel === 'remote' && + scriptOrigins.descendant === 'same') { + url = new URL( + get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/' + + 'import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js'); + return url; + } + if (scriptOrigins.topLevel === 'remote' && + scriptOrigins.descendant === 'remote') { + return new URL( + get_host_info().HTTPS_REMOTE_ORIGIN + + '/worklets/resources/import-referrer-checker-worklet-script.sub.js'); + } + assert_unreached('scriptOrigins have an invalid origin combination.'); +} + +function isDestinationCrossOrigin(fetchType, scriptOrigins) { + if (fetchType === 'top-level') + return scriptOrigins.topLevel === 'remote'; + + // Compute a descendant's cross-origin-ness relative to the top-level script. + if (fetchType === 'descendant') + return scriptOrigins.descendant !== scriptOrigins.topLevel; + assert_unreached('fetchType has an invalid value.'); +} + +function createExpectedReferrer( + importerURL, fetchType, referrerPolicy, scriptOrigins) { + if (referrerPolicy === 'no-referrer') + return ""; + if (referrerPolicy === 'same-origin') { + if (isDestinationCrossOrigin(fetchType, scriptOrigins)) + return ""; + // Delete query params to make it easier to match with an actual referrer in + // the referrer-checker.py. + const expectedReferrer = new URL(importerURL); + for (var key of expectedReferrer.searchParams.keys()) + expectedReferrer.searchParams.delete(key); + return expectedReferrer; + } + if (referrerPolicy === 'origin') + return (new URL(importerURL)).origin + '/'; + assert_unreached('referrerPolicy has an invalid value.'); +} + +window.onmessage = e => { + const workletType = e.data.workletType; + const fetchType = e.data.fetchType; + const referrerPolicy = e.data.referrerPolicy; + const scriptOrigins = e.data.scriptOrigins; + + let scriptURL; + let expectedReferrer; + if (fetchType === 'top-level') { + scriptURL = createScriptURLForTopLevel(scriptOrigins.topLevel); + expectedReferrer = createExpectedReferrer( + location.href, fetchType, referrerPolicy, scriptOrigins); + } else if (fetchType === 'descendant') { + scriptURL = createScriptURLForDecendant(scriptOrigins); + expectedReferrer = createExpectedReferrer( + scriptURL, fetchType, referrerPolicy, scriptOrigins); + } else { + assert_unreached('fetchType should be \'top-level\' or \'descendant\''); + } + + const params = new URLSearchParams; + params.append('requestor_origin', document.location.origin); + params.append('referrer_policy', referrerPolicy); + params.append('expected_referrer', expectedReferrer); + + get_worklet(workletType).addModule(scriptURL + '?' + params) + .then(() => window.opener.postMessage('RESOLVED', '*')) + .catch(e => window.opener.postMessage(e.message, '*')); +}; + +window.opener.postMessage('LOADED', '*'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js b/testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js new file mode 100644 index 0000000000..1298a626e4 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js @@ -0,0 +1,108 @@ +function openWindow(t, url) { + return new Promise(resolve => { + const win = window.open(url, '_blank'); + t.add_cleanup(() => win.close()); + window.onmessage = e => { + assert_equals(e.data, 'LOADED'); + resolve(win); + }; + }); +} + +// Runs a series of tests related to service worker interception for a worklet. +// +// Usage: +// runServiceWorkerInterceptionTests("paint"); +function runServiceWorkerInterceptionTests(worklet_type) { + const worklet = get_worklet(worklet_type); + + // Tests that a worklet should be served by the owner document's service + // worker. + // + // [Current document] registers a service worker for Window's URL. + // --(open)--> [Window] should be controlled by the service worker. + // --(addModule)--> [Worklet] should be served by the service worker. + promise_test(async t => { + const kWindowURL = 'resources/addmodule-window.html'; + const kServiceWorkerScriptURL = 'resources/service-worker.js'; + // This doesn't contain the 'resources/' prefix because this will be + // imported from a html file under resources/. + const kWorkletScriptURL = 'non-existent-worklet-script.js'; + + const registration = await service_worker_unregister_and_register( + t, kServiceWorkerScriptURL, kWindowURL); + t.add_cleanup(() => registration.unregister()); + await wait_for_state(t, registration.installing, 'activated'); + + const win = await openWindow(t, kWindowURL); + assert_not_equals(win.navigator.serviceWorker.controller, null, + 'The document should be controlled.'); + + // The worklet script on kWorkletScriptURL doesn't exist but the service + // worker serves it, so the addModule() should succeed. + win.postMessage({ type: worklet_type, script_url: kWorkletScriptURL }, '*'); + const msgEvent = await new Promise(resolve => window.onmessage = resolve); + assert_equals(msgEvent.data, 'RESOLVED'); + }, 'addModule() on a controlled document should be intercepted by a ' + + 'service worker.'); + + // Tests that a worklet should not be served by a service worker other than + // the owner document's service worker. + // + // [Current document] registers a service worker for Worklet's URL. + // --(open)--> [Window] should not be controlled by the service worker. + // --(addModule)--> [Worklet] should not be served by the service worker. + promise_test(async t => { + const kWindowURL = 'resources/addmodule-window.html'; + const kServiceWorkerScriptURL = 'resources/service-worker.js'; + // This doesn't contain the 'resources/' prefix because this will be + // imported from a html file under resources/. + const kWorkletScriptURL = 'non-existent-worklet-script.js'; + + const registration = await service_worker_unregister_and_register( + t, kServiceWorkerScriptURL, 'resources/' + kWorkletScriptURL); + t.add_cleanup(() => registration.unregister()); + await wait_for_state(t, registration.installing, 'activated'); + + const win = await openWindow(t, kWindowURL); + assert_equals(win.navigator.serviceWorker.controller, null, + 'The document should not be controlled.'); + + // The worklet script on kWorkletScriptURL doesn't exist and the service + // worker doesn't serve it, so the addModule() should fail. + win.postMessage({ type: worklet_type, script_url: kWorkletScriptURL }, '*'); + const msgEvent = await new Promise(resolve => window.onmessage = resolve); + assert_equals(msgEvent.data, 'REJECTED'); + }, 'addModule() on a non-controlled document should not be intercepted by ' + + 'a service worker even if the script is under the service worker scope.'); + + // Tests that static import should be served by the owner document's service + // worker. + // + // [Current document] registers a service worker for Window's URL. + // --(open)--> [Window] should be controlled by the service worker. + // --(addModule)--> [Worklet] should be served by the service worker. + // --(static import)--> [Script] should be served by the service worker. + promise_test(async t => { + const kWindowURL = 'resources/addmodule-window.html'; + const kServiceWorkerScriptURL = 'resources/service-worker.js'; + // This doesn't contain the 'resources/' prefix because this will be + // imported from a html file under resources/. + const kWorkletScriptURL = 'import-non-existent-worklet-script.js'; + + const registration = await service_worker_unregister_and_register( + t, kServiceWorkerScriptURL, kWindowURL); + t.add_cleanup(() => registration.unregister()); + await wait_for_state(t, registration.installing, 'activated'); + + const win = await openWindow(t, kWindowURL); + assert_not_equals(win.navigator.serviceWorker.controller, null, + 'The document should be controlled.'); + + // A script statically imported by the worklet doesn't exist but the service + // worker serves it, so the addModule() should succeed. + win.postMessage({ type: worklet_type, script_url: kWorkletScriptURL }, '*'); + const msgEvent = await new Promise(resolve => window.onmessage = resolve); + assert_equals(msgEvent.data, 'RESOLVED'); + }, 'Static import should be intercepted by a service worker.'); +} diff --git a/testing/web-platform/tests/worklets/resources/service-worker.js b/testing/web-platform/tests/worklets/resources/service-worker.js new file mode 100644 index 0000000000..67e6754cf0 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/service-worker.js @@ -0,0 +1,4 @@ +self.addEventListener('fetch', e => { + if (e.request.url.indexOf('/non-existent-worklet-script.js') != -1) + e.respondWith(fetch('empty-worklet-script.js')); +}); diff --git a/testing/web-platform/tests/worklets/resources/set-cookie.py b/testing/web-platform/tests/worklets/resources/set-cookie.py new file mode 100644 index 0000000000..a36a69cce6 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/set-cookie.py @@ -0,0 +1,15 @@ +def main(request, response): + name = request.GET.first(b"name") + value = request.GET.first(b"value") + source_origin = request.headers.get(b"origin") + if source_origin is None: + # Same origin GET won't include origin header + source_origin = "%s://%s" % (request.url_parts.scheme, + request.url_parts.netloc) + if request.url_parts.port: + source_origin += ":%s" % request.url_parts.port + + response_headers = [(b"Set-Cookie", name + b"=" + value), + (b"Access-Control-Allow-Origin", source_origin), + (b"Access-Control-Allow-Credentials", b"true")] + return (200, response_headers, u"") diff --git a/testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js b/testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js new file mode 100644 index 0000000000..471697a43b --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js @@ -0,0 +1 @@ +;-) diff --git a/testing/web-platform/tests/worklets/resources/throwing-worklet-script.js b/testing/web-platform/tests/worklets/resources/throwing-worklet-script.js new file mode 100644 index 0000000000..6417d6c5f7 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/throwing-worklet-script.js @@ -0,0 +1 @@ +throw Error(); diff --git a/testing/web-platform/tests/worklets/resources/worklet-test-utils.js b/testing/web-platform/tests/worklets/resources/worklet-test-utils.js new file mode 100644 index 0000000000..797edc9e56 --- /dev/null +++ b/testing/web-platform/tests/worklets/resources/worklet-test-utils.js @@ -0,0 +1,12 @@ +// Returns a reference to a worklet object corresponding to a given type. +function get_worklet(type) { + if (type == 'animation') + return CSS.animationWorklet; + if (type == 'layout') + return CSS.layoutWorklet; + if (type == 'paint') + return CSS.paintWorklet; + if (type == 'audio') + return new OfflineAudioContext(2,44100*40,44100).audioWorklet; + return undefined; +} |