summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/content-security-policy/support
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/content-security-policy/support')
-rw-r--r--testing/web-platform/tests/content-security-policy/support/alert-pass.js1
-rw-r--r--testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js43
-rw-r--r--testing/web-platform/tests/content-security-policy/support/checkReport.sub.js138
-rw-r--r--testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js1
-rw-r--r--testing/web-platform/tests/content-security-policy/support/echo-policy.py3
-rw-r--r--testing/web-platform/tests/content-security-policy/support/fail.asis5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/fail.html3
-rw-r--r--testing/web-platform/tests/content-security-policy/support/fail.js1
-rw-r--r--testing/web-platform/tests/content-security-policy/support/fail.pngbin0 -> 759 bytes
-rw-r--r--testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html9
-rw-r--r--testing/web-platform/tests/content-security-policy/support/fonts.css8
-rw-r--r--testing/web-platform/tests/content-security-policy/support/import-scripts.js3
-rw-r--r--testing/web-platform/tests/content-security-policy/support/inject-image.js4
-rw-r--r--testing/web-platform/tests/content-security-policy/support/inject-image.sub.js3
-rw-r--r--testing/web-platform/tests/content-security-policy/support/logTest.sub.js41
-rw-r--r--testing/web-platform/tests/content-security-policy/support/manifest.json5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js1
-rw-r--r--testing/web-platform/tests/content-security-policy/support/pass.pngbin0 -> 1689 bytes
-rw-r--r--testing/web-platform/tests/content-security-policy/support/pass2.pngbin0 -> 1689 bytes
-rw-r--r--testing/web-platform/tests/content-security-policy/support/ping.js12
-rw-r--r--testing/web-platform/tests/content-security-policy/support/post-message.js1
-rw-r--r--testing/web-platform/tests/content-security-policy/support/postmessage-fail.html4
-rw-r--r--testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html3
-rw-r--r--testing/web-platform/tests/content-security-policy/support/postmessage-pass.html4
-rw-r--r--testing/web-platform/tests/content-security-policy/support/prefetch-helper.js85
-rw-r--r--testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css3
-rw-r--r--testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers1
-rw-r--r--testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html18
-rw-r--r--testing/web-platform/tests/content-security-policy/support/resource.py5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/service-worker-helper.js5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/siblingPath.js5
-rw-r--r--testing/web-platform/tests/content-security-policy/support/testharness-helper.js142
-rw-r--r--testing/web-platform/tests/content-security-policy/support/var-a.js1
35 files changed, 568 insertions, 0 deletions
diff --git a/testing/web-platform/tests/content-security-policy/support/alert-pass.js b/testing/web-platform/tests/content-security-policy/support/alert-pass.js
new file mode 100644
index 0000000000..d3f811ec1b
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/alert-pass.js
@@ -0,0 +1 @@
+alert_assert("PASS"); \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js b/testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js
new file mode 100644
index 0000000000..3877b2679d
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js
@@ -0,0 +1,43 @@
+// note, this template substitution is XSS, but no way to avoid it in this framework
+var expected_alerts = {{GET[alerts]}};
+var timeout= "{{GET[timeout]}}";
+if (timeout == "") {
+ timeout = 2;
+}
+
+if(expected_alerts.length == 0) {
+ function alert_assert(msg) {
+ test(function () { assert_unreached(msg) });
+ }
+} else {
+ var t_alert = async_test('Expecting alerts: {{GET[alerts]}}');
+ step_timeout(function() {
+ if(t_alert.phase != t_alert.phases.COMPLETE) {
+ t_alert.step(function() { assert_unreached('Alert timeout, expected alerts ' + expected_alerts + ' not fired.') });
+ t_alert.done();
+ }
+ }, timeout * 1000);
+ var alert_assert = function (msg) {
+ t_alert.step(function () {
+ if(msg && msg instanceof Error) {
+ msg = msg.message;
+ }
+ if (msg && msg.match(/^FAIL/i)) {
+ assert_unreached(msg);
+ t_alert.done();
+ }
+ for (var i = 0; i < expected_alerts.length; i++) {
+ if (expected_alerts[i] == msg) {
+ assert_equals(expected_alerts[i], msg);
+ expected_alerts.splice(i, 1);
+ if (expected_alerts.length == 0) {
+ t_alert.done();
+ }
+ return;
+ }
+ }
+ assert_unreached('unexpected alert: ' + msg);
+ t_log.done();
+ });
+ }.bind(this);
+}
diff --git a/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js b/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js
new file mode 100644
index 0000000000..9cc242662b
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js
@@ -0,0 +1,138 @@
+(function () {
+
+ // Get values from the substitution engine.
+ // We can't just pull these from the document context
+ // because this script is intended to be transcluded into
+ // another document, and we want the GET values used to request it,
+ // not the values for the including document
+
+ // XXX these are unencoded, so there's an unavoidable
+ // injection vulnerability in constructing this file...
+ // need to upgrade the template engine.
+ var reportField = "{{GET[reportField]}}";
+ var reportValue = "{{GET[reportValue]}}";
+ var reportExists = "{{GET[reportExists]}}";
+ var noCookies = "{{GET[noCookies]}}";
+ var reportCookieName = "{{GET[reportCookieName]}}"
+ var testName = "{{GET[testName]}}"
+ var cookiePresent = "{{GET[cookiePresent]}}"
+ var reportCount = "{{GET[reportCount]}}"
+
+ var location = window.location;
+ if (reportCookieName == "") {
+ // fallback on test file name if cookie name not specified
+ reportCookieName = location.pathname.split('/')[location.pathname.split('/').length - 1].split('.')[0];
+ }
+
+ var reportID = "{{GET[reportID]}}";
+
+ if (reportID == "") {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookieName = cookies[i].split('=')[0].trim();
+ var cookieValue = cookies[i].split('=')[1].trim();
+
+ if (cookieName == reportCookieName) {
+ reportID = cookieValue;
+ var cookieToDelete = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" + document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/') + 1);
+ document.cookie = cookieToDelete;
+ break;
+ }
+ }
+ }
+
+ // There is no real way to test (in this particular layer) that a CSP report
+ // has *not* been sent, at least not without some major reworks and
+ // involvement from all the platform participants. So the current "solution"
+ // is to wait for some reasonable amount of time and if no report has been
+ // received to conclude that no report has been generated. These timeouts must
+ // not exceed the test timeouts set by vendors otherwise the test would fail.
+ var timeout = document.querySelector("meta[name=timeout][content=long]") ? 20 : 3;
+ var reportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_report&timeout=" + timeout + "&reportID=" + reportID;
+
+ if (testName == "") testName = "Violation report status OK.";
+ var reportTest = async_test(testName);
+
+ function assert_field_value(field, value, field_name) {
+ assert_true(field.indexOf(value.split(" ")[0]) != -1,
+ field_name + " value of \"" + field + "\" did not match " +
+ value.split(" ")[0] + ".");
+ }
+
+ reportTest.step(function () {
+
+ var report = new XMLHttpRequest();
+ report.onload = reportTest.step_func(function () {
+ var data = JSON.parse(report.responseText);
+
+ if (data.error) {
+ assert_equals("false", reportExists, data.error);
+ } else {
+ if (reportExists === "false") {
+ assert_equals(data.length, 0,
+ "CSP report sent, but not expecting one.");
+ } else {
+ // With the 'report-uri' directive, the report is contained in
+ // `data[0]["csp-report"]`. With the 'report-to' directive, the report
+ // is contained in `data[0]["body"]`.
+ const reportBody = data[0]["body"]
+ ? data[0]["body"]
+ : data[0]["csp-report"];
+
+ assert_true(reportBody !== undefined,
+ "No CSP report sent, but expecting one.");
+ // Firefox expands 'self' or origins in a policy to the actual origin value
+ // so "www.example.com" becomes "http://www.example.com:80".
+ // Accomodate this by just testing that the correct directive name
+ // is reported, not the details...
+
+ if (reportBody[reportField] !== undefined) {
+ assert_field_value(reportBody[reportField], reportValue, reportField);
+ } else {
+ assert_equals(reportField, "", "Expected report field could not be found in report.");
+ }
+ }
+ }
+
+ reportTest.done();
+ });
+
+ report.open("GET", reportLocation, true);
+ report.send();
+ });
+
+ if (noCookies || cookiePresent) {
+ var cookieTest = async_test("Test report cookies.");
+ var cookieReport = new XMLHttpRequest();
+ cookieReport.onload = cookieTest.step_func(function () {
+ var data = JSON.parse(cookieReport.responseText);
+ if (noCookies) {
+ assert_equals(data.reportCookies, "None", "Report should not contain any cookies");
+ }
+
+ if (cookiePresent) {
+ assert_true(data.reportCookies.hasOwnProperty(cookiePresent), "Report should contain cookie: " + cookiePresent);
+ }
+ cookieTest.done();
+ });
+ var cReportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_cookies&timeout=" + timeout + "&reportID=" + reportID;
+ cookieReport.open("GET", cReportLocation, true);
+ cookieReport.send();
+ }
+
+ if (reportCount != "") {
+ var reportCountTest = async_test("Test number of sent reports.");
+ var reportCountReport = new XMLHttpRequest();
+ reportCountReport.onload = reportCountTest.step_func(function () {
+ var data = JSON.parse(reportCountReport.responseText);
+
+ assert_equals(data.report_count, +reportCount, "Report count was not what was expected.");
+
+ reportCountTest.done();
+ });
+ var cReportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_count&timeout=" + timeout + "&reportID=" + reportID;
+ reportCountReport.open("GET", cReportLocation, true);
+ reportCountReport.send();
+ }
+
+})();
diff --git a/testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js b/testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js
new file mode 100644
index 0000000000..8441ab0de7
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js
@@ -0,0 +1,5 @@
+var url = new URL("../support/ping.js", document.baseURI).toString();
+if (document.getElementById("foo").hasAttribute("blocked-worker"))
+ assert_worker_is_blocked(url, document.getElementById("foo").getAttribute("data-desc-fallback"));
+else
+ assert_worker_is_loaded(url, document.getElementById("foo").getAttribute("data-desc-fallback")); \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js b/testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js
new file mode 100644
index 0000000000..5e78ca0dac
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js
@@ -0,0 +1 @@
+document.write("<script>test(function () { assert_unreached('FAIL inline script from document.write ran') });</script>");
diff --git a/testing/web-platform/tests/content-security-policy/support/echo-policy.py b/testing/web-platform/tests/content-security-policy/support/echo-policy.py
new file mode 100644
index 0000000000..3a4b2f3d2e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/echo-policy.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ policy = request.GET.first(b"policy")
+ return [(b"Content-Type", b"text/html"), (b"Content-Security-Policy", policy)], b"<!DOCTYPE html><title>Echo.</title>"
diff --git a/testing/web-platform/tests/content-security-policy/support/fail.asis b/testing/web-platform/tests/content-security-policy/support/fail.asis
new file mode 100644
index 0000000000..96196615bd
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/fail.asis
@@ -0,0 +1,5 @@
+HTTP/1.1 200 OK
+Content-Type: text/plain
+Access-Control-Allow-Origin: *
+
+FAIL \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/fail.html b/testing/web-platform/tests/content-security-policy/support/fail.html
new file mode 100644
index 0000000000..fedcc31bd3
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/fail.html
@@ -0,0 +1,3 @@
+<script>
+ test(function() { assert_unreached("FAIL")});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/fail.js b/testing/web-platform/tests/content-security-policy/support/fail.js
new file mode 100644
index 0000000000..9632567a6e
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/fail.js
@@ -0,0 +1 @@
+test(function() { assert_unreached("FAIL")}); \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/fail.png b/testing/web-platform/tests/content-security-policy/support/fail.png
new file mode 100644
index 0000000000..b593380333
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/fail.png
Binary files differ
diff --git a/testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html b/testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html
new file mode 100644
index 0000000000..bd60d262ad
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <!-- CSP directive 'prefetch-src' is not supported via meta tag though -->
+ <meta http-equiv="Content-Security-Policy" content="prefetch-src 'self'">
+</head>
+<body>
+</body>
+</html>
diff --git a/testing/web-platform/tests/content-security-policy/support/fonts.css b/testing/web-platform/tests/content-security-policy/support/fonts.css
new file mode 100644
index 0000000000..848961c8dc
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/fonts.css
@@ -0,0 +1,8 @@
+@font-face {
+ font-family: 'Ahem';
+ src: url('/fonts/Ahem.ttf');
+}
+
+body {
+ font-family: 'Ahem', Fallback, sans-serif;
+}
diff --git a/testing/web-platform/tests/content-security-policy/support/import-scripts.js b/testing/web-platform/tests/content-security-policy/support/import-scripts.js
new file mode 100644
index 0000000000..8325ebb3fb
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/import-scripts.js
@@ -0,0 +1,3 @@
+self.a = false;
+importScripts('/content-security-policy/support/var-a.js');
+postMessage({ 'executed': self.a });
diff --git a/testing/web-platform/tests/content-security-policy/support/inject-image.js b/testing/web-platform/tests/content-security-policy/support/inject-image.js
new file mode 100644
index 0000000000..a10d50a983
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/inject-image.js
@@ -0,0 +1,4 @@
+// This script block will trigger a violation report.
+var i = document.createElement('img');
+i.src = '/content-security-policy/support/fail.png';
+document.body.appendChild(i);
diff --git a/testing/web-platform/tests/content-security-policy/support/inject-image.sub.js b/testing/web-platform/tests/content-security-policy/support/inject-image.sub.js
new file mode 100644
index 0000000000..acf04f325f
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/inject-image.sub.js
@@ -0,0 +1,3 @@
+var i = document.createElement('img');
+i.src = "http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/fail.png";
+document.body.appendChild(i);
diff --git a/testing/web-platform/tests/content-security-policy/support/logTest.sub.js b/testing/web-platform/tests/content-security-policy/support/logTest.sub.js
new file mode 100644
index 0000000000..29b8a271f5
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/logTest.sub.js
@@ -0,0 +1,41 @@
+// note, this template substitution is XSS, but no way to avoid it in this framework
+var expected_logs = {{GET[logs]}};
+var timeout = "{{GET[timeout]}}";
+if (timeout == "") {
+ timeout = 2;
+}
+
+if (expected_logs.length == 0) {
+ function log_assert(msg) {
+ test(function () { assert_unreached(msg) });
+ }
+} else {
+ var t_log = async_test('Expecting logs: {{GET[logs]}}');
+ step_timeout(function() {
+ if(t_log.phase != t_log.phases.COMPLETE){
+ t_log.step(function () { assert_unreached('Logging timeout, expected logs ' + expected_logs + ' not sent.') });
+ t_log.done();
+ }
+ }, timeout * 1000);
+ function log(msg) {
+ //cons/**/ole.log(msg);
+ t_log.step(function () {
+ if (msg.match(/^FAIL/i)) {
+ assert_unreached(msg);
+ t_log.done();
+ }
+ for (var i = 0; i < expected_logs.length; i++) {
+ if (expected_logs[i] == msg) {
+ assert_equals(expected_logs[i], msg);
+ expected_logs.splice(i, 1);
+ if (expected_logs.length == 0) {
+ t_log.done();
+ }
+ return;
+ }
+ }
+ assert_unreached('unexpected log: ' + msg);
+ t_log.done();
+ });
+ }
+}
diff --git a/testing/web-platform/tests/content-security-policy/support/manifest.json b/testing/web-platform/tests/content-security-policy/support/manifest.json
new file mode 100644
index 0000000000..97da19c5ca
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/manifest.json
@@ -0,0 +1,5 @@
+{
+ "name": "Dummy manifest",
+ "start_url": "/start.html"
+}
+ \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js b/testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js
new file mode 100644
index 0000000000..501f7a9208
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js
@@ -0,0 +1 @@
+t.unreached_func(document.currentScript.getAttribute('src') + " should not execute.")();
diff --git a/testing/web-platform/tests/content-security-policy/support/pass.png b/testing/web-platform/tests/content-security-policy/support/pass.png
new file mode 100644
index 0000000000..2fa1e0ac06
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/pass.png
Binary files differ
diff --git a/testing/web-platform/tests/content-security-policy/support/pass2.png b/testing/web-platform/tests/content-security-policy/support/pass2.png
new file mode 100644
index 0000000000..2fa1e0ac06
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/pass2.png
Binary files differ
diff --git a/testing/web-platform/tests/content-security-policy/support/ping.js b/testing/web-platform/tests/content-security-policy/support/ping.js
new file mode 100644
index 0000000000..750ae45f96
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/ping.js
@@ -0,0 +1,12 @@
+if (typeof ServiceWorkerGlobalScope === "function") {
+ self.onmessage = function (e) { e.source.postMessage("ping"); };
+} else if (typeof SharedWorkerGlobalScope === "function") {
+ onconnect = function (e) {
+ var port = e.ports[0];
+
+ port.onmessage = function () { port.postMessage("ping"); }
+ port.postMessage("ping");
+ };
+} else if (typeof DedicatedWorkerGlobalScope === "function") {
+ self.postMessage("ping");
+}
diff --git a/testing/web-platform/tests/content-security-policy/support/post-message.js b/testing/web-platform/tests/content-security-policy/support/post-message.js
new file mode 100644
index 0000000000..69daa31d2f
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/post-message.js
@@ -0,0 +1 @@
+postMessage("importScripts allowed");
diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html b/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html
new file mode 100644
index 0000000000..a0308ad98b
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html
@@ -0,0 +1,4 @@
+<script>
+ window.parent.postMessage('FAIL', '*');
+
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html b/testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html
new file mode 100644
index 0000000000..e1bdf7102f
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html
@@ -0,0 +1,3 @@
+<script>
+ window.top.opener.postMessage('PASS', '*');
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html b/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html
new file mode 100644
index 0000000000..700167b5db
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html
@@ -0,0 +1,4 @@
+<script>
+ window.parent.postMessage('PASS', '*');
+
+</script>
diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-helper.js b/testing/web-platform/tests/content-security-policy/support/prefetch-helper.js
new file mode 100644
index 0000000000..c0c0be9157
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/prefetch-helper.js
@@ -0,0 +1,85 @@
+setup(_ => {
+ assert_implements_optional(
+ document.createElement('link').relList.supports('prefetch'),
+ "Browser supports prefetch.");
+ assert_implements_optional(
+ "PerformanceResourceTiming" in window,
+ "Browser supports performance APIs.");
+});
+
+function assert_resource_not_downloaded(test, url) {
+ // CSP failures generate resource timing entries, so let's make sure that
+ // download sizes are 0.
+ const entries = performance.getEntriesByName(url, 'resource');
+ for (const entry of entries) {
+ assert_equals(entry.transferSize, 0, 'transferSize');
+ assert_equals(entry.encodedBodySize, 0, 'encodedBodySize');
+ assert_equals(entry.decodedBodySize, 0, 'decodedBodySize');
+ }
+}
+
+function assert_link_prefetches(test, link) {
+ assert_no_csp_event_for_url(test, link.href);
+
+ link.onerror = test.unreached_func('onerror should not fire.');
+
+ // Test is finished when either the `load` event fires, or we get a performance
+ // entry showing that the resource loaded successfully.
+ link.onload = test.step_func(test.step_func_done());
+ waitUntilResourceDownloaded(link.href).then(test.step_func_done());
+
+ document.head.appendChild(link);
+}
+
+function assert_link_does_not_prefetch(test, link) {
+ let cspEvent = false;
+ let errorEvent = false;
+
+ waitUntilCSPEventForURL(test, link.href)
+ .then(test.step_func(e => {
+ cspEvent = true;
+ assert_equals(e.violatedDirective, "prefetch-src");
+ assert_equals(e.effectiveDirective, "prefetch-src");
+
+ if (errorEvent)
+ test.done();
+ }));
+
+ link.onerror = test.step_func(e => {
+ errorEvent = true;
+ if (cspEvent)
+ test.done();
+ });
+ link.onload = test.unreached_func('onload should not fire.');
+
+ document.head.appendChild(link);
+}
+
+async function try_to_prefetch(href, test) {
+ const url = new URL(href, location.href);
+ url.searchParams.set(
+ 'pipe',
+ '|header(Cache-Control, max-age=604800)' +
+ '|header(Access-Control-Allow-Origin, *)' +
+ '|header(Timing-Allow-Origin, *)');
+ url.searchParams.set('uuid', token());
+
+ const link = document.createElement('link');
+ link.rel = 'prefetch';
+ link.href = url.toString();
+ link.crossOrigin = 'anonymous';
+ test.add_cleanup(() => link.remove());
+
+ const didPrefetch = new Promise(resolve => {
+ const observer = new PerformanceObserver(list => {
+ const entries = list.getEntriesByName(link.href);
+ if (entries.length) {
+ resolve(entries[0]);
+ }
+ });
+ observer.observe({entryTypes: ['resource']})
+ });
+ document.head.appendChild(link);
+ const entry = await didPrefetch;
+ return entry.requestStart > 0 && entry.decodedBodySize > 0;
+}
diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css
new file mode 100644
index 0000000000..4c4fa46442
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css
@@ -0,0 +1,3 @@
+/* This CSS file sends some headers:
+ * Link: </content-security-policy/support/fail.png>;rel=prefetch
+ */
diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers
new file mode 100644
index 0000000000..eaf7b16638
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers
@@ -0,0 +1 @@
+Link: </content-security-policy/support/fail.png>;rel=prefetch
diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html b/testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html
new file mode 100644
index 0000000000..8185a3abee
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+ <html>
+ <head>
+ <link id="prefetch" rel="prefetch" href="pass.png">
+ </head>
+ <body>
+ <script>
+ const bc = new BroadcastChannel(new URLSearchParams(location.search).get("uid"));
+ document.getElementById("prefetch").addEventListener("error", e => bc.postMessage(false));
+ const observer = new PerformanceObserver(entries => {
+ const found = entries.getEntriesByName(new URL("pass.png", location.href).href);
+ if (found.length)
+ bc.postMessage(found[0].encodedBodySize > 0);
+ });
+ observer.observe({entryTypes: ["resource"]});
+ </script>
+ </body>
+ </html>
diff --git a/testing/web-platform/tests/content-security-policy/support/resource.py b/testing/web-platform/tests/content-security-policy/support/resource.py
new file mode 100644
index 0000000000..4d73d5bf76
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/resource.py
@@ -0,0 +1,5 @@
+def main(request, response):
+ headers = []
+ headers.append((b"Access-Control-Allow-Origin", b"*"))
+
+ return headers, b"{ \"result\": \"success\" }"
diff --git a/testing/web-platform/tests/content-security-policy/support/service-worker-helper.js b/testing/web-platform/tests/content-security-policy/support/service-worker-helper.js
new file mode 100644
index 0000000000..b5f65c96a0
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/service-worker-helper.js
@@ -0,0 +1,5 @@
+var url = new URL("../support/ping.js", document.baseURI).toString();
+if (document.getElementById("foo").hasAttribute("blocked-worker"))
+ assert_service_worker_is_blocked(url, document.getElementById("foo").getAttribute("data-desc-fallback"));
+else
+ assert_service_worker_is_loaded(url, document.getElementById("foo").getAttribute("data-desc-fallback")); \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js b/testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js
new file mode 100644
index 0000000000..2a3873873f
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js
@@ -0,0 +1,5 @@
+var url = new URL("../support/ping.js", document.baseURI).toString();
+if (document.getElementById("foo").hasAttribute("blocked-worker"))
+ assert_shared_worker_is_blocked(url, document.getElementById("foo").getAttribute("data-desc-fallback"));
+else
+ assert_shared_worker_is_loaded(url, document.getElementById("foo").getAttribute("data-desc-fallback")); \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/siblingPath.js b/testing/web-platform/tests/content-security-policy/support/siblingPath.js
new file mode 100644
index 0000000000..f4012f04dd
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/siblingPath.js
@@ -0,0 +1,5 @@
+ buildSiblingPath = function(hostPrefix, relativePath, newPort) {
+ var port = newPort ? newPort : document.location.port;
+ var path = document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/') + 1);
+ return (document.location.protocol + '//' + hostPrefix + "." + document.location.hostname + ':' + port + path + relativePath);
+}; \ No newline at end of file
diff --git a/testing/web-platform/tests/content-security-policy/support/testharness-helper.js b/testing/web-platform/tests/content-security-policy/support/testharness-helper.js
new file mode 100644
index 0000000000..5c36e286da
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/testharness-helper.js
@@ -0,0 +1,142 @@
+function assert_no_csp_event_for_url(test, url) {
+ self.addEventListener("securitypolicyviolation", test.step_func(e => {
+ if (e.blockedURI !== url)
+ return;
+ assert_unreached("SecurityPolicyViolation event fired for " + url);
+ }));
+}
+
+function assert_no_event(test, obj, name) {
+ obj.addEventListener(name, test.unreached_func("The '" + name + "' event should not have fired."));
+}
+
+function waitUntilCSPEventForURLOrLine(test, url, line) {
+ return new Promise((resolve, reject) => {
+ self.addEventListener("securitypolicyviolation", test.step_func(e => {
+ if (e.blockedURI == url && (!line || line == e.lineNumber))
+ resolve(e);
+ }));
+ });
+}
+
+function waitUntilCSPEventForURL(test, url) {
+ return waitUntilCSPEventForURLOrLine(test, url);
+}
+
+function waitUntilCSPEventForEval(test, line) {
+ return waitUntilCSPEventForURLOrLine(test, "eval", line);
+}
+
+function waitUntilCSPEventForTrustedTypes(test) {
+ return waitUntilCSPEventForURLOrLine(test, "trusted-types-sink");
+}
+
+function waitUntilEvent(obj, name) {
+ return new Promise((resolve, reject) => {
+ obj.addEventListener(name, resolve);
+ });
+}
+
+// Given the URL of a worker that pings its opener upon load, this
+// function builds a test that asserts that the ping is received,
+// and that no CSP event fires.
+function assert_worker_is_loaded(url, description, expected_message = "ping") {
+ async_test(t => {
+ assert_no_csp_event_for_url(t, url);
+ var w = new Worker(url);
+ assert_no_event(t, w, "error");
+ waitUntilEvent(w, "message")
+ .then(t.step_func_done(e => {
+ assert_equals(e.data, expected_message);
+ }));
+ }, description);
+}
+
+function assert_shared_worker_is_loaded(url, description, expected_message = "ping") {
+ async_test(t => {
+ assert_no_csp_event_for_url(t, url);
+ var w = new SharedWorker(url);
+ assert_no_event(t, w, "error");
+ waitUntilEvent(w.port, "message")
+ .then(t.step_func_done(e => {
+ assert_equals(e.data, expected_message);
+ }));
+ w.port.start();
+ }, description);
+}
+
+function assert_service_worker_is_loaded(url, description) {
+ promise_test(t => {
+ assert_no_csp_event_for_url(t, url);
+ return Promise.all([
+ waitUntilEvent(navigator.serviceWorker, "message")
+ .then(e => {
+ assert_equals(e.data, "ping");
+ }),
+ navigator.serviceWorker.register(url, { scope: url })
+ .then(r => {
+ var sw = r.active || r.installing || r.waiting;
+ t.add_cleanup(_ => r.unregister());
+ sw.postMessage("pong?");
+ })
+ ]);
+ }, description);
+}
+
+// Given the URL of a worker that pings its opener upon load, this
+// function builds a test that asserts that the constructor throws
+// a SecurityError, and that a CSP event fires.
+function assert_worker_is_blocked(url, description) {
+ async_test(t => {
+ // If |url| is a blob, it will be stripped down to "blob" for reporting.
+ var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
+ waitUntilCSPEventForURL(t, reportedURL)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, reportedURL);
+ assert_equals(e.violatedDirective, "worker-src");
+ assert_equals(e.effectiveDirective, "worker-src");
+ }));
+
+ // TODO(mkwst): We shouldn't be throwing here. We should be firing an
+ // `error` event on the Worker. https://crbug.com/663298
+ assert_throws_dom("SecurityError", function () {
+ var w = new Worker(url);
+ });
+ }, description);
+}
+
+function assert_shared_worker_is_blocked(url, description) {
+ async_test(t => {
+ // If |url| is a blob, it will be stripped down to "blob" for reporting.
+ var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
+ waitUntilCSPEventForURL(t, reportedURL)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, reportedURL);
+ assert_equals(e.violatedDirective, "worker-src");
+ assert_equals(e.effectiveDirective, "worker-src");
+ }));
+
+ // TODO(mkwst): We shouldn't be throwing here. We should be firing an
+ // `error` event on the SharedWorker. https://crbug.com/663298
+ assert_throws_dom("SecurityError", function () {
+ var w = new SharedWorker(url);
+ });
+ }, description);
+}
+
+function assert_service_worker_is_blocked(url, description) {
+ promise_test(t => {
+ assert_no_event(t, navigator.serviceWorker, "message");
+ // If |url| is a blob, it will be stripped down to "blob" for reporting.
+ var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
+ return Promise.all([
+ waitUntilCSPEventForURL(t, reportedURL)
+ .then(t.step_func_done(e => {
+ assert_equals(e.blockedURI, reportedURL);
+ assert_equals(e.violatedDirective, "worker-src");
+ assert_equals(e.effectiveDirective, "worker-src");
+ })),
+ promise_rejects_dom(t, "SecurityError", navigator.serviceWorker.register(url, { scope: url }))
+ ]);
+ }, description);
+}
diff --git a/testing/web-platform/tests/content-security-policy/support/var-a.js b/testing/web-platform/tests/content-security-policy/support/var-a.js
new file mode 100644
index 0000000000..5fc5fde204
--- /dev/null
+++ b/testing/web-platform/tests/content-security-policy/support/var-a.js
@@ -0,0 +1 @@
+self.a = true;