summaryrefslogtreecommitdiffstats
path: root/docshell/test/mochitest/test_content_javascript_loads.html
diff options
context:
space:
mode:
Diffstat (limited to 'docshell/test/mochitest/test_content_javascript_loads.html')
-rw-r--r--docshell/test/mochitest/test_content_javascript_loads.html163
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>