Source code
Revision control
Copy as Markdown
Other Tools
const REFERRER_URL_BASE = "/browser/browser/base/content/test/referrer/";
const REFERRER_POLICYSERVER_URL =
"test1.example.com" + REFERRER_URL_BASE + "file_referrer_policyserver.sjs";
const REFERRER_POLICYSERVER_URL_ATTRIBUTE =
"test1.example.com" +
REFERRER_URL_BASE +
"file_referrer_policyserver_attr.sjs";
var gTestWindow = null;
var rounds = 0;
// We test that the UI code propagates three pieces of state - the referrer URI
// itself, the referrer policy, and the triggering principal. After that, we
// trust nsIWebNavigation to do the right thing with the info it's given, which
// is covered more exhaustively by dom/base/test/test_bug704320.html (which is
// a faster content-only test). So, here, we limit ourselves to cases that
// would break when the UI code drops either of these pieces; we don't try to
// especially when we're opening a new window for each case.
var _referrerTests = [
// 1. Normal cases - no referrer policy, no special attributes.
// We expect a full referrer normally, and no referrer on downgrade.
{
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
fromScheme: "http://",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
toScheme: "http://",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
},
{
fromScheme: "https://",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
toScheme: "http://",
result: "", // no referrer when downgrade
},
// 2. Origin referrer policy - we expect an origin referrer,
// even on downgrade. But rel=noreferrer trumps this.
{
fromScheme: "https://",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
toScheme: "http://",
policy: "origin",
},
{
fromScheme: "https://",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
toScheme: "http://",
policy: "origin",
rel: "noreferrer",
result: "", // rel=noreferrer trumps meta-referrer
},
// Origin-when-cross-origin policy - this depends on the triggering
// principal. We expect full referrer for same-origin requests,
// and origin referrer for cross-origin requests.
{
fromScheme: "https://",
toScheme: "https://",
policy: "no-referrer",
},
{
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
fromScheme: "http://",
toScheme: "https://",
policy: "no-referrer",
},
];
/**
* Returns the test object for a given test number.
* @param aTestNumber The test number - 0, 1, 2, ...
* @return The test object, or undefined if the number is out of range.
*/
function getReferrerTest(aTestNumber) {
return _referrerTests[aTestNumber];
}
/**
* Returns shimmed test object for a given test number.
*
* @param aTestNumber The test number - 0, 1, 2, ...
* @return The test object with result hard-coded to "",
* or undefined if the number is out of range.
*/
function getRemovedReferrerTest(aTestNumber) {
let testCase = _referrerTests[aTestNumber];
if (testCase) {
// We want all the referrer tests to fail!
testCase.result = "";
}
return testCase;
}
/**
* Returns a brief summary of the test, for logging.
* @param aTestNumber The test number - 0, 1, 2...
* @return The test description.
*/
function getReferrerTestDescription(aTestNumber) {
let test = getReferrerTest(aTestNumber);
return (
"policy=[" +
test.policy +
"] " +
"rel=[" +
test.rel +
"] " +
test.fromScheme +
" -> " +
test.toScheme
);
}
/**
* Clicks the link.
* @param aWindow The window to click the link in.
* @param aLinkId The id of the link element.
* @param aOptions The options for synthesizeMouseAtCenter.
*/
function clickTheLink(aWindow, aLinkId, aOptions) {
return BrowserTestUtils.synthesizeMouseAtCenter(
"#" + aLinkId,
aOptions,
aWindow.gBrowser.selectedBrowser
);
}
/**
* Extracts the referrer result from the target window.
* @param aWindow The window where the referrer target has loaded.
* @return {Promise}
* @resolves When extacted, with the text of the (trimmed) referrer.
*/
function referrerResultExtracted(aWindow) {
return SpecialPowers.spawn(aWindow.gBrowser.selectedBrowser, [], function () {
return content.document.getElementById("testdiv").textContent;
});
}
/**
* Waits for browser delayed startup to finish.
* @param aWindow The window to wait for.
* @return {Promise}
* @resolves When the window is loaded.
*/
function delayedStartupFinished(aWindow) {
return new Promise(function (resolve) {
Services.obs.addObserver(function observer(aSubject, aTopic) {
if (aWindow == aSubject) {
Services.obs.removeObserver(observer, aTopic);
resolve();
}
}, "browser-delayed-startup-finished");
});
}
/**
* Waits for some (any) tab to load. The caller triggers the load.
* @param aWindow The window where to wait for a tab to load.
* @return {Promise}
* @resolves With the tab once it's loaded.
*/
function someTabLoaded() {
return BrowserTestUtils.waitForNewTab(gTestWindow.gBrowser, null, true);
}
/**
* Waits for a new window to open and load. The caller triggers the open.
* @return {Promise}
* @resolves With the new window once it's open and loaded.
*/
function newWindowOpened() {
return TestUtils.topicObserved("browser-delayed-startup-finished").then(
([win]) => win
);
}
/**
* Opens the context menu.
* @param aWindow The window to open the context menu in.
* @param aLinkId The id of the link to open the context menu on.
* @return {Promise}
* @resolves With the menu popup when the context menu is open.
*/
function contextMenuOpened(aWindow, aLinkId) {
let popupShownPromise = BrowserTestUtils.waitForEvent(
aWindow.document,
"popupshown"
);
// Simulate right-click.
clickTheLink(aWindow, aLinkId, { type: "contextmenu", button: 2 });
return popupShownPromise.then(e => e.target);
}
/**
* Performs a context menu command.
* @param aWindow The window with the already open context menu.
* @param aMenu The menu popup to hide.
* @param aItemId The id of the menu item to activate.
*/
function doContextMenuCommand(aWindow, aMenu, aItemId) {
let command = aWindow.document.getElementById(aItemId);
command.doCommand();
aMenu.hidePopup();
}
/**
* Loads a single test case, i.e., a source url into gTestWindow.
* @param aTestNumber The test case number - 0, 1, 2...
* @return {Promise}
* @resolves When the source url for this test case is loaded.
*/
function referrerTestCaseLoaded(aTestNumber, aParams) {
let test = getReferrerTest(aTestNumber);
let server =
rounds == 0
? REFERRER_POLICYSERVER_URL
: REFERRER_POLICYSERVER_URL_ATTRIBUTE;
let url =
test.fromScheme +
server +
"?scheme=" +
escape(test.toScheme) +
"&policy=" +
escape(test.policy || "") +
"&rel=" +
escape(test.rel || "") +
"&cross=" +
escape(test.cross || "");
let browser = gTestWindow.gBrowser;
return BrowserTestUtils.openNewForegroundTab(
browser,
() => {
browser.selectedTab = BrowserTestUtils.addTab(browser, url, aParams);
},
false,
true
);
}
/**
* Checks the result of the referrer test, and moves on to the next test.
* @param aTestNumber The test number - 0, 1, 2, ...
* @param aNewWindow The new window where the referrer target opened, or null.
* @param aNewTab The new tab where the referrer target opened, or null.
* @param aStartTestCase The callback to start the next test, aTestNumber + 1.
*/
function checkReferrerAndStartNextTest(
aTestNumber,
aNewWindow,
aNewTab,
aStartTestCase,
aParams = {}
) {
referrerResultExtracted(aNewWindow || gTestWindow).then(function (result) {
// Compare the actual result against the expected one.
let test = getReferrerTest(aTestNumber);
let desc = getReferrerTestDescription(aTestNumber);
is(result, test.result, desc);
// Clean up - close new tab / window, and then the source tab.
aNewTab && (aNewWindow || gTestWindow).gBrowser.removeTab(aNewTab);
aNewWindow && aNewWindow.close();
is(gTestWindow.gBrowser.tabs.length, 2, "two tabs open");
gTestWindow.gBrowser.removeTab(gTestWindow.gBrowser.tabs[1]);
// Move on to the next test. Or finish if we're done.
var nextTestNumber = aTestNumber + 1;
if (getReferrerTest(nextTestNumber)) {
referrerTestCaseLoaded(nextTestNumber, aParams).then(function () {
aStartTestCase(nextTestNumber);
});
} else if (rounds == 0) {
nextTestNumber = 0;
rounds = 1;
referrerTestCaseLoaded(nextTestNumber, aParams).then(function () {
aStartTestCase(nextTestNumber);
});
} else {
finish();
}
});
}
/**
* Fires up the complete referrer test.
* @param aStartTestCase The callback to start a single test case, called with
* the test number - 0, 1, 2... Needs to trigger the navigation from the source
* page, and call checkReferrerAndStartNextTest() when the target is loaded.
*/
function startReferrerTest(aStartTestCase, params = {}) {
waitForExplicitFinish();
// Open the window where we'll load the source URLs.
gTestWindow = openDialog(location, "", "chrome,all,dialog=no", "about:blank");
registerCleanupFunction(function () {
gTestWindow && gTestWindow.close();
});
// Load and start the first test.
delayedStartupFinished(gTestWindow).then(function () {
referrerTestCaseLoaded(0, params).then(function () {
aStartTestCase(0);
});
});
}