Reland "COEP WPT local scheme documents prevented from loading"

This includes a change that avoid the instability in the expectation.

Reland of https://chromium-review.googlesource.com/c/chromium/src/+/3367984

Original change's description:
> COEP WPT local scheme documents prevented from loading
>
> Add a test that asserts that local scheme documents inheriting a
> cross-origin-embedder-policy of none cannot load when embedded within
> an iframe that has a cross-origin-embedder-policy of require-corp.
>
> Bug: 1151223

Change-Id: I1e3915527a2e347fc6a287de85c91cd33af8568b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3368801
Auto-Submit: Pâris Meuleman <pmeuleman@chromium.org>
Reviewed-by: Arthur Hemery <ahemery@chromium.org>
Commit-Queue: Arthur Hemery <ahemery@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956074}
diff --git a/html/cross-origin-embedder-policy/block-local-documents-inheriting-none.https.html b/html/cross-origin-embedder-policy/block-local-documents-inheriting-none.https.html
new file mode 100644
index 0000000..ab645b7
--- /dev/null
+++ b/html/cross-origin-embedder-policy/block-local-documents-inheriting-none.https.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<div id=log></div>
+
+<script>
+const script = `
+    <script>
+      top.postMessage({event: "loaded", type: location.protocol}, "*");
+    <\/script>`;
+
+const test_cases = [
+    {name: "data", url: encodeURI(`data:text/html,${script}`)},
+    {name: "blob", url: URL.createObjectURL(new Blob([script], { type: "text/html" }))},
+    {name: "about", url: "about:blank"},
+  ];
+
+const observeReports = async (frame) => {
+  const reports = [];
+
+  const observer = new frame.contentWindow.ReportingObserver(
+    rs => reports.push(...rs.map(r => r.toJSON()))
+  );
+  observer.observe();
+
+  // Wait for reports. Use a timeout to catch both expected and unexpected
+  // reports.
+  await new Promise(resolve => step_timeout(resolve, 3000));
+  return reports;
+};
+
+promise_test(async t => {
+  const this_window_token = token();
+
+  // Expect the nested frame to not load, since they inherit COEP: none from the
+  // top frame, which is incompatible with first_frame's COEP: require-corp.
+  const received_events = [];
+  addEventListener("message", event => {
+    if(event.data.event == "loaded")
+      received_events.push(`Nested ${event.data.type} loaded!`);
+  });
+
+  // Create an iframe with COEP: require-corp
+  const first_iframe = document.createElement("iframe");
+  t.add_cleanup( () => first_iframe.remove() );
+  first_iframe.src = "/common/blank.html?pipe=header(cross-origin-embedder-policy,require-corp)";
+  let iframe_load_promise = new Promise( resolve => first_iframe.addEventListener("load", resolve) );
+
+  document.body.append(first_iframe);
+  await iframe_load_promise;
+
+  const reportPromise = observeReports(first_iframe);
+  // 1. Create nested frames.
+  // They initially navigate to blank.html and have COEP: require-corp set.
+  // This initial navigation is required because it uses the parent frame as the
+  // initiator. That is first_iframe is the initiator, while we want top to be
+  // the initiator for this test, which will be done in step 3 with a second
+  // navigation from that blank.html document to the local scheme one.
+  const nested_frames = {};
+  const nested_frames_promises = [];
+  test_cases.forEach(test => {
+    nested_frame = document.createElement("iframe");
+    nested_frame.src = "/common/blank.html?pipe=header(cross-origin-embedder-policy,require-corp)";
+    t.add_cleanup( () => nested_frame.remove() );
+    nested_frames_promises.push(new Promise( resolve => nested_frame.addEventListener("load", resolve) ) );
+    first_iframe.contentDocument.body.append(nested_frame);
+    nested_frames[test.name] = nested_frame;
+  });
+
+  // 2. Wait for the loads of all iframes to complete.
+  await Promise.all(nested_frames_promises);
+
+  // 3. Navigate nested frames to a local scheme document.
+  // COEP should be inherited from the initiator or blobURL's creator (top in both
+  // cases), this results in COEP being none and the documents not being allowed
+  // to load under the COEP: require-corp iframe (first_iframe).
+  test_cases.forEach(test => {
+    // Top navigates nested_frame_[test.name] to a test.url
+    const frame = nested_frames[test.name];
+    // Use frame.contentDocument.location to ensure the initiator is this (top)
+    // frame. frame.src is not used here as this makes the parent of the nested
+    // frame (first_iframe) the initiator.
+    frame.contentDocument.location = test.url;
+  });
+
+  // 4. Wait and validate reports.
+  const reports = await reportPromise;
+  assert_equals(reports.length, test_cases.length);
+  test_cases.forEach(test => {
+    assert_true(reports.some( report => {
+      return report.type == 'coep' &&
+      report.body.type == 'navigation' &&
+      report.body.blockedURL == test.url;
+    }), `No report matched for test "${test.name}"`);
+  });
+  // Also verify that no message was sent by the nested frames and stored in
+  // received_events.
+  assert_equals([], received_events.sort());
+}, "Prevent local scheme documents from loading within a COEP: require-corp iframe if they inherit COEP: none");
+</script>