Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>DNR with tabIds condition</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
"use strict";
// While most DNR tests are xpcshell tests, this one is a mochitest because it
// is not possible to create a tab and get a tabId in a xpcshell test.
// toolkit/components/extensions/test/xpcshell/test_ext_dnr_tabIds.js does
// exist, as an isolated xpcshell is needed to verify that the internals are
// working as expected. A mochitest is not a good fit for that because it has
// built-in add-ons that may affect the observed behavior.
add_setup(async () => {
await SpecialPowers.pushPrefEnv({
set: [
["extensions.manifestV3.enabled", true],
["extensions.dnr.enabled", true],
],
});
});
add_task(async function match_by_tabIds() {
let extension = ExtensionTestUtils.loadExtension({
async background() {
async function createTabAndPort() {
let portPromise = new Promise(resolve => {
browser.runtime.onConnect.addListener(function listener(port) {
browser.runtime.onConnect.removeListener(listener);
browser.test.assertEq("port_from_tab", port.name, "Got port");
resolve(port);
});
});
const tab = await browser.tabs.create({ url: "tab.html" });
const port = await portPromise;
browser.test.assertEq(tab.id, port.sender.tab.id, "Got port from tab");
browser.test.assertTrue(tab.id > 0, `tabId must be valid: ${tab.id}`);
tab.port = port;
return tab;
}
async function getFinalUrlForFetchInTab(tabWithPort, url) {
const port = tabWithPort.port; // from createTabAndPort.
return new Promise(resolve => {
port.onMessage.addListener(function listener(responseUrl) {
port.onMessage.removeListener(listener);
resolve(responseUrl);
});
port.postMessage(url);
});
}
let tab1 = await createTabAndPort();
let tab2 = await createTabAndPort();
function makeRedirect(id, condition, url) {
return {
id,
// The test sends a request to example.net and expects a redirect to
// URL_PREFIX (example.com).
condition: { requestDomains: ["example.net"], ...condition },
action: { type: "redirect", redirect: { url }},
};
}
await browser.declarativeNetRequest.updateSessionRules({
addRules: [
makeRedirect(1, { tabIds: [-1] }, `${URL_PREFIX}?tabId/-1`),
makeRedirect(2, { tabIds: [tab1.id] }, `${URL_PREFIX}?tabId/tab1`),
makeRedirect(
3,
{ excludedTabIds: [-1, tab1.id] },
`${URL_PREFIX}?tabId/not-1,not-tab1`
),
],
});
browser.test.assertEq(
`${URL_PREFIX}?tabId/-1`,
(await fetch("https://example.net/?pre-redirect-bg")).url,
"Request from background should match tabIds: [-1]"
);
browser.test.assertEq(
`${URL_PREFIX}?tabId/tab1`,
await getFinalUrlForFetchInTab(tab1, "https://example.net/?pre-tab1"),
"Request from tab1 should match tabIds: [tab1]"
);
browser.test.assertEq(
`${URL_PREFIX}?tabId/not-1,not-tab1`,
await getFinalUrlForFetchInTab(tab2, "https://example.net/?pre-tab2"),
"Request from tab2 should match excludedTabIds: [-1, tab1]"
);
await browser.tabs.remove(tab1.id);
await browser.tabs.remove(tab2.id);
browser.test.sendMessage("done");
},
temporarilyInstalled: true, // Needed for granted_host_permissions
manifest: {
manifest_version: 3,
host_permissions: ["*://example.com/*", "*://example.net/*"],
permissions: ["declarativeNetRequest"],
granted_host_permissions: true,
},
files: {
"tab.html": `<!DOCTYPE html><script src="tab.js"><\/script>`,
"tab.js": () => {
let port = browser.runtime.connect({ name: "port_from_tab" });
port.onMessage.addListener(async url => {
try {
let res = await fetch(url);
port.postMessage(res.url);
} catch (e) {
port.postMessage(e.message);
}
});
},
},
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});
</script>
</body>
</html>