Make the COEP:Credentialless check ignores the subdocument request if it's a redirect

We shouldn't block the iframe if the initial request doesn't have valid
headers, we should only check the final request.

Differential Revision: https://phabricator.services.mozilla.com/D180485

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1837585
gecko-commit: f1fb26526a2e8e7d9539b3f975817b0578e1bc0c
gecko-reviewers: valentin, necko-reviewers
diff --git a/html/cross-origin-embedder-policy/credentialless/iframe-coep-redirect.https.window.js b/html/cross-origin-embedder-policy/credentialless/iframe-coep-redirect.https.window.js
new file mode 100644
index 0000000..a9f6a1c
--- /dev/null
+++ b/html/cross-origin-embedder-policy/credentialless/iframe-coep-redirect.https.window.js
@@ -0,0 +1,41 @@
+// META: variant=?1-4
+// META: variant=?5-last
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=./resources/common.js
+// META: script=./resources/iframeTest.js
+promise_test(async test => {
+  const test_token = token();
+  const child_token = token();
+
+  const redirecting_child_url = cross_origin + "/common/dispatcher/executor.html?uuid=" + child_token;
+
+  const child_url =
+    same_origin +
+    "/html/cross-origin-embedder-policy/credentialless/resources/redirect_none_to_credentialless.py?redirectTo=" + redirecting_child_url;
+
+  await send(newWindow(coep_credentialless), `
+    let iframe = document.createElement("iframe");
+    iframe.src = "${child_url}";
+    document.body.appendChild(iframe);
+  `);
+
+  await 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
+  // Use a shorter timeout when it is expected to be reached.
+  // - The long delay reduces the false-positive rate. False-positive causes
+  //   stability problems on bot, so a big delay is used to vanish them.
+  //   https://crbug.com/1215956.
+  // - The short delay avoids delaying too much the test(s) for nothing and
+  //   timing out. False-negative are not a problem, they just need not to
+  //   overwhelm the true-negative, which is trivial to get.
+  step_timeout(()=>send(test_token, "block"), 6000);
+
+  assert_equals(await receive(test_token), EXPECT_LOAD);
+});
diff --git a/html/cross-origin-embedder-policy/credentialless/resources/redirect_none_to_credentialless.py b/html/cross-origin-embedder-policy/credentialless/resources/redirect_none_to_credentialless.py
new file mode 100644
index 0000000..7f0c35e
--- /dev/null
+++ b/html/cross-origin-embedder-policy/credentialless/resources/redirect_none_to_credentialless.py
@@ -0,0 +1,14 @@
+COEP_HEADER = b"|header(cross-origin-embedder-policy, credentialless)"
+CORP_HEADER = b"|header(cross-origin-resource-policy, cross-origin)"
+
+def main(request, response):
+    """
+    Causes a redirection that the initial response doesn't have credentialless and the
+    redirected response has credentialless.
+    """
+    response.status = 302
+
+    location = \
+        request.GET[b'redirectTo'] + b"&pipe=" + COEP_HEADER + CORP_HEADER
+
+    response.headers.set(b"Location", location)