112 lines
4.6 KiB
HTML
112 lines
4.6 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<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>
|
|
<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 4 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 a dummy frame. This is required because some browsers (Chrome)
|
|
// might consider the first navigation in 4. as a redirect otherwise.
|
|
const dummy_Frame = document.createElement("iframe");
|
|
t.add_cleanup( () => dummy_Frame.remove() );
|
|
dummy_Frame.src = "/common/blank.html";
|
|
iframe_load_promise = new Promise( resolve => dummy_Frame.addEventListener("load", resolve) );
|
|
document.body.append(dummy_Frame);
|
|
await iframe_load_promise;
|
|
|
|
// 4. 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;
|
|
});
|
|
|
|
// 5. 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.length, 0);
|
|
}, "Prevent local scheme documents from loading within a COEP: require-corp iframe if they inherit COEP: none");
|
|
</script>
|