Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

"use strict";
// Bug 2074019: A first-party load of a listed host must receive first-party
// classification flags without a content blocking event, and must never be
// cancelled. The antitracking redirect, navigation and popup heuristics read
// these flags off the top-level document channel, so this mirrors
// url-classifier, whose annotation features run on every channel while its
// blocking features only consider third-party ones.
const LISTED_DOMAIN = "https://example.com/";
const LISTED_TOP_PAGE = LISTED_DOMAIN + TEST_PATH + "page.html";
const LISTED_IMAGE_PREFIX =
LISTED_DOMAIN +
"browser/toolkit/components/antitracking/test/browser/raptor.jpg";
// Publishes example.com on the trackers list and enables the trackers engine
// for both cancel and annotate, so a wrongly ungated cancel pass would show up
// as a blocked top-level load.
async function setupTrackersEngine() {
let client = getRSClient();
let records = await populateMultipleRS(client.db, [
{
id: "trackers",
name: "disconnect-tracker-base",
rules: ["||example.com^"],
},
]);
await pushEnginePrefs({ protection: "trackers", annotation: "trackers" });
return { client, records };
}
function getDocumentClassification(browser) {
return SpecialPowers.spawn(browser, [], () => {
let channel = content.docShell.currentDocumentChannel.QueryInterface(
Ci.nsIClassifiedChannel
);
return {
documentURI: content.document.documentURI,
firstParty: channel.firstPartyClassificationFlags,
thirdParty: channel.thirdPartyClassificationFlags,
};
});
}
// Resolves with the classification flags of the parent-process channel whose
// URL starts with urlPrefix, once that channel stops.
function waitForChannelClassification(urlPrefix) {
return new Promise(resolve => {
let observer = subject => {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith(urlPrefix)) {
return;
}
Services.obs.removeObserver(observer, "http-on-stop-request");
let classified = channel.QueryInterface(Ci.nsIClassifiedChannel);
resolve({
firstParty: classified.firstPartyClassificationFlags,
thirdParty: classified.thirdPartyClassificationFlags,
});
};
Services.obs.addObserver(observer, "http-on-stop-request");
});
}
add_task(async function test_top_level_document_gets_first_party_flags() {
let { client, records } = await setupTrackersEngine();
await syncAndWaitForLists(client, records);
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
LISTED_TOP_PAGE
);
let browser = tab.linkedBrowser;
let classification = await getDocumentClassification(browser);
is(
classification.documentURI,
LISTED_TOP_PAGE,
"Top-level load of a listed host is not cancelled"
);
ok(
classification.firstParty & Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING,
"Document channel carries the first-party tracking flag"
);
is(
classification.thirdParty,
0,
"Document channel carries no third-party flags"
);
let log = JSON.parse(await browser.getContentBlockingLog());
ok(
!log[LISTED_DOMAIN.replace(/\/$/, "")],
"A first-party load produces no content blocking event"
);
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_same_site_subresource_gets_first_party_flags() {
let { client, records } = await setupTrackersEngine();
await syncAndWaitForLists(client, records);
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
LISTED_TOP_PAGE
);
let browser = tab.linkedBrowser;
let classified = waitForChannelClassification(LISTED_IMAGE_PREFIX);
let loaded = await loadThirdPartyImage(browser, LISTED_DOMAIN);
ok(loaded, "Same-site image from a listed host loads");
let classification = await classified;
ok(
classification.firstParty & Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING,
"Same-site image channel carries the first-party tracking flag"
);
is(
classification.thirdParty,
0,
"Same-site image channel carries no third-party flags"
);
BrowserTestUtils.removeTab(tab);
});