summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/browsers/sandboxing
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /testing/web-platform/tests/html/browsers/sandboxing
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/browsers/sandboxing')
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/inner-iframe.html13
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/noscript-iframe.html3
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/popup-from-initial-empty-sandboxed-document.window.js46
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/check-sandbox-flags.html8
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/document-open.html14
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/execute-postmessage.html5
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/post-done-to-opener.html3
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html15
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html.headers1
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-javascript-window-open.html18
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-same-origin.html30
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-scripts.html29
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-popups.html39
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-same-origin.html35
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts-via-unsandboxed-popup.tentative.html33
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts.html29
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open-mutation.window.js37
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open.html50
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-frame.html64
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-response.html46
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html154
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-initial-empty-document-toward-same-origin.html30
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-javascript-window-open.html19
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing-iframe.tentative.html16
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing.tentative.html29
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context-iframe.html5
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context.html39
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html6
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript.html7
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/sandbox-window-open-srcdoc.html52
-rw-r--r--testing/web-platform/tests/html/browsers/sandboxing/window-open-blank-from-different-initiator.html90
31 files changed, 965 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/inner-iframe.html b/testing/web-platform/tests/html/browsers/sandboxing/inner-iframe.html
new file mode 100644
index 0000000000..229f6b3d85
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/inner-iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script>
+ window.onload = function() {
+ top.calledFromIframe();
+ }
+ </script>
+ </head>
+ <body>
+ <div id="inner">foo</div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/noscript-iframe.html b/testing/web-platform/tests/html/browsers/sandboxing/noscript-iframe.html
new file mode 100644
index 0000000000..677b5fc83a
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/noscript-iframe.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<noscript>PASS</noscript>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/popup-from-initial-empty-sandboxed-document.window.js b/testing/web-platform/tests/html/browsers/sandboxing/popup-from-initial-empty-sandboxed-document.window.js
new file mode 100644
index 0000000000..1ae4fad0cb
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/popup-from-initial-empty-sandboxed-document.window.js
@@ -0,0 +1,46 @@
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/dispatcher/dispatcher.js
+
+// Regression test for: https://crbug.com/1256822.
+//
+// From a sandboxed iframe allowing popups, scripts, and same-origin. Open a
+// popup using the WindowProxy of a new iframe that is still on the initial
+// empty document. Check that the sandbox flags are properly inherited.
+
+// Return true if the execution context is sandboxed.
+const isSandboxed = () => {
+ try {
+ // Setting document.domain in sandboxed document throw errors.
+ document.domain = document.domain;
+ return false;
+ } catch (error) {
+ return true;
+ }
+}
+
+promise_test(async test => {
+ // 1. Create a sandboxed iframe, allowing popups, same-origin and scripts.
+ const iframe_token = token();
+ const iframe_document = new RemoteContext(iframe_token);
+ const iframe_url = remoteExecutorUrl(iframe_token);
+ const iframe = document.createElement("iframe");
+ iframe.sandbox = "allow-same-origin allow-scripts allow-popups";
+ iframe.src = iframe_url;
+ document.body.appendChild(iframe);
+ assert_true(await iframe_document.execute_script(isSandboxed),
+ "iframe is sandboxed");
+
+ // 2. From the sandboxed iframe, create an empty iframe, and open a popup
+ // using it's WindowProxy. The popup must inherit sandbox flags.
+ const popup_token = token();
+ const popup_document = new RemoteContext(popup_token);
+ const popup_url = remoteExecutorUrl(popup_token);
+ iframe_document.execute_script((popup_url) => {
+ let iframe = document.createElement("iframe");
+ iframe.name = "iframe_name";
+ document.body.appendChild(iframe);
+ iframe_name.open(popup_url);
+ }, [popup_url.href]);
+ assert_true(await popup_document.execute_script(isSandboxed), "popup is sandboxed");
+});
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/check-sandbox-flags.html b/testing/web-platform/tests/html/browsers/sandboxing/resources/check-sandbox-flags.html
new file mode 100644
index 0000000000..0dc95315f1
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/check-sandbox-flags.html
@@ -0,0 +1,8 @@
+<script>
+ try {
+ document.domain = document.domain;
+ parent.postMessage('document-domain-is-allowed', '*');
+ } catch (error) {
+ parent.postMessage('document-domain-is-disallowed', '*');
+ }
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/document-open.html b/testing/web-platform/tests/html/browsers/sandboxing/resources/document-open.html
new file mode 100644
index 0000000000..136c494d5a
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/document-open.html
@@ -0,0 +1,14 @@
+<script>
+ onload = () => {
+ document.write(`
+ <script>
+ try {
+ document.domain = document.domain;
+ parent.postMessage('document-domain-is-allowed', '*');
+ } catch (error) {
+ parent.postMessage('document-domain-is-disallowed', '*');
+ }
+ </sc`+`ript>
+ `);
+ }
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/execute-postmessage.html b/testing/web-platform/tests/html/browsers/sandboxing/resources/execute-postmessage.html
new file mode 100644
index 0000000000..89bd268f9c
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/execute-postmessage.html
@@ -0,0 +1,5 @@
+<script>
+ // Execute arbitrary code from somewhere else, via postMessage.
+ window.addEventListener("message", event => eval(event.data));
+ window.opener.postMessage("ready", "*");
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/post-done-to-opener.html b/testing/web-platform/tests/html/browsers/sandboxing/resources/post-done-to-opener.html
new file mode 100644
index 0000000000..b47f0f274e
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/post-done-to-opener.html
@@ -0,0 +1,3 @@
+<script>
+ window.opener.top.postMessage("DONE", "*");
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html b/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html
new file mode 100644
index 0000000000..29c7f12441
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html
@@ -0,0 +1,15 @@
+<script>
+ const iframe_1_script = encodeURI(`
+ <script>
+ try {
+ document.domain = document.domain;
+ parent.postMessage("not sandboxed", "*");
+ } catch (exception) {
+ parent.postMessage("sandboxed", "*");
+ }
+ </scr`+`ipt>
+ `);
+
+ const iframe_1 = parent.document.querySelector("#iframe_1");
+ iframe_1.src = `data:text/html,${iframe_1_script}`;
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html.headers b/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html.headers
new file mode 100644
index 0000000000..82e8023d0b
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-inherited-from-initiator-response-helper.html.headers
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox allow-scripts allow-same-origin
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-javascript-window-open.html b/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-javascript-window-open.html
new file mode 100644
index 0000000000..909956a54f
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/resources/sandbox-javascript-window-open.html
@@ -0,0 +1,18 @@
+<script>
+ // Forward message from the openee toward the parent.
+ window.addEventListener("message", event => top.postMessage(event.data, "*"));
+
+ let check_sandboxed = `"
+ <script>
+ try {
+ document.domain = document.domain;
+ opener.postMessage('allow-document-domain', '*');
+ } catch (error) {
+ opener.postMessage('disallow-document-domain', '*');
+ }
+ </scr`+`ipt>
+ "`;
+
+ window.open('about:blank', "window_name");
+ window.open("javascript:" + check_sandboxed, "window_name");
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-same-origin.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-same-origin.html
new file mode 100644
index 0000000000..d6b3b099f2
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-same-origin.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>DOM access in sandbox="allow-same-origin" iframe</title>
+ <link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
+ <link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>DOM access in sandbox="allow-same-origin" iframe</h1>
+ <script type="text/javascript">
+ var t = async_test("DOM access in sandbox='allow-same-origin' iframe is allowed")
+ var called = 0;
+ function calledFromIframe() {
+ called++;
+ }
+ function loaded() {
+ assert_equals(document.getElementById('sandboxedframe').contentWindow.document.getElementById('inner').innerHTML, 'foo');
+ assert_equals(called, 0);
+ t.done();
+ }
+ </script>
+
+ <iframe src="/html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox="allow-same-origin" id="sandboxedframe" onload="loaded();"></iframe>
+
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-scripts.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-scripts.html
new file mode 100644
index 0000000000..6cf3f5a4a8
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-allow-scripts.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Script execution in sandbox="allow-scripts" iframe</title>
+ <link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
+ <link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Script execution in sandbox="allow-scripts" iframe</h1>
+ <script type="text/javascript">
+ var t = async_test("Running script from sandbox='allow-scripts' iframe is allowed")
+ var called = 0;
+ function calledFromIframe() {
+ called++;
+ }
+ function loaded() {
+ assert_equals(called, 1);
+ t.done();
+ }
+ </script>
+
+ <iframe src="/html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox="allow-scripts allow-same-origin" id="sandboxedframe" onload="loaded();"></iframe>
+
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-popups.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-popups.html
new file mode 100644
index 0000000000..8e4b34eb8b
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-popups.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>window.open in sandbox iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<script>
+setup({single_test: true});
+// check that the popup's URL is not loaded
+const uuid = token();
+async function assert_popup_not_loaded() {
+ const response = await fetch(`/fetch/api/resources/stash-take.py?key=${uuid}`);
+ assert_equals(await response.json(), null); // is "loaded" if it loads
+}
+
+// check for message from the iframe
+window.onmessage = e => {
+ assert_equals(e.data, 'null', 'return value of window.open (stringified)');
+ step_timeout(async () => {
+ await assert_popup_not_loaded();
+ done();
+ }, 1000);
+};
+const iframe = document.createElement('iframe');
+iframe.sandbox = 'allow-scripts';
+iframe.srcdoc = `
+ <script>
+ let result;
+ try {
+ result = window.open('/fetch/api/resources/stash-put.py?key=${uuid}&value=loaded', '_blank');
+ } catch(ex) {
+ result = ex;
+ }
+ parent.postMessage(String(result), '*');
+ <\/script>
+`;
+document.body.appendChild(iframe);
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-same-origin.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-same-origin.html
new file mode 100644
index 0000000000..0dae0137ac
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-same-origin.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Access to sandbox iframe</title>
+ <link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#sandboxed-origin-browsing-context-flag">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#integration-with-idl">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Access to sandbox iframe</h1>
+ <script type="text/javascript">
+ var t = async_test("Access to sandbox iframe is disallowed")
+ var called = 0;
+ function calledFromIframe() {
+ called++;
+ }
+ function loaded() {
+ t.step(() => {
+ assert_throws_dom("SecurityError", () => {
+ document.getElementById('sandboxedframe').contentWindow.document;
+ });
+ assert_equals(called, 0);
+ t.done();
+ });
+ }
+ </script>
+
+ <iframe src="/html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox id="sandboxedframe" onload="loaded();"></iframe>
+ </body>
+
+ <div id="log"></div>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts-via-unsandboxed-popup.tentative.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts-via-unsandboxed-popup.tentative.html
new file mode 100644
index 0000000000..3c8c0b346a
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts-via-unsandboxed-popup.tentative.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+ <script>
+ async_test(t => {
+ let i = document.createElement('iframe');
+ i.sandbox = "allow-same-origin allow-popups allow-popups-to-escape-sandbox";
+ i.srcdoc = `<a target='_blank' rel='opener'
+ href="javascript:window.opener.top.postMessage('FAIL', '*');">Click me!</a>
+ <a target='_blank' rel='opener'
+ href="./resources/post-done-to-opener.html">Click me next!</a>`;
+
+ i.onload = _ => {
+ // Since the frame is sandboxed, but allow-same-origin, we can reach into it to grab the
+ // anchor element to click. We'll click the `javascript:` URL first, then pop up a new
+ // window that posts `DONE`.
+ //
+ // TODO(mkwst): This feels like a race, but it's one that we consistently win when I'm
+ // running the test locally 10,000 times. Good enough!™
+ i.contentDocument.body.querySelectorAll('a')[0].click();
+ i.contentDocument.body.querySelectorAll('a')[1].click();
+ };
+ document.body.appendChild(i);
+
+ window.addEventListener('message', t.step_func(e => {
+ assert_not_equals(e.data, "FAIL");
+ if (e.data == "DONE")
+ t.done();
+ }));
+ }, "Sandboxed => unsandboxed popup");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts.html
new file mode 100644
index 0000000000..1bc116ada4
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-disallow-scripts.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Script execution in sandbox iframe</title>
+ <link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
+ <link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Script execution in sandbox iframe</h1>
+ <script type="text/javascript">
+ var t = async_test("Running script from sandbox iframe is disallowed")
+ var called = 0;
+ function calledFromIframe() {
+ called++;
+ }
+ function loaded() {
+ assert_equals(called, 0);
+ t.done();
+ }
+ </script>
+
+ <iframe src="/html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox id="sandboxedframe" onload="loaded();"></iframe>
+
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open-mutation.window.js b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open-mutation.window.js
new file mode 100644
index 0000000000..713ca612c5
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open-mutation.window.js
@@ -0,0 +1,37 @@
+// Return whether the current context is sandboxed or not. The implementation do
+// not matter much, but might have to change over time depending on what side
+// effect sandbox flag have. Feel free to update as needed.
+const is_sandboxed = () => {
+ try {
+ document.domain = document.domain;
+ return "not sandboxed";
+ } catch (error) {
+ return "sandboxed";
+ }
+};
+
+promise_test(async test => {
+ const message = new Promise(r => window.addEventListener("message", r));
+
+ const iframe_unsandboxed = document.createElement("iframe");
+ document.body.appendChild(iframe_unsandboxed);
+
+ const iframe_sandboxed = document.createElement("iframe");
+ iframe_sandboxed.sandbox = "allow-same-origin allow-scripts";
+ document.body.appendChild(iframe_sandboxed);
+
+ iframe_sandboxed.srcdoc = `
+ <script>
+ parent.frames[0].document.write(\`
+ <script>
+ const is_sandboxed = ${is_sandboxed};
+ window.parent.postMessage(is_sandboxed(), '*');
+ </scr\`+\`ipt>
+ \`);
+ parent.frames[0].document.close();
+ </scr`+`ipt>
+ `;
+ assert_equals((await message).data, "not sandboxed");
+
+}, "Using document.open() against a document from a different window must not" +
+ " mutate the other window's sandbox flags");
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open.html
new file mode 100644
index 0000000000..3f754374ba
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-document-open.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>
+ Check sandbox-flags aren't lost after using document.open().
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+promise_test(async test => {
+ let message = new Promise(resolve =>
+ window.addEventListener("message", event => resolve(event.data))
+ );
+
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
+ iframe.setAttribute("src", "./resources/document-open.html")
+ document.body.appendChild(iframe);
+
+ assert_equals(await message, "document-domain-is-disallowed");
+}, "document.open()");
+
+promise_test(async test => {
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
+ iframe.setAttribute("src", "/common/blank.html");
+ let loaded = new Promise(resolve => iframe.onload = resolve);
+ document.body.appendChild(iframe);
+ await loaded;
+
+ let message = new Promise(resolve =>
+ window.addEventListener("message", event => resolve(event.data))
+ );
+
+ iframe.contentDocument.write(`
+ <script>
+ try {
+ document.domain = document.domain;
+ parent.postMessage('document-domain-is-allowed', '*');
+ } catch (error) {
+ parent.postMessage('document-domain-is-disallowed', '*');
+ }
+ </sc`+`ript>
+ `);
+
+ assert_equals(await message, "document-domain-is-disallowed");
+}, "other_document.open()");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-frame.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-frame.html
new file mode 100644
index 0000000000..ab87fce5e0
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-frame.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Inherit sandbox flags from the initiator's frame</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+// Check sandbox flags are properly inherited when a document initiate a
+// navigation inside another frame that it doesn't own directly.
+
+// This check the sandbox flags defined by the frame. See also the other test
+// about sandbox flags defined by the response (e.g. CSP sandbox):
+// => sandbox-inherited-from-initiators-response.html
+
+// Return a promise, resolving when |element| triggers |event_name| event.
+let future = (element, event_name) => {
+ return new Promise(resolve => {
+ element.addEventListener(event_name, event => resolve(event))
+ });
+};
+
+promise_test(async test => {
+ const iframe_1 = document.createElement("iframe");
+ const iframe_2 = document.createElement("iframe");
+
+ iframe_1.id = "iframe_1";
+ iframe_2.id = "iframe_2";
+
+ const iframe_1_script = encodeURI(`
+ <script>
+ try {
+ document.domain = document.domain;
+ parent.postMessage("not sandboxed", "*");
+ } catch (exception) {
+ parent.postMessage("sandboxed", "*");
+ }
+ </scr`+`ipt>
+ `);
+
+ const iframe_2_script = `
+ <script>
+ const iframe_1 = parent.document.querySelector("#iframe_1");
+ iframe_1.src = "data:text/html,${iframe_1_script}";
+ </scr`+`ipt>
+ `;
+
+ iframe_2.sandbox = "allow-scripts allow-same-origin";
+ iframe_2.srcdoc = iframe_2_script;
+
+ // Insert |iframe_1|. It will load the initial empty document, with no sandbox
+ // flags.
+ const iframe_1_load_1 = future(iframe_1, "load");
+ document.body.appendChild(iframe_1);
+ await iframe_1_load_1;
+
+ // Insert |iframe_2|. It will load with sandbox flags. It will make |iframe_1|
+ // to navigate toward a data-url, which should inherit the sandbox flags.
+ const iframe_1_reply = future(window, "message");
+ document.body.appendChild(iframe_2);
+ const result = await iframe_1_reply;
+
+ assert_equals("sandboxed", result.data);
+})
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-response.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-response.html
new file mode 100644
index 0000000000..638f1ba783
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-initiator-response.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Inherit sandbox flags from the initiator's response</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+// Check sandbox flags are properly inherited when a document initiate a
+// navigation inside another frame that it doesn't own directly.
+
+// This check the sandbox flags defined by the response (e.g. CSP sandbox). See
+// also the other test about sandbox flags inherited from the frame.
+// => sandbox-inherited-from-initiators-frame.html
+
+// Return a promise, resolving when |element| triggers |event_name| event.
+let future = (element, event_name) => {
+ return new Promise(resolve => {
+ element.addEventListener(event_name, event => resolve(event))
+ });
+};
+
+promise_test(async test => {
+ const iframe_1 = document.createElement("iframe");
+ const iframe_2 = document.createElement("iframe");
+
+ iframe_1.id = "iframe_1";
+ iframe_2.id = "iframe_2";
+
+ iframe_2.src =
+ "./resources/sandbox-inherited-from-initiator-response-helper.html";
+
+ // Insert |iframe_1|. It will load the initial empty document, with no sandbox
+ // flags.
+ const iframe_1_load_1 = future(iframe_1, "load");
+ document.body.appendChild(iframe_1);
+ await iframe_1_load_1;
+
+ // Insert |iframe_2|. It will load with sandbox flags. It will make |iframe_1|
+ // to navigate toward a data-url, which should inherit the sandbox flags.
+ const iframe_1_reply = future(window, "message");
+ document.body.appendChild(iframe_2);
+ const result = await iframe_1_reply;
+
+ assert_equals("sandboxed", result.data);
+})
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html
new file mode 100644
index 0000000000..04f485cc66
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Inherit sandbox from CSP embedded enforcement</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+<script>
+// Check sandbox flags are properly defined when its parent requires them and
+// the child allows it.
+
+const same_origin = get_host_info().HTTP_ORIGIN;
+const cross_origin = get_host_info().HTTP_REMOTE_ORIGIN;
+const check_sandbox_url =
+ "/html/browsers/sandboxing/resources/check-sandbox-flags.html?pipe=";
+const allow_csp_from_star = "|header(Allow-CSP-From,*)";
+
+// Return a promise, resolving when |element| triggers |event_name| event.
+const future = (element, event_name, source) => {
+ return new Promise(resolve => {
+ element.addEventListener(event_name, event => {
+ if (!source || source.contentWindow == event.source)
+ resolve(event)
+ })
+ });
+};
+
+const check_sandbox_script = `
+<script>
+ try {
+ document.domain = document.domain;
+ parent.postMessage("document-domain-is-allowed", "*");
+ } catch (exception) {
+ parent.postMessage("document-domain-is-disallowed", "*");
+ }
+</scr`+`ipt>
+`;
+
+const sandbox_policy = "sandbox allow-scripts allow-same-origin";
+
+// Test using the modern async/await primitives are easier to read/write.
+// However they run sequentially, contrary to async_test. This is the parallel
+// version, to avoid timing out.
+let promise_test_parallel = (promise, description) => {
+ async_test(test => {
+ promise(test)
+ .then(() => {test.done();})
+ .catch(test.step_func(error => { throw error; }));
+ }, description);
+};
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.csp = sandbox_policy;
+
+ // The <iframe> immediately hosts the initial empty document after being
+ // appended into the DOM. It will, as long as its 'src' isn't loaded. That's
+ // why a page do not load is being used.
+ iframe.src = "/fetch/api/resources/infinite-slow-response.py";
+ document.body.appendChild(iframe);
+
+ const iframe_reply = future(window, "message", iframe);
+ iframe.contentDocument.write(check_sandbox_script);
+ const result = await iframe_reply;
+ iframe.remove();
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "initial empty document");
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.src = "data:text/html,dummy";
+
+ const iframe_load_1 = future(iframe, "load");
+ document.body.appendChild(iframe);
+ await iframe_load_1;
+
+ const iframe_load_2 = future(iframe, "load");
+ iframe.csp = sandbox_policy;
+ iframe.src = "about:blank";
+ await iframe_load_2;
+
+ const iframe_reply = future(window, "message", iframe);
+ iframe.contentDocument.write(check_sandbox_script);
+ const result = await iframe_reply;
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "about:blank");
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.csp = sandbox_policy;
+ iframe.src =
+ `data:text/html,${encodeURI(check_sandbox_script)}`;
+
+ const iframe_reply = future(window, "message", iframe);
+ document.body.appendChild(iframe);
+ const result = await iframe_reply;
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "data-url");
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.csp = sandbox_policy;
+ iframe.srcdoc = check_sandbox_script;
+
+ const iframe_reply = future(window, "message", iframe);
+ document.body.appendChild(iframe);
+ const result = await iframe_reply;
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "srcdoc");
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.csp = sandbox_policy;
+
+ const blob = new Blob([check_sandbox_script], { type: "text/html" });
+
+ iframe.src = URL.createObjectURL(blob);
+
+ const iframe_reply = future(window, "message", iframe);
+ document.body.appendChild(iframe);
+ const result = await iframe_reply;
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "blob URL");
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.csp = sandbox_policy;
+ iframe.src = same_origin + check_sandbox_url + allow_csp_from_star;
+
+ const iframe_reply = future(window, "message", iframe);
+ document.body.appendChild(iframe);
+ const result = await iframe_reply;
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "same-origin");
+
+promise_test_parallel(async test => {
+ const iframe = document.createElement("iframe");
+ iframe.csp = sandbox_policy;
+ iframe.src = cross_origin + check_sandbox_url + allow_csp_from_star;
+
+ const iframe_reply = future(window, "message", iframe);
+ document.body.appendChild(iframe);
+ const result = await iframe_reply;
+
+ assert_equals(result.data, "document-domain-is-disallowed");
+}, "cross-origin");
+
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-initial-empty-document-toward-same-origin.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-initial-empty-document-toward-same-origin.html
new file mode 100644
index 0000000000..d1306c9703
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-initial-empty-document-toward-same-origin.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>
+ Check sandbox-flags inheritance in case of javascript window reuse.
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+promise_test(async test => {
+ let message = new Promise(resolve =>
+ window.addEventListener("message", event => resolve(event.data))
+ );
+
+ // Create an initial empty document in the iframe, sandboxed. It will attempt
+ // to load a slow page, but won't have time.
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
+ iframe.src = "/fetch/api/resources/infinite-slow-response.py";
+ document.body.appendChild(iframe);
+
+ // Remove sandbox flags. This should apply to documents committed from
+ // navigations started after this instruction.
+ iframe.removeAttribute("sandbox");
+ iframe.src = "./resources/check-sandbox-flags.html";
+
+ // The window is reused, but the new sandbox flags should be used.
+ assert_equals(await message, "document-domain-is-allowed");
+});
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-javascript-window-open.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-javascript-window-open.html
new file mode 100644
index 0000000000..fd21e9bb02
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-javascript-window-open.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>window.open in sandbox iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<script>
+promise_test(async test => {
+ let message = new Promise(resolve => {
+ window.addEventListener("message", event => resolve(event.data));
+ });
+ let iframe = document.createElement("iframe");
+ iframe.sandbox = "allow-scripts allow-popups allow-same-origin";
+ iframe.src = "./resources/sandbox-javascript-window-open.html";
+ document.body.appendChild(iframe);
+ assert_equals(await message, "disallow-document-domain");
+});
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing-iframe.tentative.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing-iframe.tentative.html
new file mode 100644
index 0000000000..43726e7720
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing-iframe.tentative.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+ let result;
+ try {
+ parent.document.getElementsByClassName('script');
+ result = 'iframe not sandboxed'
+ } catch (e) {
+ result = 'iframe sandboxed(' + e.message + ')';
+ }
+ window.onmessage = m => {
+ window.parent.postMessage({
+ result: result
+ }, '*');
+ };
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing.tentative.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing.tentative.html
new file mode 100644
index 0000000000..686f1c0c9f
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-navigation-timing.tentative.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Sandbox Navigation Timing</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<html></html>
+<script>
+ const sandboxUrl = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1) + 'sandbox-navigation-timing-iframe.tentative.html';
+ async_test(t => {
+ const iframe = document.createElement('iframe');
+ iframe.src = sandboxUrl;
+ document.body.appendChild(iframe); // Navigation starts; value of sandbox flags locked on.
+ // This should not affect the sandbox value used for both about:blank document
+ // and the final document in iframe.
+ iframe.sandbox = 'allow-scripts';
+ const iframeAboutBlankDocument = iframe.contentDocument;
+
+ iframe.onload = t.step_func(() => {
+ const iframeAboutBlankContents = iframeAboutBlankDocument.querySelectorAll('body');
+ assert_equals(iframeAboutBlankContents[0].tagName, "BODY",
+ "about:blank document's contents should still be accessible");
+
+ iframe.contentWindow.postMessage("is iframe sandboxed?", "*");
+ });
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.result, 'iframe not sandboxed');
+ });
+ }, 'setting sandbox attribute should not affect current document in iframe');
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context-iframe.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context-iframe.html
new file mode 100644
index 0000000000..801e78f9c0
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context-iframe.html
@@ -0,0 +1,5 @@
+<body>
+ <script>
+ Object.getPrototypeOf(document).changeFromSandboxedIframe = "change from sandboxed iframe";
+ </script>
+</body>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context.html
new file mode 100644
index 0000000000..dc1953aee6
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-new-execution-context.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Reuse of iframe about:blank document execution context</title>
+ <link rel="author" title="Dan Clark" href="mailto:daniec@microsoft.com">
+ <link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Reuse of iframe about:blank document execution context in sandbox="allow-scripts" iframe</h1>
+ <script type="text/javascript">
+ async_test(t => {
+ let iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ let iframeAboutBlankDocument = iframe.contentDocument;
+ assert_equals(iframeAboutBlankDocument.URL, "about:blank");
+
+ iframe.sandbox = "allow-scripts";
+ iframe.src = './sandbox-new-execution-context-iframe.html';
+
+ iframe.onload = t.step_func_done(() => {
+ assert_equals(iframe.contentDocument, null,
+ "New document in sandboxed iframe should have opaque origin");
+
+ assert_equals(Object.getPrototypeOf(iframeAboutBlankDocument).changeFromSandboxedIframe, undefined,
+ "Sandboxed iframe contents should not have been able to mess with type system of about:blank document");
+
+ let iframeAboutBlankContents = iframeAboutBlankDocument.querySelectorAll('body');
+ assert_equals(iframeAboutBlankContents[0].tagName, "BODY",
+ "about:blank document's contents should still be accessible");
+ });
+ },"iframe with sandbox should load with new execution context");
+ </script>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html
new file mode 100644
index 0000000000..9cf92768f7
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript-ref.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>noscript parsing when sandbox disables scripting</title>
+<iframe srcdoc="PASS" sandbox></iframe>
+<iframe srcdoc="PASS" sandbox></iframe>
+<iframe srcdoc="P<b>AS</b>S" sandbox></iframe>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript.html
new file mode 100644
index 0000000000..bb7ced0a14
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-parse-noscript.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>noscript parsing when sandbox disables scripting</title>
+<link rel=match href=/html/browsers/sandboxing/sandbox-parse-noscript-ref.html>
+<iframe srcdoc="<noscript>PASS</noscript>" sandbox></iframe>
+<iframe src="noscript-iframe.html" sandbox></iframe>
+<iframe srcdoc="<noscript>P<b>AS</b>S</noscript>" sandbox></iframe>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/sandbox-window-open-srcdoc.html b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-window-open-srcdoc.html
new file mode 100644
index 0000000000..6fbff6df82
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/sandbox-window-open-srcdoc.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>window.open("about:srcdoc") from a sandboxed iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+// Check what happens when executing window.open("about:srcdoc") from a
+// sandboxed iframe. Srcdoc can't be loaded in the main frame. It should
+// result in an error page. The error page should be cross-origin with the
+// opener.
+//
+// This test covers an interesting edge case. A main frame should inherit
+// sandbox flags. However the document loaded is an internal error page. This
+// might trigger some assertions, especially if the implementation wrongly
+// applies the sandbox flags of the opener to the internal error page document.
+//
+// This test is mainly a coverage test. It passes if it doesn't crash.
+async_test(test => {
+ let iframe = document.createElement("iframe");
+ iframe.sandbox = "allow-scripts allow-popups allow-same-origin";
+ iframe.srcdoc = `
+ <script>
+ let w = window.open();
+ onunload = () => w.close();
+
+ let notify = () => {
+ try {
+ w.origin; // Will fail after navigating to about:srcdoc.
+ parent.postMessage("pending", "*");
+ } catch (e) {
+ parent.postMessage("done", "*");
+ };
+ };
+
+ addEventListener("message", notify);
+ notify();
+
+ w.location = "about:srcdoc"; // Error page.
+ </scr`+`ipt>
+ `;
+
+ let closed = false;
+ addEventListener("message", event => {
+ closed = (event.data === "done");
+ iframe.contentWindow.postMessage("ping","*");
+ });
+
+ document.body.appendChild(iframe);
+ test.step_wait_func_done(()=>closed);
+}, "window.open('about:srcdoc') from sandboxed srcdoc doesn't crash.");
+</script>
diff --git a/testing/web-platform/tests/html/browsers/sandboxing/window-open-blank-from-different-initiator.html b/testing/web-platform/tests/html/browsers/sandboxing/window-open-blank-from-different-initiator.html
new file mode 100644
index 0000000000..91817c3db4
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/sandboxing/window-open-blank-from-different-initiator.html
@@ -0,0 +1,90 @@
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script>
+
+// This is a regression test for https://crbug.com/1170038.
+//
+// A document creates a popup and makes it navigate elsewhere. The navigation
+// will never commit. The popup has not completed any real load outside of the
+// initial empty document. Then from a different window with a different CSP
+// policy, make it navigate to about:blank.
+//
+// Web browser behavior might change depending on whether a pending navigation
+// exists for in the popup or not. Both are tested here.
+
+const same_origin = get_host_info().HTTP_ORIGIN;
+
+// Return a promise, resolving when |element| triggers |event_name| event.
+const future = (element, event_name) => {
+ return new Promise(resolve => element.addEventListener(event_name, resolve));
+};
+
+// `createNewPopup` is a function returning a new window that has not committed
+// any real load in its frame, outside of the initial empty document. The two
+// tests below vary depending on whether there is a pending navigation in the
+// frame or not.
+const runTest = (description, createNewPopup) => {
+ promise_test(async test => {
+ // Open a same-origin window with a different CSP.
+ const executor_path =
+ "/html/browsers/sandboxing/resources/execute-postmessage.html?pipe=";
+ const csp = "|header(Content-Security-Policy, " +
+ "sandbox" +
+ " allow-scripts" +
+ " allow-popups" +
+ " allow-same-origin" +
+ " allow-popups-to-escape-sandbox";
+ const executor = window.open(same_origin + executor_path + csp);
+ const executor_reply = await future(window, "message");
+ assert_equals(executor_reply.data, "ready");
+
+ const popup_name = token();
+ const popup = await createNewPopup(test, popup_name);
+
+ // Request the first real load from a DIFFERENT window with different CSPs.
+ const first_real_load = future(popup, "load");
+ executor.postMessage(`window.open("about:blank", "${popup_name}");`);
+ await first_real_load;
+
+ // The new blank document in the popup must inherit CSPs from |executor|:
+ let is_sandboxed = future(window, "message");
+ popup.document.write(`
+ <script>
+ try {
+ document.domain = document.domain;
+ opener.opener.postMessage("not sandboxed", "*");
+ } catch (error) {
+ opener.opener.postMessage("sandboxed", "*");
+ }
+ </scr`+`ipt>
+ `);
+ assert_equals((await is_sandboxed).data, "sandboxed");
+ }, description);
+}
+
+// Open a new window and start loading from an unresponsive server. The frame
+// will be left with the initial empty document and a pending navigation.
+runTest("One pending navigation", async (test, popup_name) => {
+ const unresponsive_path =
+ "/fetch/api/resources/infinite-slow-response.py";
+ return window.open(same_origin + unresponsive_path, popup_name);
+});
+
+// Open a new window and start loading. The response is a 204 and the navigation
+// is canceled. As a result, the frame will be left with the initial empty
+// document and NO pending navigation.
+runTest("No pending navigation", async (test, popup_name) => {
+ const no_content_path = "/common/blank.html?pipe=status(204)"
+ const popup = window.open(same_origin + no_content_path, popup_name);
+
+ // Unfortunately, there are no web API to detect a navigation has been
+ // canceled. Waiting using setTimeout is the only possible way to wait for it.
+ await new Promise(r => test.step_timeout(r, 1000));
+
+ return popup;
+});
+
+</script>