diff options
Diffstat (limited to 'testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html')
-rw-r--r-- | testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html new file mode 100644 index 0000000000..8ebb3ccd4a --- /dev/null +++ b/testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html @@ -0,0 +1,199 @@ +<!DOCTYPE html> +<title>Cross-Origin-Opener-Policy and a "javascript:" URL popup</title> +<meta charset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?1-2"> +<meta name="variant" content="?3-4"> +<meta name="variant" content="?5-6"> +<meta name="variant" content="?7-8"> +<meta name="variant" content="?9-10"> +<meta name="variant" content="?11-12"> +<meta name="variant" content="?13-14"> +<meta name="variant" content="?15-16"> +<meta name="variant" content="?17-last"> +<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/subset-tests.js"></script> +<script src="/common/utils.js"></script> +<script src="resources/common.js"></script> + +<p>According to HTML's navigate algorithm, requests to <code>javascript:</code> +URLs should inherit the cross-origin opener policy of the active document. To +observe this, each subtest uses the following procedure.</p> + +<ol> + <li>create popup with a given COOP (the <code>parentCOOP</code>)</li> + <li>navigate the popup to a <code>javascript:</code> URL (the new document is + expected to inherit the <code>parentCOOP</code>)</li> + <li>from the popup, create a second popup window with a given COOP (the + <code>childCOOP</code>)</li> +</ol> + +<p>Both popup windows inspect state and report back to the test.</p> + +<pre> + .---- test ----. + | open(https:) | + | parentCOOP | .----- subject -------. + | '---------> | --------. | + | | | v | + | | | assign(javascript:) | + | | | (COOP under test) | + | | | | | + | | | open(https:) | + | | | childCOOP | .- child -. + | | | '--------------> | | + | | '---------------------' '---------' + | | | | + | validate | <--status---+---------------------' + '--------------' +</pre> + +<script> +'use strict'; + +function getExecutorPath(uuid, origin, coopHeader) { + const executorPath = '/common/dispatcher/executor.html?'; + const coopHeaderPipe = + `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(coopHeader)})`; + return origin + executorPath + `uuid=${uuid}` + '&pipe=' + coopHeaderPipe; +} + +function assert_isolated(results) { + assert_equals(results.childName, '', 'child name'); + assert_false(results.childOpener, 'child opener'); + // The test subject's reference to the "child" window must report "closed" + // when COOP enforces isolation because the document initially created during + // the window open steps must be discarded when a new document object is + // created at the end of the navigation. + assert_true(results.childClosed, 'child closed'); +} + +function assert_not_isolated(results, expectedName) { + assert_equals(results.childName, expectedName, 'child name'); + assert_true(results.childOpener, 'child opener'); + assert_false(results.childClosed, 'child closed'); +} + +async function javascript_url_test(parentCOOP, childCOOP, origin, resultsVerification) { + promise_test(async t => { + const parentToken = token(); + const childToken = token(); + const responseToken = token(); + + const parentURL = getExecutorPath( + parentToken, + SAME_ORIGIN.origin, + parentCOOP); + const childURL = getExecutorPath( + childToken, + origin.origin, + childCOOP); + + // Open a first popup, referred to as the parent popup, and wait for it to + // load. + window.open(parentURL); + send(parentToken, `send('${responseToken}', 'Done loading');`); + assert_equals(await receive(responseToken), 'Done loading'); + + // Make sure the parent popup is removed once the test has run, keeping a + // clean state. + add_completion_callback(() => { + send(parentToken, 'close'); + }); + + // Navigate the popup to the javascript URL. It should inherit the current + // document's COOP. Because we're navigating to a page that is not an + // executor, we lose access to easy messaging, making things a bit more + // complicated. We use a predetermined scenario of communication that + // enables us to retrieve whether the child popup appears closed from the + // parent popup. + // + // Notes: + // - Splitting the script tag prevents HTML parsing to kick in. + // - The innermost double quotes need a triple backslash, because it goes + // through two rounds of consuming escape characters (\\\" -> \" -> "). + // - The javascript URL does not accept \n characters so we need to use + // a new template literal for each line. + send(parentToken, + `location.assign("javascript:'` + + // Include dispatcher.js to have access to send() and receive(). + `<script src=\\\"/common/dispatcher/dispatcher.js\\\"></scr` + `ipt>` + + `<script> (async () => {` + + + // Open the child popup and keep a handle to it. + `const w = open(\\\"${childURL}\\\", \\\"${childToken}\\\");` + + + // We wait for the main frame to query the w.closed property. + `await receive(\\\"${parentToken}\\\");` + + `send(\\\"${responseToken}\\\", w.closed);` + + + // Finally we wait for the cleanup indicating that this popup can be + // closed. + `await receive(\\\"${parentToken}\\\");` + + `close();` + + `})()</scr` + `ipt>'");` + ); + + // Make sure the javascript navigation ran, and the child popup was created. + send(childToken, `send('${responseToken}', 'Done loading');`); + assert_equals(await receive(responseToken), 'Done loading'); + + // Make sure the child popup is removed once the test has run, keeping a + // clean state. + add_completion_callback(() => { + send(childToken, `close()`); + }); + + // Give some time for things to settle across processes etc. before + // proceeding with verifications. + await new Promise(resolve => { t.step_timeout(resolve, 500); }); + + // Gather information about the child popup and verify that they match what + // we expect. + const results = {}; + send(parentToken, 'query'); + results.childClosed = await receive(responseToken) === 'true'; + + send(childToken, `send('${responseToken}', opener != null);`); + results.childOpener = await receive(responseToken) === 'true'; + + send(childToken, `send('${responseToken}', name);`); + results.childName = await receive(responseToken); + + resultsVerification(results, childToken); + }, `navigation: ${origin.name}; ` + `parentCOOP: ${parentCOOP}; ` + + `childCOOP: ${childCOOP}`); +} + +const tests = [ + ['unsafe-none', 'unsafe-none', SAME_ORIGIN, assert_not_isolated], + ['unsafe-none', 'unsafe-none', SAME_SITE, assert_not_isolated], + ['unsafe-none', 'same-origin-allow-popups', SAME_ORIGIN, assert_isolated], + ['unsafe-none', 'same-origin-allow-popups', SAME_SITE, assert_isolated], + ['unsafe-none', 'same-origin', SAME_ORIGIN, assert_isolated], + ['unsafe-none', 'same-origin', SAME_SITE, assert_isolated], + ['same-origin-allow-popups', 'unsafe-none', SAME_ORIGIN, assert_not_isolated], + ['same-origin-allow-popups', 'unsafe-none', SAME_SITE, assert_not_isolated], + ['same-origin-allow-popups', 'same-origin-allow-popups', SAME_ORIGIN, assert_not_isolated], + ['same-origin-allow-popups', 'same-origin-allow-popups', SAME_SITE, assert_isolated], + ['same-origin-allow-popups', 'same-origin', SAME_ORIGIN, assert_isolated], + ['same-origin-allow-popups', 'same-origin', SAME_SITE, assert_isolated], + ['same-origin', 'unsafe-none', SAME_ORIGIN, assert_isolated], + ['same-origin', 'unsafe-none', SAME_SITE, assert_isolated], + ['same-origin', 'same-origin-allow-popups', SAME_ORIGIN, assert_isolated], + ['same-origin', 'same-origin-allow-popups', SAME_SITE, assert_isolated], + ['same-origin', 'same-origin', SAME_ORIGIN, assert_not_isolated], + ['same-origin', 'same-origin', SAME_SITE, assert_isolated], +].forEach(([parentCOOP, childCOOP, origin, expectation]) => { + subsetTest( + javascript_url_test, + parentCOOP, + childCOOP, + origin, + expectation); +}); + +</script> |