[Credentialless] WPT <iframe>
Add one WPT test about <iframe>.
A few parameters can vary:
- Parent is COEP:{none,credentialless,require-corp}
- Child is COEP:{none,credentialless,require-corp}
- Child is CORP:{undefined, cross-origin}
- Child is {same-origin,cross-origin} with its parent.
Depending on all of those, the iframe must be blocked or must loaded.
Bug: 1175099
Change-Id: I6f60cac9211afdecf9969050efb5e4598cc1052e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2709861
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Camille Lamy <clamy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#857616}
diff --git a/html/cross-origin-embedder-policy/credentialless/iframe-coep-credentialless.tentative.https.html b/html/cross-origin-embedder-policy/credentialless/iframe-coep-credentialless.tentative.https.html
new file mode 100644
index 0000000..85d2be9
--- /dev/null
+++ b/html/cross-origin-embedder-policy/credentialless/iframe-coep-credentialless.tentative.https.html
@@ -0,0 +1,39 @@
+<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 src="./resources/common.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script src="./resources/iframeTest.js"></script>
+
+<script>
+
+const parent_coep_credentialless = newWindow(coep_credentialless);
+iframeTest("COEP:credentialless embeds same-origin COEP:none",
+ parent_coep_credentialless, same_origin, coep_none, EXPECT_BLOCK);
+iframeTest("COEP:credentialless embeds cross-origin COEP:none",
+ parent_coep_credentialless, cross_origin, coep_none, EXPECT_BLOCK);
+iframeTest("COEP:credentialless embeds same-origin COEP:credentialless",
+ parent_coep_credentialless, same_origin, coep_credentialless, EXPECT_LOAD);
+iframeTest("COEP:credentialless embeds cross-origin COEP:credentialless",
+ parent_coep_credentialless, cross_origin, coep_credentialless, EXPECT_BLOCK);
+iframeTest("COEP:credentialless embeds same-origin COEP:require-corp",
+ parent_coep_credentialless, same_origin, coep_require_corp, EXPECT_LOAD);
+iframeTest("COEP:credentialless embeds cross-origin COEP:require-corp",
+ parent_coep_credentialless, cross_origin, coep_require_corp, EXPECT_BLOCK);
+
+// Using CORP:cross-origin might unblock previously blocked iframes.
+iframeTestCORP("COEP:credentialless embeds same-origin COEP:none",
+ parent_coep_credentialless, same_origin, coep_none, EXPECT_BLOCK);
+iframeTestCORP("COEP:credentialless embeds cross-origin COEP:none",
+ parent_coep_credentialless, cross_origin, coep_none, EXPECT_BLOCK);
+iframeTestCORP("COEP:credentialless embeds same-origin COEP:credentialless",
+ parent_coep_credentialless, same_origin, coep_credentialless, EXPECT_LOAD);
+iframeTestCORP("COEP:credentialless embeds cross-origin COEP:credentialless",
+ parent_coep_credentialless, cross_origin, coep_credentialless, EXPECT_LOAD);
+iframeTestCORP("COEP:credentialless embeds same-origin COEP:require-corp",
+ parent_coep_credentialless, same_origin, coep_require_corp, EXPECT_LOAD);
+iframeTestCORP("COEP:credentialless embeds cross-origin COEP:require-corp",
+ parent_coep_credentialless, cross_origin, coep_require_corp, EXPECT_LOAD);
+
+</script>
diff --git a/html/cross-origin-embedder-policy/credentialless/iframe-coep-none.tentative.https.html b/html/cross-origin-embedder-policy/credentialless/iframe-coep-none.tentative.https.html
new file mode 100644
index 0000000..ad28c3a
--- /dev/null
+++ b/html/cross-origin-embedder-policy/credentialless/iframe-coep-none.tentative.https.html
@@ -0,0 +1,25 @@
+<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 src="./resources/common.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script src="./resources/iframeTest.js"></script>
+
+<script>
+
+const parent_coep_none = newWindow(coep_none);
+iframeTest("COEP:none embeds same-origin COEP:none",
+ parent_coep_none, same_origin, coep_none, EXPECT_LOAD);
+iframeTest("COEP:none embeds cross-origin COEP:none",
+ parent_coep_none, cross_origin, coep_none, EXPECT_LOAD);
+iframeTest("COEP:none embeds same-origin COEP:credentialless",
+ parent_coep_none, same_origin, coep_credentialless, EXPECT_LOAD);
+iframeTest("COEP:none embeds cross-origin COEP:credentialless",
+ parent_coep_none, cross_origin, coep_credentialless, EXPECT_LOAD);
+iframeTest("COEP:none embeds same-origin COEP:require-corp",
+ parent_coep_none, same_origin, coep_require_corp, EXPECT_LOAD);
+iframeTest("COEP:none embeds cross-origin COEP:require-corp",
+ parent_coep_none, cross_origin, coep_require_corp, EXPECT_LOAD);
+
+</script>
diff --git a/html/cross-origin-embedder-policy/credentialless/iframe-coep-require-corp.tentative.https.html b/html/cross-origin-embedder-policy/credentialless/iframe-coep-require-corp.tentative.https.html
new file mode 100644
index 0000000..cb86ff2
--- /dev/null
+++ b/html/cross-origin-embedder-policy/credentialless/iframe-coep-require-corp.tentative.https.html
@@ -0,0 +1,39 @@
+<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 src="./resources/common.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script src="./resources/iframeTest.js"></script>
+
+<script>
+
+const parent_coep_require_corp = newWindow(coep_require_corp);
+iframeTest("COEP:require-corp embeds same-origin COEP:none",
+ parent_coep_require_corp, same_origin, coep_none, EXPECT_BLOCK);
+iframeTest("COEP:require-corp embeds cross-origin COEP:none",
+ parent_coep_require_corp, cross_origin, coep_none, EXPECT_BLOCK);
+iframeTest("COEP:require-corp embeds same-origin COEP:credentialless",
+ parent_coep_require_corp, same_origin, coep_credentialless, EXPECT_BLOCK);
+iframeTest("COEP:require-corp embeds cross-origin COEP:credentialless",
+ parent_coep_require_corp, cross_origin, coep_credentialless, EXPECT_BLOCK);
+iframeTest("COEP:require-corp embeds same-origin COEP:require-corp",
+ parent_coep_require_corp, same_origin, coep_require_corp, EXPECT_LOAD);
+iframeTest("COEP:require-corp embeds cross-origin COEP:require-corp",
+ parent_coep_require_corp, cross_origin, coep_require_corp, EXPECT_BLOCK);
+
+// Using CORP:cross-origin might unblock previously blocked iframes.
+iframeTestCORP("COEP:require-corp embeds same-origin COEP:none",
+ parent_coep_require_corp, same_origin, coep_none, EXPECT_BLOCK);
+iframeTestCORP("COEP:require-corp embeds cross-origin COEP:none",
+ parent_coep_require_corp, cross_origin, coep_none, EXPECT_BLOCK);
+iframeTestCORP("COEP:require-corp embeds same-origin COEP:credentialless",
+ parent_coep_require_corp, same_origin, coep_credentialless, EXPECT_BLOCK);
+iframeTestCORP("COEP:require-corp embeds cross-origin COEP:credentialless",
+ parent_coep_require_corp, cross_origin, coep_credentialless, EXPECT_BLOCK);
+iframeTestCORP("COEP:require-corp embeds same-origin COEP:require-corp",
+ parent_coep_require_corp, same_origin, coep_require_corp, EXPECT_LOAD);
+iframeTestCORP("COEP:require-corp embeds cross-origin COEP:require-corp",
+ parent_coep_require_corp, cross_origin, coep_require_corp, EXPECT_LOAD);
+
+</script>
diff --git a/html/cross-origin-embedder-policy/credentialless/resources/common.js b/html/cross-origin-embedder-policy/credentialless/resources/common.js
index be6bb0e..45fd935 100644
--- a/html/cross-origin-embedder-policy/credentialless/resources/common.js
+++ b/html/cross-origin-embedder-policy/credentialless/resources/common.js
@@ -1,9 +1,21 @@
const directory = '/html/cross-origin-embedder-policy/credentialless';
-
const executor_path = directory + '/resources/executor.html?pipe=';
-const coep_none = '|header(Cross-Origin-Embedder-Policy,none)';
+
+// COEP
+const coep_none =
+ '|header(Cross-Origin-Embedder-Policy,none)';
const coep_credentialless =
'|header(Cross-Origin-Embedder-Policy,credentialless)';
+const coep_require_corp =
+ '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+// COOP
+const coop_same_origin =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+
+// CORP
+const corp_cross_origin =
+ '|header(Cross-Origin-Resource-Policy,cross-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
diff --git a/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js b/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js
index d1fd1b6..ed0e1ce 100644
--- a/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js
+++ b/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js
@@ -4,10 +4,28 @@
"/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.py";
const dispatcher_url = new URL(dispatcher_path, location.href).href;
+// Return a promise, limiting the number of concurrent accesses to a shared
+// resources to |max_concurrent_access|.
+const concurrencyLimiter = (max_concurrency) => {
+ let pending = 0;
+ let waiting = [];
+ return async (task) => {
+ pending++;
+ if (pending > max_concurrency)
+ await new Promise(resolve => waiting.push(resolve));
+ await task();
+ pending--;
+ waiting.shift()?.();
+ };
+}
+
+// The official web-platform-test runner sometimes drop POST requests when
+// too many are requested in parallel. Limiting this document to send only one
+// at a time fixes the issue.
+const sendLimiter = concurrencyLimiter(1);
+
const send = async function(uuid, message) {
- // The official web-platform-test runner sometimes drop POST requests when
- // many are requested in parallel. Using a lock fixes the issue.
- await navigator.locks.request("dispatcher_send", async lock => {
+ await sendLimiter(async () => {
await fetch(dispatcher_url + `?uuid=${uuid}`, {
method: 'POST',
body: message
diff --git a/html/cross-origin-embedder-policy/credentialless/resources/iframeTest.js b/html/cross-origin-embedder-policy/credentialless/resources/iframeTest.js
new file mode 100644
index 0000000..1e3038e
--- /dev/null
+++ b/html/cross-origin-embedder-policy/credentialless/resources/iframeTest.js
@@ -0,0 +1,75 @@
+// One document embeds another in an iframe. Both are loaded from the network.
+// Depending on the response headers:
+// - Cross-Origin-Embedder-Policy (COEP)
+// - Cross-Origin-Resource-Policy (CORP)
+// The child must load or must be blocked.
+//
+// What to do for:
+// - COEP:credentialless
+// - COEP:credentialless-on-children
+// is currently an active open question. This test will be updated/completed
+// later.
+
+// There are no interoperable ways to check an iframe failed to load. So a
+// timeout is being used. See https://github.com/whatwg/html/issues/125
+// Moreover, we want to track progress, managing timeout explicitly allows to
+// get a per-test results, even in case of failure of one.
+setup({ explicit_timeout: true });
+
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+// Open a new window loaded with the given |headers|. The new document will
+// execute any script sent toward the token it returns.
+const newWindow = (headers) => {
+ const executor_token = token();
+ const url = same_origin + executor_path + headers + `&uuid=${executor_token}`;
+ const w = window.open(url);
+ add_completion_callback(() => w.close());
+ return executor_token;
+};
+
+const EXPECT_LOAD = "load";
+const EXPECT_BLOCK = "block";
+
+// Load in iframe. Control both the parent and the child headers. Check whether
+// it loads or not.
+const iframeTest = function(
+ description,
+ parent_token,
+ child_origin,
+ child_headers,
+ expectation
+) {
+ promise_test_parallel(async test => {
+ const test_token = token();
+
+ const child_token = token();
+ const child_url = child_origin + executor_path + child_headers +
+ `&uuid=${child_token}`;
+
+ send(parent_token, `
+ let iframe = document.createElement("iframe");
+ iframe.src = "${child_url}";
+ document.body.appendChild(iframe);
+ `);
+
+ send(child_token, `
+ send("${test_token}", "load");
+ `);
+
+ // There are no interoperable ways to check an iframe failed to load. So a
+ // timeout is being used.
+ // See https://github.com/whatwg/html/issues/125
+ step_timeout(()=>send(test_token, "block"), 3000);
+
+ assert_equals(await receive(test_token), expectation);
+ }, description);
+}
+
+// A decorated version of iframeTest, adding CORP:cross-origin to the child.
+const iframeTestCORP = function() {
+ arguments[0] += ", CORP:cross-origin"; // description
+ arguments[3] += corp_cross_origin; // child_headers
+ iframeTest(...arguments);
+}