diff options
Diffstat (limited to 'docshell/test/mochitest/test_content_javascript_loads.html')
-rw-r--r-- | docshell/test/mochitest/test_content_javascript_loads.html | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/docshell/test/mochitest/test_content_javascript_loads.html b/docshell/test/mochitest/test_content_javascript_loads.html new file mode 100644 index 0000000000..eabc1d314e --- /dev/null +++ b/docshell/test/mochitest/test_content_javascript_loads.html @@ -0,0 +1,163 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for Bug 1647519</title> + <meta charset="utf-8"> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1647519">Mozilla Bug 1647519</a> + +<script type="application/javascript"> +"use strict"; + +function promiseMessage(source, filter = event => true) { + return new Promise(resolve => { + function listener(event) { + if (event.source == source && filter(event)) { + window.removeEventListener("message", listener); + resolve(event); + } + } + window.addEventListener("message", listener); + }); +} + +async function runTests(resourcePath) { + /* globals Assert, content */ + let doc = content.document; + + // Sends a message to the given target window and waits for a response a few + // times to (more or less) ensure that a `javascript:` load request has had + // time to succeed, if it were going to. + async function doSomeRoundTrips(target) { + for (let i = 0; i < 3; i++) { + // Note: The ping message needs to be sent from a script running in the + // content scope or there will be no source window for the reply to be + // sent to. + await content.wrappedJSObject.ping(target); + } + } + + function promiseEvent(target, name) { + return new Promise(resolve => { + target.addEventListener(name, resolve, { once: true }); + }); + } + + function createIframe(host, id) { + let iframe = doc.createElement("iframe"); + iframe.id = id; + iframe.name = id; + iframe.src = `https://${host}${resourcePath}file_content_javascript_loads_frame.html`; + doc.body.appendChild(iframe); + return promiseEvent(iframe, "load"); + } + + const ID_SAME_ORIGIN = "frame-same-origin"; + const ID_SAME_BASE_DOMAIN = "frame-same-base-domain"; + const ID_CROSS_BASE_DOMAIN = "frame-cross-base-domain"; + + await Promise.all([ + createIframe("example.com", ID_SAME_ORIGIN), + createIframe("test1.example.com", ID_SAME_BASE_DOMAIN), + createIframe("example.org", ID_CROSS_BASE_DOMAIN), + ]); + + let gotJSLoadFrom = null; + let pendingJSLoadID = null; + content.addEventListener("message", event => { + if ("javascriptLoadID" in event.data) { + Assert.equal( + event.data.javascriptLoadID, + pendingJSLoadID, + "Message from javascript: load should have the expected ID" + ); + Assert.equal( + gotJSLoadFrom, + null, + "Should not have seen a previous load message this cycle" + ); + gotJSLoadFrom = event.source.name; + } + }); + + async function watchForJSLoads(frameName, expected, task) { + let loadId = Math.random(); + + let jsURI = + "javascript:" + + encodeURI(`parent.postMessage({ javascriptLoadID: ${loadId} }, "*")`); + + pendingJSLoadID = loadId; + gotJSLoadFrom = null; + + await task(jsURI); + + await doSomeRoundTrips(content.wrappedJSObject[frameName]); + + if (expected) { + Assert.equal( + gotJSLoadFrom, + frameName, + `Should have seen javascript: URI loaded into ${frameName}` + ); + } else { + Assert.equal( + gotJSLoadFrom, + null, + "Should not have seen javascript: URI loaded" + ); + } + } + + let frames = [ + { name: ID_SAME_ORIGIN, expectLoad: true }, + { name: ID_SAME_BASE_DOMAIN, expectLoad: false }, + { name: ID_CROSS_BASE_DOMAIN, expectLoad: false }, + ]; + for (let { name, expectLoad } of frames) { + info(`Checking loads for frame "${name}". Expecting loads: ${expectLoad}`); + + info("Checking location setter"); + await watchForJSLoads(name, expectLoad, jsURI => { + // Note: We need to do this from the content scope since security checks + // depend on the JS caller scope. + content.wrappedJSObject.setFrameLocation(name, jsURI); + }); + + info("Checking targeted <a> load"); + await watchForJSLoads(name, expectLoad, jsURI => { + let a = doc.createElement("a"); + a.target = name; + a.href = jsURI; + doc.body.appendChild(a); + a.click(); + a.remove(); + }); + + info("Checking targeted window.open load"); + await watchForJSLoads(name, expectLoad, jsURI => { + content.wrappedJSObject.open(jsURI, name); + }); + } +} + +add_task(async function() { + const resourcePath = location.pathname.replace(/[^\/]+$/, ""); + + let win = window.open( + `https://example.com${resourcePath}file_content_javascript_loads_root.html` + ); + await promiseMessage(win, event => event.data == "ready"); + + await SpecialPowers.spawn(win, [resourcePath], runTests); + + win.close(); +}); +</script> + +</body> +</html> |