Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const TEST_CASES = [
{
name: "XHR",
url: TEST_4TH_PARTY_PAGE_HTTPS,
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
let xhr = new content.XMLHttpRequest();
xhr.open("GET", srcUrl);
xhr.send();
});
},
},
{
name: "Fetch",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "fetch.html",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await content.fetch(srcUrl);
});
},
},
{
name: "Image",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "raptor.jpg",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await new content.Promise(resolve => {
let img = content.document.createElement("img");
img.src = srcUrl;
img.onload = resolve;
content.document.body.appendChild(img);
});
});
},
},
{
name: "CSS",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "style.css",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await new content.Promise(resolve => {
let link = content.document.createElement("link");
link.rel = "stylesheet";
link.href = srcUrl;
link.onload = resolve;
content.document.head.appendChild(link);
});
});
},
},
{
name: "Video",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "short.mp4",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await new content.Promise(resolve => {
let video = content.document.createElement("video");
video.src = srcUrl;
video.onloadeddata = resolve;
content.document.body.appendChild(video);
});
});
},
},
{
name: "Audio",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "empty_size.mp3",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await new content.Promise(resolve => {
let audio = content.document.createElement("audio");
audio.src = srcUrl;
audio.onloadeddata = resolve;
content.document.body.appendChild(audio);
});
});
},
},
{
name: "Iframe",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "page.html",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await new content.Promise(resolve => {
let iframe = content.document.createElement("iframe");
iframe.src = srcUrl;
iframe.onload = resolve;
content.document.body.appendChild(iframe);
});
});
},
},
{
name: "Script",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "empty.js",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], async srcUrl => {
await new content.Promise(resolve => {
let script = content.document.createElement("script");
script.src = srcUrl;
script.onload = resolve;
content.document.body.appendChild(script);
});
});
},
},
{
name: "Font",
url: TEST_4TH_PARTY_DOMAIN_HTTPS + TEST_PATH + "test.font.woff",
testFunc: async (browsingContext, url) => {
await SpecialPowers.spawn(browsingContext, [url], srcUrl => {
let fontName = "TestFont" + Math.random().toString(36).substring(2);
let style = content.document.createElement("style");
style.textContent = `@font-face { font-family: ${fontName}; src: url('${srcUrl}'); }`;
content.document.head.appendChild(style);
let span = content.document.createElement("span");
span.textContent = "FontTest";
span.style.fontFamily = fontName;
content.document.body.appendChild(span);
// Force layout to trigger font load
content.getComputedStyle(span).fontFamily;
});
},
},
// The url of a websocket channel is still using http scheme in the observer.
// So we need to use a http url but not a ws url. But the actual websocket
// request is still made to the ws url.
{
name: "WebSocket",
testFunc: async (browsingContext, _) => {
await SpecialPowers.spawn(browsingContext, [], async _ => {
let ws = new content.WebSocket(
["test"]
);
await ContentTaskUtils.waitForEvent(ws, "open");
});
},
},
];
// A helper function to observe and check flags on the channel.
function observeAndCheck(
url,
expectedFirstPartyFlags,
expectedThirdPartyFlags
) {
return new Promise(resolve => {
let observer = {
observe(subject, topic) {
if (topic !== "http-on-opening-request") {
return;
}
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel || channel.URI.spec !== url) {
return;
}
let loadInfo = channel.loadInfo;
is(
loadInfo.triggeringFirstPartyClassificationFlags,
expectedFirstPartyFlags,
`Correct first party flags for ${url}`
);
is(
loadInfo.triggeringThirdPartyClassificationFlags,
expectedThirdPartyFlags,
`Correct third party flags for ${url}`
);
Services.obs.removeObserver(observer, "http-on-opening-request");
resolve();
},
};
Services.obs.addObserver(observer, "http-on-opening-request");
});
}
add_setup(async function () {
await UrlClassifierTestUtils.addTestTrackers();
registerCleanupFunction(async _ => {
UrlClassifierTestUtils.cleanupTestTrackers();
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () =>
resolve()
);
});
});
});
// Test that the third party flags are set correctly when the request is made
// from a third party iframe.
add_task(async function test_third_party_flags() {
// Open the test page and inject the tracking iframe
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_TOP_PAGE
);
// Creating a tracking iframe.
let trackingIframeBC = await SpecialPowers.spawn(
tab.linkedBrowser,
[TEST_3RD_PARTY_PAGE_HTTP],
async iframeUrl => {
let iframe = content.document.createElement("iframe");
iframe.src = iframeUrl;
content.document.body.appendChild(iframe);
await new content.Promise(resolve => {
iframe.onload = resolve;
});
return iframe.browsingContext;
}
);
for (const testCase of TEST_CASES) {
info(`Running classification flags test for: ${testCase.name}`);
let obsPromise = observeAndCheck(
testCase.url,
0,
Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING
);
// Call the testing function to make the request.
await testCase.testFunc(trackingIframeBC, testCase.url);
await obsPromise;
}
BrowserTestUtils.removeTab(tab);
});
// Test that the first party flags are set correctly when the request is made
// from an about:blank iframe in a tracking iframe.
add_task(async function test_third_party_flags_in_about_blank_iframe() {
// Open the test page and inject the tracking iframe
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_TOP_PAGE
);
// Creating a tracking iframe.
let trackingIframeBC = await SpecialPowers.spawn(
tab.linkedBrowser,
[TEST_3RD_PARTY_PAGE_HTTP],
async iframeUrl => {
let iframe = content.document.createElement("iframe");
iframe.src = iframeUrl;
content.document.body.appendChild(iframe);
await new content.Promise(resolve => {
iframe.onload = resolve;
});
return iframe.browsingContext;
}
);
// Open an about:blank iframe in the tracking iframe.
let aboutBlankIframeBC = await SpecialPowers.spawn(
trackingIframeBC,
[],
async () => {
let iframe = content.document.createElement("iframe");
content.document.body.appendChild(iframe);
return iframe.browsingContext;
}
);
for (const testCase of TEST_CASES) {
info(`Running classification flags test for: ${testCase.name}`);
let obsPromise = observeAndCheck(
testCase.url,
0,
Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING
);
// Call the testing function to make the request.
await testCase.testFunc(aboutBlankIframeBC, testCase.url);
await obsPromise;
}
BrowserTestUtils.removeTab(tab);
});
// Test that the first party flags are set correctly when the request is made
// from the top-level context loading a tracking domain.
add_task(async function test_first_party_flags() {
// Open the tab that loads a tracking domain.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_3RD_PARTY_PAGE_HTTP
);
for (const testCase of TEST_CASES) {
info(`Running first-party classification flags test for: ${testCase.name}`);
let obsPromise = observeAndCheck(
testCase.url,
Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING,
0
);
// Call the testing function to make the request.
await testCase.testFunc(tab.linkedBrowser, testCase.url);
await obsPromise;
}
BrowserTestUtils.removeTab(tab);
});
// Test that the first party flags are set correctly when the request is made
// from an about:blank iframe in the top-level context loading a tracking domain.
add_task(async function test_first_party_flags_in_about_blank_iframe() {
// Open the tab that loads a tracking domain.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_3RD_PARTY_PAGE_HTTP
);
// Open an about:blank iframe in the top-level context.
let aboutBlankIframeBC = await SpecialPowers.spawn(
tab.linkedBrowser,
[],
async () => {
let iframe = content.document.createElement("iframe");
content.document.body.appendChild(iframe);
return iframe.browsingContext;
}
);
for (const testCase of TEST_CASES) {
info(
`Running first-party classification flags test (about:blank iframe) for: ${testCase.name}`
);
let obsPromise = observeAndCheck(
testCase.url,
Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING,
0
);
// Call the testing function to make the request.
await testCase.testFunc(aboutBlankIframeBC, testCase.url);
await obsPromise;
}
BrowserTestUtils.removeTab(tab);
});
// Test that loads from an embedded tracking script have the correct flags.
add_task(async function test_embedded_tracking_script() {
// Open the test page and inject the tracking iframe
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_TOP_PAGE
);
for (const testCase of TEST_CASES) {
// Skip the font face test because we don't have a definite way to determine
// who triggers the load in this case.
if (testCase.name === "Font") {
continue;
}
let obsPromise = observeAndCheck(
testCase.url,
0,
Ci.nsIClassifiedChannel.CLASSIFIED_TRACKING
);
// Inject a tracking script into the page.
await SpecialPowers.spawn(
tab.linkedBrowser,
[
TEST_3RD_PARTY_DOMAIN_HTTP +
TEST_PATH +
"triggerLoads.sjs?type=" +
testCase.name +
"&url=" +
testCase.url,
],
async src => {
let script = content.document.createElement("script");
script.src = src;
content.document.body.appendChild(script);
}
);
await obsPromise;
}
BrowserTestUtils.removeTab(tab);
});