Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
"use strict";
// the parent process go through DocumentLoadListener::OpenInParent instead of
// OpenDocument. OpenInParent used to skip the
// BounceTrackingState::OnStartNavigation call, so the BounceTrackingRecord was
// never created and OnDocumentStartRequest / OnResponseReceived failed. As a
// result server side bounces from parent initiated loads were never classified.
//
// This happens in two common real world cases:
// - A content initiated cross-site top level navigation. Under Fission this
// switches process and the parent initiates the load (WindowGlobalParent::
// RecvLoadURI -> OpenInParent) carrying the page's content principal.
// - An address bar / bookmark load, which the parent initiates with the system
// principal.
let bounceTrackingProtection = Cc[
"@mozilla.org/bounce-tracking-protection;1"
].getService(Ci.nsIBounceTrackingProtection);
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
[
"privacy.bounceTrackingProtection.mode",
Ci.nsIBounceTrackingProtection.MODE_ENABLED,
],
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
],
});
});
// A server side bounce reached via a content initiated cross-process top level
// navigation must classify the redirecting site. Under Fission the cross-site
// navigation switches process, so the parent initiates the load through
// DocumentLoadListener::OpenInParent carrying the page's content principal.
// created and the tracker was never classified.
add_task(async function test_content_parent_load_server_bounce() {
bounceTrackingProtection.clearAll();
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
0,
"No bounce tracker hosts initially."
);
let initialURL = getBaseUrl(ORIGIN_A) + "file_start.html";
await BrowserTestUtils.withNewTab(initialURL, async browser => {
let targetURL = new URL(getBaseUrl(ORIGIN_B) + "file_start.html");
let bounceURL = getBounceURL({ bounceType: "server", targetURL });
// Script a cross-site navigation to the bounce URL, which process switches
// and makes the parent initiate the load.
let targetLoaded = BrowserTestUtils.browserLoaded(
browser,
false,
targetURL
);
await navigateContentParentLoad(browser, bounceURL);
await targetLoaded;
// End the extended navigation with a user activated navigation, which
// triggers RecordStatefulBounces.
await navigateLinkClick(
browser,
new URL(getBaseUrl(ORIGIN_C) + "file_start.html")
);
// The tracker is only recorded via OnDocumentStartRequest ->
// OnResponseReceived, which needs the record created by OnStartNavigation on
// the parent initiated load. Poll so a missing fix fails fast here instead
// of hanging.
await TestUtils.waitForCondition(
() =>
bounceTrackingProtection
.testGetBounceTrackerCandidateHosts({})
.some(entry => entry.siteHost == SITE_TRACKER),
`Waiting for ${SITE_TRACKER} to be classified as a bounce tracker.`
);
let purgedHosts =
await bounceTrackingProtection.testRunPurgeBounceTrackers();
Assert.ok(
purgedHosts.includes(SITE_TRACKER),
`Should purge ${SITE_TRACKER} from the parent initiated bounce. Got: ${JSON.stringify(
purgedHosts
)}`
);
bounceTrackingProtection.clearAll();
});
await SiteDataTestUtils.clear();
});
// A server side bounce started from the address bar (parent process, system
// principal) must still classify the redirecting site as a bounce tracker.
// The system principal load counts as a user activation, which ends the initial
// extended navigation and starts a new one, so the resulting state differs from
// the link click case and we assert on classification directly.
add_task(async function test_url_bar_server_bounce() {
bounceTrackingProtection.clearAll();
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
0,
"No bounce tracker hosts initially."
);
let initialURL = getBaseUrl(ORIGIN_A) + "file_start.html";
await BrowserTestUtils.withNewTab(initialURL, async browser => {
let targetURL = new URL(getBaseUrl(ORIGIN_B) + "file_start.html");
let bounceURL = getBounceURL({ bounceType: "server", targetURL });
// Load the bounce URL the way the address bar does.
let targetLoaded = BrowserTestUtils.browserLoaded(
browser,
false,
targetURL
);
await navigateSystemPrincipalLoad(browser, bounceURL);
await targetLoaded;
// End the extended navigation with a user activated navigation, which
// triggers RecordStatefulBounces.
await navigateLinkClick(
browser,
new URL(getBaseUrl(ORIGIN_C) + "file_start.html")
);
// Wait for the tracker to be classified. The tracker is only recorded via
// OnDocumentStartRequest -> OnResponseReceived, which needs the record
// record was missing for address bar loads so this never happened.
// Polling avoids racing the grace period driven purge below.
await TestUtils.waitForCondition(
() =>
bounceTrackingProtection
.testGetBounceTrackerCandidateHosts({})
.some(entry => entry.siteHost == SITE_TRACKER),
`Waiting for ${SITE_TRACKER} to be classified as a bounce tracker.`
);
let purgedHosts =
await bounceTrackingProtection.testRunPurgeBounceTrackers();
Assert.ok(
purgedHosts.includes(SITE_TRACKER),
`Should purge ${SITE_TRACKER} from the address bar bounce. Got: ${JSON.stringify(
purgedHosts
)}`
);
bounceTrackingProtection.clearAll();
});
await SiteDataTestUtils.clear();
});