Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!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>
<script type="application/javascript">
"use strict";
function promiseMessage(source, filter = () => 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>