Source code

Revision control

Copy as Markdown

Other Tools

"use strict";
/**
* Helper script for mixed content testing. It opens a new top-level window
* from a secure origin and '?runtest' query. That tells us to run the test
* body, function runTest(). Then we wait for call of finish(). On its first
* call it loads helper page 'backward.html' that immediately navigates
* back to the test secure test. This checks the bfcache. We got second call
* to onload and this time we call afterNavigationTest() function to let the
* test check security state after re-navigation back. Then we again wait for
* finish() call, that this time finishes completelly the test.
*/
// Tells the framework if to load the test in an insecure page (http://)
var loadAsInsecure = false;
// Set true to bypass the navigation forward/back test
var bypassNavigationTest = false;
// Set true to do forward/back navigation over an http:// page, test state leaks
var navigateToInsecure = false;
// Open the test in two separate windows, test requests sharing among windows
var openTwoWindows = false;
// Override the name of the test page to load, useful e.g. to prevent load
// of images or other content before the test starts; this is actually
// a 'redirect' to a different test page.
var testPage = "";
// Assign a function to this variable to have a clean up at the end
var testCleanUp = null;
// Contains mixed active content that needs to load to run the test
var hasMixedActiveContent = false;
// Internal variables
var _windowCount = 0;
window.onload = async function onLoad() {
if (location.search == "?runtest") {
try {
if (history.length == 1) {
// Each test that includes this helper file is supposed to define
// runTest(). See the top level comment.
await runTest(); // eslint-disable-line no-undef
} else {
// Each test that includes this helper file is supposed to define
// afterNavigationTest(). See the top level comment.
await afterNavigationTest(); // eslint-disable-line no-undef
}
} catch (ex) {
ok(false, "Exception thrown during test: " + ex);
finish();
}
} else {
window.addEventListener("message", onMessageReceived);
let secureTestLocation = loadAsInsecure
secureTestLocation += location.pathname;
if (testPage != "") {
let array = secureTestLocation.split("/");
array.pop();
array.push(testPage);
secureTestLocation = array.join("/");
}
secureTestLocation += "?runtest";
if (hasMixedActiveContent) {
SpecialPowers.pushPrefEnv(
{ set: [["security.mixed_content.block_active_content", false]] },
null
);
}
if (openTwoWindows) {
_windowCount = 2;
window.open(secureTestLocation, "_new1", "");
window.open(secureTestLocation, "_new2", "");
} else {
_windowCount = 1;
window.open(secureTestLocation);
}
}
};
function onMessageReceived(event) {
switch (event.data) {
// Indication of all test parts finish (from any of the frames)
case "done":
if (--_windowCount == 0) {
if (testCleanUp) {
testCleanUp();
}
if (hasMixedActiveContent) {
SpecialPowers.popPrefEnv(null);
}
SimpleTest.finish();
}
break;
// Any other message is an error or success message of a test.
default:
SimpleTest.ok(!event.data.match(/^FAILURE/), event.data);
break;
}
}
function postMsg(message) {
opener.postMessage(message, "http://mochi.test:8888");
}
function finish() {
if (history.length == 1 && !bypassNavigationTest) {
window.setTimeout(() => {
window.location.assign(
navigateToInsecure
);
}, 0);
} else {
postMsg("done");
window.close();
}
}
function ok(a, message) {
if (!a) {
postMsg("FAILURE: " + message);
} else {
postMsg(message);
}
}
function is(a, b, message) {
if (a != b) {
postMsg(`FAILURE: ${message}, expected ${b} got ${a}`);
} else {
postMsg(`${message}, expected ${b} got ${a}`);
}
}
async function isSecurityState(expectedState, message, test) {
if (!test) {
test = ok;
}
let state = await SpecialPowers.getSecurityState(window);
let isInsecure =
state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_INSECURE;
let isBroken =
state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_BROKEN;
let isEV =
state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
let gotState = "secure";
if (isInsecure) {
gotState = "insecure";
} else if (isBroken) {
gotState = "broken";
} else if (isEV) {
gotState = "EV";
}
test(
gotState == expectedState,
(message || "") + ", expected " + expectedState + " got " + gotState
);
switch (expectedState) {
case "insecure":
test(
isInsecure && !isBroken && !isEV,
"for 'insecure' excpected flags [1,0,0], " + (message || "")
);
break;
case "broken":
test(
!isInsecure && isBroken && !isEV,
"for 'broken' expected flags [0,1,0], " + (message || "")
);
break;
case "secure":
test(
!isInsecure && !isBroken && !isEV,
"for 'secure' expected flags [0,0,0], " + (message || "")
);
break;
case "EV":
test(
!isInsecure && !isBroken && isEV,
"for 'EV' expected flags [0,0,1], " + (message || "")
);
break;
default:
throw new Error("Invalid isSecurityState state");
}
}
function waitForSecurityState(expectedState, callback) {
let roundsLeft = 200; // Wait for 20 seconds (=200*100ms)
let interval = window.setInterval(async () => {
await isSecurityState(expectedState, "", isok => {
if (isok) {
roundsLeft = 0;
}
});
if (!roundsLeft--) {
window.clearInterval(interval);
callback();
}
}, 100);
}