summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/content-security-policy/securitypolicyviolation
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/content-security-policy/securitypolicyviolation')
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html20
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html19
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html53
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html239
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js18
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html31
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers2
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html25
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html22
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html27
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html23
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html80
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html94
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html28
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html27
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html28
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html28
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html26
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html26
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html102
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html39
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html39
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js57
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers5
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js5
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html169
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html100
-rw-r--r--testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers2
28 files changed, 1334 insertions, 0 deletions
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html
new file mode 100644
index 0000000000..ddd5068df1
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ async_test(t => {
+ var watcher = new EventWatcher(t, document, 'securitypolicyviolation');
+ watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "eval");
+ assert_equals(e.lineNumber, 15);
+ assert_equals(e.columnNumber, 12);
+ }));
+
+ try {
+ eval("assert_unreached('eval() should be blocked.");
+ } catch (e) {
+ assert_equals(e.name, 'EvalError');
+ }
+ }, "Eval violations have a blockedURI of 'eval'");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html
new file mode 100644
index 0000000000..7cced9ef69
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<script nonce="abc">
+ async_test(t => {
+ var watcher = new EventWatcher(t, document, 'securitypolicyviolation');
+ watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.lineNumber, 15);
+ assert_equals(e.columnNumber, 8);
+ }));
+ }, "Inline violations have a blockedURI of 'inline'");
+</script>
+<script>
+ test(t => {
+ assert_unreached();
+ }, "Blocked script shouldn't execute.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html
new file mode 100644
index 0000000000..88bf4ae599
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-ws-wss-scheme.html
@@ -0,0 +1,53 @@
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+
+const info = get_host_info();
+
+const nextCSPViolation = (test) => {
+ return new Promise((resolve, reject) => {
+ document.addEventListener("securitypolicyviolation", resolve, {once: true});
+ test.step_timeout(() => reject("timeout"), 3000);
+ });
+};
+
+const redirector = get_host_info().HTTP_REMOTE_ORIGIN.replace("http", "wss") +
+ "/common/redirect.py";
+
+promise_setup(async () => {
+ const meta = document.createElement('meta');
+ meta.httpEquiv = "Content-Security-Policy";
+ meta.content = "connect-src " + redirector;
+ document.getElementsByTagName('head')[0].appendChild(meta);
+}, "Install <meta> CSP");
+
+promise_test(async test => {
+ const url = get_host_info().HTTP_ORIGIN.replace("http", "ws") + "/path";
+ const violation = nextCSPViolation(test);
+ try { new WebSocket(url); } catch (e) {}
+ assert_equals((await violation).blockedURI, url);
+}, "ws");
+
+promise_test(async test => {
+ const url = get_host_info().HTTP_ORIGIN.replace("http", "wss") + "/path";
+ const violation = nextCSPViolation(test);
+ try { new WebSocket(url); } catch (e) {}
+ assert_equals((await violation).blockedURI, url);
+}, "wss");
+
+promise_test(async test => {
+ const url = get_host_info().HTTP_REMOTE_ORIGIN.replace("http", "wss") + "/path";
+ const violation = nextCSPViolation(test);
+ try { new WebSocket(url); } catch (e) {}
+ assert_equals((await violation).blockedURI, url);
+}, "cross-origin");
+
+promise_test(async test => {
+ const url = get_host_info().HTTP_ORIGIN.replace("http", "wss") + "/path";
+ const violation = nextCSPViolation(test);
+ try {new WebSocket(redirector + "?location=" + url); } catch (e) {}
+ assert_equals((await violation).blockedURI, url);
+}, "redirect");
+
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html
new file mode 100644
index 0000000000..1a090d8e2c
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/constructor-required-fields.html
@@ -0,0 +1,239 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ // basic tests.
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent(); });
+ }, "SecurityPolicyViolationEvent constructor should throw with no parameters");
+
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor works with an init dict");
+
+ // missing required members
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ // documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ })});
+ }, "SecurityPolicyViolationEvent constructor requires documentURI");
+
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ // violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ })});
+ }, "SecurityPolicyViolationEvent constructor requires violatedDirective");
+
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ // effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ })});
+ }, "SecurityPolicyViolationEvent constructor requires effectiveDirective");
+
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ // originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ })});
+ }, "SecurityPolicyViolationEvent constructor requires originalPolicy");
+
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ // disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ })});
+ }, "SecurityPolicyViolationEvent constructor requires disposition");
+
+ test(function() {
+ assert_throws_js(TypeError,
+ function() { new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ // statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ })});
+ }, "SecurityPolicyViolationEvent constructor requires statusCode");
+
+ // missing optional members
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ // referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor does not require referrer");
+
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ // blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor does not require blockedURI");
+
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ // sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor does not require sourceFile");
+
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ // sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor does not require sample");
+
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ // lineNumber: 1,
+ columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor does not require lineNumber");
+
+ test(function() {
+ assert_not_equals(new SecurityPolicyViolationEvent("securitypolicyviolation", {
+ documentURI: "http://example.com",
+ referrer: "http://example.com",
+ blockedURI: "http://example.com",
+ violatedDirective: "default-src",
+ effectiveDirective: "default-src",
+ originalPolicy: "default-src 'none'",
+ sourceFile: "example.js",
+ sample: "<script>alert('1');</scr" + "ipt>",
+ disposition: "enforce",
+ statusCode: 200,
+ lineNumber: 1,
+ // columnNumber: 1,
+ }), undefined);
+ }, "SecurityPolicyViolationEvent constructor does not require columnNumber");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js
new file mode 100644
index 0000000000..25efd0d4e1
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/idlharness.window.js
@@ -0,0 +1,18 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+// https://w3c.github.io/webappsec-csp/
+
+'use strict';
+
+idl_test(
+ ['CSP'],
+ ['dom', 'reporting'],
+ idl_array => {
+ idl_array.add_objects({
+ SecurityPolicyViolationEvent: [
+ 'new SecurityPolicyViolationEvent("securitypolicyviolation")'
+ ]
+ })
+ }
+);
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html
new file mode 100644
index 0000000000..c63206db46
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<body></body>
+<script>
+ function waitForViolation(el, t, policy, blockedURI) {
+ return new Promise(resolve => {
+ el.addEventListener('securitypolicyviolation', e => {
+ if (e.originalPolicy == policy && e.blockedURI == blockedURI)
+ resolve(e);
+ else
+ t.unreached_func("Unexpected violation event for " + e.blockedURI)();
+ });
+ });
+ }
+
+ async_test(t => {
+ var i = document.createElement("img");
+ var redirect = generateCrossOriginRedirectImage();
+ i.src = redirect.url;
+
+ // Report-only policy should trigger a violation on the redirected request.
+ waitForViolation(window, t, "img-src https:", new URL(redirect.url, window.location).href).then(t.step_func(e => {
+ t.done();
+ }));
+
+ document.body.appendChild(i);
+ }, "Image that redirects to http:// URL prohibited by Report-Only must generate a violation report, even with upgrade-insecure-requests");
+</script>
+</html>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers
new file mode 100644
index 0000000000..57207bbd23
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers
@@ -0,0 +1,2 @@
+Content-Security-Policy-Report-Only: img-src https:
+Content-Security-Policy: upgrade-insecure-requests
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html
new file mode 100644
index 0000000000..9bffad09b3
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta http-equiv="content-security-policy" content="img-src 'self'">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body></body>
+<script>
+ async_test(t => {
+ const i = document.createElement("img");
+
+ const target = "http://{{hosts[alt][]}}:{{ports[http][0]}}/content-security-policy/support/fail.png";
+ const url = window.origin + "/common/redirect.py?location=" + encodeURIComponent(target);
+
+ window.addEventListener('securitypolicyviolation', t.step_func_done((e) => {
+ assert_equals(e.blockedURI, url);
+ }));
+
+ i.onload = t.step_func(() => {
+ assert_unreached("Img should be blocked.");
+ });
+ i.src = url;
+
+ document.body.appendChild(i);
+ }, "The blocked URI in the security policy violation event should be the original URI before redirects.");
+</script>
+</html>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html
new file mode 100644
index 0000000000..0912ec2ad9
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!--
+ Set a policy in the document to ensure that the block is triggering
+ in the worker and not in the document.
+-->
+<meta http-equiv="content-security-policy" content="connect-src 'self'">
+
+<script>
+ var w = new Worker("./support/inside-worker.sub.js");
+
+ // Forward 'securitypolicyviolation' events from the document into the
+ // worker (we shouldn't actually see any, so the worker will assert that
+ // none are fired).
+ document.addEventListener('securitypolicyviolation', _ => {
+ w.postMessage("SecurityPolicyViolation from Document");
+ });
+
+ fetch_tests_from_worker(w);
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html
new file mode 100644
index 0000000000..e0e59c8b8e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-service-worker.https.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!--
+ Set a policy in the document to ensure that the block is triggering
+ in the worker and not in the document.
+-->
+<meta http-equiv="content-security-policy" content="connect-src 'self'">
+
+<script>
+ navigator.serviceWorker.register("./support/inside-worker.sub.js", { scope: "./support/" })
+ .then(r => {
+ var sw = r.active || r.installing || r.waiting;
+ add_completion_callback(_ => r.unregister());
+
+ // Forward 'securitypolicyviolation' events from the document into the
+ // worker (we shouldn't actually see any, so the worker will assert that
+ // none are fired.
+ document.addEventListener('securitypolicyviolation', _ => {
+ sw.postMessage("SecurityPolicyViolation from Document");
+ });
+
+ fetch_tests_from_worker(sw);
+ });
+</script>
+
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html
new file mode 100644
index 0000000000..4fddf12a3c
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/inside-shared-worker.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!--
+ Set a policy in the document to ensure that the block is triggering
+ in the worker and not in the document.
+-->
+<meta http-equiv="content-security-policy" content="connect-src 'self'">
+
+<script>
+ var w = new SharedWorker("./support/inside-worker.sub.js");
+
+ // Forward 'securitypolicyviolation' events from the document into the
+ // worker (we shouldn't actually see any, so the worker will assert that
+ // none are fired.
+ document.addEventListener('securitypolicyviolation', _ => {
+ w.port.postMessage("SecurityPolicyViolation from Document");
+ });
+
+ fetch_tests_from_worker(w);
+</script>
+
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html
new file mode 100644
index 0000000000..3e25ce299c
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample-no-opt-in.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'; style-src 'self'; img-src 'none'">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<body>
+<script nonce="abc">
+ function waitForViolation(el) {
+ return new Promise(resolve => {
+ el.addEventListener('securitypolicyviolation', e => resolve(e));
+ });
+ }
+
+ async_test(t => {
+ var s = document.createElement('script');
+ s.innerText = "assert_unreached('inline script block')";
+
+ waitForViolation(s)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "");
+ }));
+
+ document.head.append(s);
+ }, "Inline script should not have a sample.");
+
+ async_test(t => {
+ var a = document.createElement("a");
+ a.setAttribute("onclick", "assert_unreached('inline event handler')");
+
+ waitForViolation(a)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "");
+ }));
+
+ document.body.append(a);
+ a.click();
+ }, "Inline event handlers should not have a sample.");
+
+ async_test(t => {
+ var i = document.createElement("iframe");
+ i.src = "javascript:'inline url'";
+
+ waitForViolation(i)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "");
+ }));
+
+ document.body.append(i);
+ }, "JavaScript URLs in iframes should not have a sample.");
+
+ async_test(t => {
+ var violations = 0;
+ document.addEventListener('securitypolicyviolation', t.step_func(e => {
+ if (e.blockedURI != "eval")
+ return;
+
+ assert_equals(e.sample, "");
+ violations++
+ if (violations == 3)
+ t.done();
+ }));
+ try {
+ eval("assert_unreached('eval')");
+ assert_unreached('eval');
+ } catch (e) {
+ }
+ try {
+ setInterval("assert_unreached('interval')", 1000);
+ assert_unreached('interval');
+ } catch (e) {
+ }
+ try {
+ setTimeout("assert_unreached('timeout')", 1000);
+ assert_unreached('timeout');
+ } catch (e) {
+ }
+ }, "eval()-alikes should not have a sample.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html
new file mode 100644
index 0000000000..b38055bf7b
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/script-sample.html
@@ -0,0 +1,94 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc' 'report-sample'; style-src 'self'; img-src 'none'">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<body>
+<script nonce="abc">
+ function waitForViolation(el) {
+ return new Promise(resolve => {
+ el.addEventListener('securitypolicyviolation', e => resolve(e));
+ });
+ }
+
+ async_test(t => {
+ var s = document.createElement('script');
+ s.innerText = "assert_unreached('inline script block')";
+
+ waitForViolation(s)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "assert_unreached('inline script block')");
+ }));
+
+ document.head.append(s);
+ }, "Inline script should have a sample.");
+
+ async_test(t => {
+ var a = document.createElement("a");
+ a.setAttribute("onclick", "assert_unreached('inline event handler')");
+
+ waitForViolation(a)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "assert_unreached('inline event handler')");
+ }));
+
+ document.body.append(a);
+ a.click();
+ }, "Inline event handlers should have a sample.");
+
+ async_test(t => {
+ var i = document.createElement("iframe");
+ i.src = "javascript:'inline url'";
+
+ waitForViolation(i)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "javascript:'inline url'");
+ }));
+
+ document.body.append(i);
+ }, "JavaScript URLs in iframes should have a sample.");
+
+ async_test(t => {
+ document.addEventListener('securitypolicyviolation', t.step_func(e => {
+ if (e.blockedURI == "eval" &&
+ e.sample == "assert_unreached('eval')") {
+ t.done();
+ }
+ }));
+ try {
+ eval("assert_unreached('eval')");
+ assert_unreached('eval');
+ } catch (e) {
+ }
+ }, "eval() should have a sample.");
+
+ async_test(t => {
+ document.addEventListener('securitypolicyviolation', t.step_func(e => {
+ if (e.blockedURI == "eval" &&
+ e.sample == "assert_unreached('interval')") {
+ t.done();
+ }
+ }));
+ try {
+ setInterval("assert_unreached('interval')", 1000);
+ assert_unreached('interval');
+ } catch (e) {
+ }
+ }, "setInterval() should have a sample.");
+
+ async_test(t => {
+ document.addEventListener('securitypolicyviolation', t.step_func(e => {
+ if (e.blockedURI == "eval" &&
+ e.sample == "assert_unreached('timeout')") {
+ t.done();
+ }
+ }));
+ try {
+ setTimeout("assert_unreached('timeout')", 1000);
+ assert_unreached('timeout');
+ } catch (e) {
+ }
+ }, "setTimeout() should have a sample.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html
new file mode 100644
index 0000000000..318fae4634
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/content-security-policy/support/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+<body>
+<script>
+ async_test(t => {
+ waitUntilEvent(window, "securitypolicyviolation")
+ .then(t.step_func_done(e => {
+ assert_equals(e.documentURI, document.location.toString());
+ assert_equals(e.referrer, document.referrer);
+ assert_equals(e.blockedURI, "http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/fail.png");
+ assert_equals(e.violatedDirective, "img-src");
+ assert_equals(e.effectiveDirective, "img-src");
+ assert_equals(e.originalPolicy, "img-src \'none\'");
+ assert_equals(e.disposition, "enforce");
+ assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js");
+ assert_equals(e.lineNumber, 2);
+ assert_equals(e.columnNumber, 0);
+ assert_equals(e.statusCode, 200);
+ }));
+
+ var s = document.createElement("script");
+ s.src = "{{location[scheme]}}://{{domains[www2]}}:{{location[port]}}/content-security-policy/support/inject-image.sub.js";
+ document.body.appendChild(s);
+ }, "Non-redirected cross-origin URLs are not stripped.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html
new file mode 100644
index 0000000000..44ca8d50e4
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/content-security-policy/support/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+<body>
+<script>
+ async_test(t => {
+ waitUntilEvent(window, "securitypolicyviolation")
+ .then(t.step_func_done(e => {
+ assert_equals(e.documentURI, document.location.toString());
+ assert_equals(e.referrer, document.referrer);
+ assert_equals(e.blockedURI, "{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/fail.png");
+ assert_equals(e.violatedDirective, "img-src");
+ assert_equals(e.effectiveDirective, "img-src");
+ assert_equals(e.originalPolicy, "img-src \'none\'");
+ assert_equals(e.disposition, "enforce");
+ assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html");
+ assert_equals(e.lineNumber, 25);
+ assert_equals(e.columnNumber, 4);
+ assert_equals(e.statusCode, 200);
+ }));
+
+ var i = document.createElement("img");
+ i.src = "{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/fail.png";
+ }, "Non-redirected cross-origin URLs are not stripped.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html
new file mode 100644
index 0000000000..c09643c20e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/content-security-policy/support/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+<body>
+<script>
+ async_test(t => {
+ waitUntilEvent(window, "securitypolicyviolation")
+ .then(t.step_func_done(e => {
+ assert_equals(e.documentURI, document.location.toString());
+ assert_equals(e.referrer, document.referrer);
+ assert_equals(e.blockedURI, "http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/fail.png");
+ assert_equals(e.violatedDirective, "img-src");
+ assert_equals(e.effectiveDirective, "img-src");
+ assert_equals(e.originalPolicy, "img-src \'none\'");
+ assert_equals(e.disposition, "enforce");
+ assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js");
+ assert_equals(e.lineNumber, 2);
+ assert_equals(e.columnNumber, 0);
+ assert_equals(e.statusCode, 200);
+ }));
+
+ var s = document.createElement("script");
+ s.src = "/content-security-policy/support/inject-image.sub.js";
+ document.body.appendChild(s);
+ }, "Non-redirected cross-origin URLs are not stripped.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html
new file mode 100644
index 0000000000..541c139533
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/content-security-policy/support/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+<body>
+<script>
+ async_test(t => {
+ waitUntilEvent(window, "securitypolicyviolation")
+ .then(t.step_func_done(e => {
+ assert_equals(e.documentURI, document.location.toString());
+ assert_equals(e.referrer, document.referrer);
+ assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/content-security-policy/support/fail.png");
+ assert_equals(e.violatedDirective, "img-src");
+ assert_equals(e.effectiveDirective, "img-src");
+ assert_equals(e.originalPolicy, "img-src \'none\'");
+ assert_equals(e.disposition, "enforce");
+ assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html");
+ assert_equals(e.lineNumber, 25);
+ assert_equals(e.columnNumber, 4);
+ assert_equals(e.statusCode, 200);
+ }));
+
+ var i = document.createElement("img");
+ i.src = "/content-security-policy/support/fail.png";
+ }, "Non-redirected same-origin URLs are not stripped.");
+</script>
+
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html
new file mode 100644
index 0000000000..ad3d9f3600
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc' blob:">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<script nonce="abc">
+ async_test(t => {
+ var watcher = new EventWatcher(t, document, 'securitypolicyviolation');
+ watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "eval");
+ assert_equals(e.sourceFile, "blob");
+ assert_equals(e.lineNumber, 3);
+ assert_equals(e.columnNumber, 16);
+ }));
+
+ var scriptText = `
+ try {
+ eval("assert_unreached('no eval')");
+ } catch (e) {
+ assert_equals(e.name, 'EvalError');
+ }
+ `;
+ var s = document.createElement("script");
+ s.src = URL.createObjectURL(new Blob([scriptText], {type: "text/javascript"}));
+ document.head.append(s);
+ }, "Violations from data:-URL scripts have a sourceFile of 'blob'");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html
new file mode 100644
index 0000000000..06511571d4
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc' data:">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<script nonce="abc">
+ async_test(t => {
+ var watcher = new EventWatcher(t, document, 'securitypolicyviolation');
+ watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "eval");
+ assert_equals(e.sourceFile, "data");
+ assert_equals(e.lineNumber, 3);
+ assert_equals(e.columnNumber, 16);
+ }));
+
+ var scriptText = `
+ try {
+ eval("assert_unreached('no eval')");
+ } catch (e) {
+ assert_equals(e.name, 'EvalError');
+ }
+ `;
+ var s = document.createElement("script");
+ s.src = "data:text/javascript," + encodeURIComponent(scriptText);
+ document.head.append(s);
+ }, "Violations from data:-URL scripts have a sourceFile of 'data'");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html
new file mode 100644
index 0000000000..354b8dfd20
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/source-file.html
@@ -0,0 +1,102 @@
+<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const policy = trustedTypes.createPolicy("sample", {createScript: x => x});
+
+// Check CSP violated by a script originating from |input| returns a CSP
+// violation whose sourceFile is |output|.
+const testSourceFile = (description, input, output) => {
+ promise_test(async test => {
+ // Listen for TrustedType violation.
+ const violation = new Promise(resolve => {
+ document.addEventListener("securitypolicyviolation", e => {
+ resolve(e);
+ }, {once: true});
+ });
+
+ // A trusted script using a customized sourceURL. The script's execution
+ // itself will trigger a TrustedType violation.
+ const trusted_script = policy.createScript(`
+ eval('');
+ //# sourceURL=${input}
+ `)
+ try {
+ eval(trusted_script);
+ assert_unreached();
+ } catch (e) {}
+
+ assert_equals((await violation).sourceFile, output);
+ }, description);
+};
+
+testSourceFile("Basic HTTPS URL",
+ "http://dummy.test/script1.js",
+ "http://dummy.test/script1.js");
+
+testSourceFile("Basic HTTP URL",
+ "https://dummy.test/script1.js",
+ "https://dummy.test/script1.js");
+
+testSourceFile("Basic WSS URL",
+ "wss://dummy.test/script1.js",
+ "wss://dummy.test/script1.js");
+
+testSourceFile("Basic WS URL",
+ "ws://dummy.test/script1.js",
+ "ws://dummy.test/script1.js");
+
+testSourceFile("Fragment",
+ "https://dummy.test/script1.js#frag",
+ "https://dummy.test/script1.js");
+
+testSourceFile("Query",
+ "https://dummy.test/script1.js?query",
+ "https://dummy.test/script1.js");
+
+testSourceFile("Port",
+ "https://dummy.test:8080/script1.js",
+ "https://dummy.test:8080/script1.js");
+
+testSourceFile("User:password",
+ "https://user:password@dummy.test/script1.js",
+ "https://dummy.test/script1.js");
+
+testSourceFile("User",
+ "https://user@dummy.test/script1.js",
+ "https://dummy.test/script1.js");
+
+testSourceFile("Invalid URL",
+ "script2.js",
+ "");
+
+testSourceFile("file:",
+ "file:///temp/script3.js",
+ "file");
+
+testSourceFile("Custom protocol",
+ "webpack://node_modules/sample/script4.js",
+ "webpack");
+
+testSourceFile("about:blank",
+ "about:blank",
+ "about");
+
+testSourceFile("about:custom",
+ "about:custom",
+ "about");
+
+testSourceFile("data:",
+ "data:text/html;charset=utf8,<html></html>",
+ "data");
+
+testSourceFile("blob:",
+ "blob:http://test.test/012345-6789-abcd-efab-0123456789",
+ "blob");
+
+testSourceFile("javascript:",
+ "javascript:void(0)",
+ "javascript");
+
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html
new file mode 100644
index 0000000000..1fb0bf0c09
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample-no-opt-in.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="style-src 'nonce-abc'">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<body>
+<script nonce="abc">
+ function waitForViolation(el) {
+ return new Promise(resolve => {
+ el.addEventListener('securitypolicyviolation', e => resolve(e));
+ });
+ }
+
+ async_test(t => {
+ var s = document.createElement('style');
+ s.innerText = "p { omg: yay !important; }";
+
+ waitForViolation(s)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "");
+ }));
+
+ document.head.append(s);
+ }, "Inline style blocks should not have a sample.");
+
+ async_test(t => {
+ var p = document.createElement('p');
+ p.setAttribute("style", "omg: yay !important;");
+ p.innerText = "Yay!";
+
+ waitForViolation(p)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "");
+ }));
+
+ document.head.append(p);
+ }, "Inline style attributes should not have a sample.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html
new file mode 100644
index 0000000000..7eed52aac7
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/style-sample.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="style-src 'nonce-abc' 'report-sample'">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<body>
+<script nonce="abc">
+ function waitForViolation(el) {
+ return new Promise(resolve => {
+ el.addEventListener('securitypolicyviolation', e => resolve(e));
+ });
+ }
+
+ async_test(t => {
+ var s = document.createElement('style');
+ s.innerText = "p { omg: yay !important; }";
+
+ waitForViolation(s)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "p { omg: yay !important; }");
+ }));
+
+ document.head.append(s);
+ }, "Inline style blocks should have a sample.");
+
+ async_test(t => {
+ var p = document.createElement('p');
+ p.setAttribute("style", "omg: yay !important;");
+ p.innerText = "Yay!";
+
+ waitForViolation(p)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.sample, "omg: yay !important;");
+ }));
+
+ document.head.append(p);
+ }, "Inline style attributes should have a sample.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js
new file mode 100644
index 0000000000..58bd02fd9e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js
@@ -0,0 +1,57 @@
+importScripts("{{location[scheme]}}://{{host}}:{{location[port]}}/resources/testharness.js");
+importScripts("{{location[scheme]}}://{{host}}:{{location[port]}}/content-security-policy/support/testharness-helper.js");
+
+var cspEventFiredInDocument = false;
+// ServiceWorker and Worker
+self.addEventListener("message", e => {
+ if (e.data == "SecurityPolicyViolation from Document")
+ cspEventFiredInDocument = true;
+});
+// SharedWorker
+self.addEventListener("connect", c => {
+ c.ports[0].addEventListener("message", m => {
+ if (m.data == "SecurityPolicyViolation from Document")
+ cspEventFiredInDocument = true;
+ });
+});
+
+async_test(t => {
+ var url = "{{location[scheme]}}://{{host}}:{{location[port]}}/content-security-policy/support/resource.py";
+ assert_no_csp_event_for_url(t, url);
+
+ fetch(url)
+ .catch(t.unreached_func("Fetch should succeed."))
+ .then(t.step_func_done(r => {
+ assert_equals(r.status, 200);
+ assert_false(cspEventFiredInDocument);
+ }));
+}, "No SecurityPolicyViolation event fired for successful load.");
+
+async_test(t => {
+ var url = "{{location[scheme]}}://{{domains[www2]}}:{{location[port]}}/content-security-policy/support/resource.py";
+ waitUntilCSPEventForURL(t, url)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, url);
+ assert_false(cspEventFiredInDocument);
+ }));
+
+ fetch(url)
+ .then(t.unreached_func("Fetch should not succeed."))
+ .catch(t.step_func(e => assert_true(e instanceof TypeError)));
+}, "SecurityPolicyViolation event fired on global.");
+
+async_test(t => {
+ var url = "{{location[scheme]}}://{{host}}:{{location[port]}}/common/redirect.py?location={{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/ping.js";
+ waitUntilCSPEventForURL(t, url)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, url);
+ assert_false(cspEventFiredInDocument);
+ }));
+
+ fetch(url)
+ .then(t.unreached_func("Fetch should not succeed."))
+ .catch(t.step_func(e => assert_true(e instanceof TypeError)));
+}, "SecurityPolicyViolation event fired on global with the correct blockedURI.");
+
+// Worker tests need an explicit `done()`.
+done();
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers
new file mode 100644
index 0000000000..50ff4a5b94
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers
@@ -0,0 +1,5 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Content-Security-Policy: connect-src 'self'
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js
new file mode 100644
index 0000000000..816b88fc6e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/support/testharness-helper.sub.js
@@ -0,0 +1,5 @@
+function generateCrossOriginRedirectImage() {
+ var target = "http://{{host}}:{{ports[https][0]}}/content-security-policy/support/pass.png";
+ var url = "/common/redirect.py?location=" + encodeURIComponent(target);
+ return { url: url, target: target }
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
new file mode 100644
index 0000000000..b21273ca55
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
@@ -0,0 +1,169 @@
+<!doctype html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'; style-src 'self'">
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<script nonce="abc">
+ var unexecuted_test = async_test("These tests should not fail.");
+
+ async_test(t => {
+ var watcher = new EventWatcher(t, document, ['securitypolicyviolation'])
+ watcher.wait_for('securitypolicyviolation')
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, document.querySelector('#block1'));
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, document.querySelector('#block2'));
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, document.querySelector('#block3'));
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, document.querySelector('#block4'));
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, document.querySelector('#block5'));
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.lineNumber, 118);
+ assert_in_array(e.columnNumber, [4, 6]);
+ assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.");
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.lineNumber, 131);
+ assert_in_array(e.columnNumber, [4, 59]);
+ assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.");
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.lineNumber, 139);
+ assert_in_array(e.columnNumber, [4, 6]);
+ assert_equals(e.target, document, "Inline event handlers for disconnected elements target the document.");
+ return watcher.wait_for('securitypolicyviolation');
+ }))
+ .then(t.step_func(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.lineNumber, 0);
+ assert_equals(e.columnNumber, 0);
+ assert_equals(e.target, document, "Inline event handlers for elements disconnected after triggering target the document.");
+ }))
+ .then(t.step_func_done(_ => {
+ unexecuted_test.done();
+ }));
+ }, "Inline violations target the right element.");
+
+</script>
+<!-- Inline block with no nonce. -->
+<script id="block1">
+ unexecuted_test.assert_unreached("This code block should not execute.");
+</script>
+
+<!-- Inline event handler. -->
+<a id="block2" onclick="void(0)">Click me!</a>
+<script nonce='abc'>document.querySelector('#block2').click();</script>
+
+<!-- Style block. -->
+<style id="block3">
+ p { color: red !important; }
+</style>
+
+<!-- Inline event handler inside Shadow DOM -->
+<div id="block4"></div>
+<script nonce='abc'>
+ async_test(t => {
+ var shadow = document.querySelector('#block4').attachShadow({"mode":"closed"});
+ shadow.innerHTML = "<a id='block4a' onclick='void(0)'>Click!</a>";
+ var a = shadow.querySelector('#block4a');
+ a.addEventListener('securitypolicyviolation', t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, a);
+ }));
+ a.click();
+ }, "Correct targeting inside shadow tree (inline handler).");
+</script>
+
+<!-- Inline event handler inside Shadow DOM -->
+<div id="block5"></div>
+<script nonce='abc'>
+ async_test(t => {
+ var shadow = document.querySelector('#block5').attachShadow({"mode":"closed"});
+ var style = document.createElement('style');
+ style.innerText = 'p { color: red; }';
+ style.addEventListener('securitypolicyviolation', t.step_func_done(e => {
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, style);
+ }));
+ shadow.appendChild(style);
+ }, "Correct targeting inside shadow tree (style).");
+</script>
+
+<!-- Pushed into a same-origin Document that isn't this Document -->
+<iframe id="block6"></iframe>
+<script nonce="abc">
+ async_test(t => {
+ var d = document.createElement("div");
+ d.setAttribute("onclick", "void(0);");
+ var events = 0;
+ d.addEventListener('securitypolicyviolation', t.step_func(e => {
+ events++;
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, d);
+ }));
+ document.querySelector('#block6').contentDocument.addEventListener('securitypolicyviolation', t.step_func_done(e => {
+ events++;
+ assert_equals(e.blockedURI, "inline");
+ assert_equals(e.target, d);
+ assert_equals(events, 2);
+ }));
+ document.querySelector('#block6').contentDocument.body.appendChild(d);
+ }, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.");
+</script>
+
+<!-- Disconnected inline event handler -->
+<script nonce="abc">
+ async_test(t => {
+ var d = document.createElement("div");
+ d.setAttribute("onclick", "void(0);");
+ d.addEventListener('securitypolicyviolation', t.unreached_func());
+ d.click();
+ t.done();
+ }, "Inline event handlers for disconnected elements target the document.");
+</script>
+
+<!-- Inline event handler, disconnected after click. -->
+<a id="block8" onclick="void(0)">Click me also!</a>
+<script nonce="abc">
+ async_test(t => {
+ var a = document.querySelector('#block8');
+ a.addEventListener('securitypolicyviolation', t.unreached_func());
+ a.click();
+ a.parentNode.removeChild(a);
+ t.done();
+ }, "Inline event handlers for elements disconnected after triggering target the document.");
+</script>
+
+<!-- Disconnected in a DocumentFragment -->
+<script nonce="abc">
+ async_test(t => {
+ var f = new DocumentFragment();
+ var d = document.createElement('div');
+ d.setAttribute('onclick', 'void(0)');
+ d.addEventListener('securitypolicyviolation', t.unreached_func());
+ f.appendChild(d);
+ d.click();
+ t.done();
+ }, "Inline event handlers for elements in a DocumentFragment target the document.");
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html
new file mode 100644
index 0000000000..a6617a9590
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html
@@ -0,0 +1,100 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/security-features/resources/common.sub.js"></script>
+<body></body>
+<script>
+ function waitForViolation(el, effective_directive) {
+ return new Promise(resolve => {
+ el.addEventListener('securitypolicyviolation', e => {
+ if (e.effectiveDirective == effective_directive)
+ resolve(e);
+ });
+ });
+ }
+
+ async_test(t => {
+ var url = getRequestURLs("img-tag",
+ "same-http-downgrade",
+ "no-redirect").testUrl;
+ var i = document.createElement('img');
+ var loaded = false;
+ var reported = false;
+ waitForViolation(window, "img-src")
+ .then(t.step_func(e => {
+ reported = true;
+ if (loaded)
+ t.done();
+ }));
+ i.onload = t.step_func(_ => {
+ loaded = true;
+ if (reported)
+ t.done();
+ });
+ i.onerror = t.unreached_func(url + " should load successfully.");
+ i.src = url;
+ document.body.appendChild(i);
+ }, "Upgraded image is reported");
+
+ async_test(t => {
+ var url = getRequestURLs("iframe-tag",
+ "same-http-downgrade",
+ "no-redirect").testUrl;
+ var i = document.createElement('iframe');
+ var loaded = false;
+ var reported = false;
+ waitForViolation(window, "frame-src")
+ .then(t.step_func(e => {
+ reported = true;
+ if (loaded)
+ t.done();
+ }));
+ window.addEventListener("message", t.step_func(e => {
+ if (e.source == i.contentWindow) {
+ i.remove();
+ loaded = true;
+ if (reported)
+ t.done();
+ }
+ }));
+ i.src = url;
+ document.body.appendChild(i);
+ }, "Upgraded iframe is reported");
+
+ async_test(t => {
+ // Load an HTTPS iframe, then navigate it to an HTTP URL and check that the HTTP URL is both upgraded and reported.
+ var url = getRequestURLs("iframe-tag",
+ "same-https",
+ "no-redirect").testUrl;
+ var navigate_to = getRequestURLs("iframe-tag",
+ "cross-http-downgrade",
+ "no-redirect").testUrl;
+ var upgraded = new URL(navigate_to);
+ upgraded.protocol = "https";
+
+ var i = document.createElement('iframe');
+ var loaded = false;
+ var reported = false;
+
+ window.addEventListener("message", t.step_func(e => {
+ if (e.source == i.contentWindow) {
+ if (e.data.location == url) {
+ waitForViolation(window, "frame-src")
+ .then(t.step_func(e => {
+ reported = true;
+ if (loaded)
+ t.done();
+ }));
+ i.contentWindow.location.href = navigate_to;
+ } else if (e.data.location == upgraded) {
+ loaded = true;
+ if (reported)
+ t.done();
+ }
+ }
+ }));
+ i.src = url;
+ document.body.appendChild(i);
+ }, "Navigated iframe is upgraded and reported");
+</script>
+</html>
diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers
new file mode 100644
index 0000000000..b8bec0b95e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.headers
@@ -0,0 +1,2 @@
+Content-Security-Policy-Report-Only: frame-src https:; img-src https:
+Content-Security-Policy: upgrade-insecure-requests