<!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>