Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

"use strict";
const server = createHttpServer({
hosts: ["example.org", "example.net", "example.com"],
});
function promiseSetCookies() {
return new Promise(resolve => {
server.registerPathHandler("/setCookies", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.setHeader("Set-Cookie", "none=a; sameSite=none", true);
response.setHeader("Set-Cookie", "lax=b; sameSite=lax", true);
response.setHeader("Set-Cookie", "strict=c; sameSite=strict", true);
response.write("<html></html>");
resolve();
});
});
}
function promiseLoadedCookies() {
return new Promise(resolve => {
let cookies;
server.registerPathHandler("/checkCookies", (request, response) => {
cookies = request.hasHeader("Cookie") ? request.getHeader("Cookie") : "";
response.setStatusLine(request.httpVersion, 302, "Moved Permanently");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.setHeader("Location", "/ready");
});
server.registerPathHandler("/navigate", (request, response) => {
cookies = request.hasHeader("Cookie") ? request.getHeader("Cookie") : "";
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write(
"<html><script>location = '/checkCookies';</script></html>"
);
});
server.registerPathHandler("/fetch", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
// /checkCookies ultimately redirects to /ready, which resolves the
// promise returned by promiseLoadedCookies(). At that point, the test
// can choose to close the ContentPage that hosts us, and abort the
// pending fetch(). When extensions.webextensions.remote is false, the
// PromiseTestUtils.assertNoUncaughtRejections() check may detect this
// and cause the test to fail unexpectedly. To avoid this issue, we catch
// the error unconditionally.
response.write(`<html><script>
fetch("/checkCookies").catch(e => console.log("fetch() error: " + e));
</script></html>`);
});
server.registerPathHandler("/nestedfetch", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write(
"<html><iframe src='http://example.net/nestedfetch2'></iframe></html>"
);
});
server.registerPathHandler("/nestedfetch2", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write(
"<html><iframe src='http://example.org/fetch'></iframe></html>"
);
});
server.registerPathHandler("/ready", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write("<html></html>");
resolve(cookies);
});
});
}
add_task(async function setup() {
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault", true);
// We don't want to have 'secure' cookies because our test http server doesn't run in https.
Services.prefs.setBoolPref(
"network.cookie.sameSite.noneRequiresSecure",
false
);
// Let's set 3 cookies before loading the extension.
let cookiesPromise = promiseSetCookies();
let contentPage = await ExtensionTestUtils.loadContentPage(
);
await cookiesPromise;
await contentPage.close();
Assert.equal(Services.cookies.cookies.length, 3);
});
add_task(async function test_cookies_firstParty() {
// Loads a http:-URL in moz-extension://[uuid]/page.html
allow_unsafe_parent_loads_when_extensions_not_remote();
async function pageScript() {
const ifr = document.createElement("iframe");
ifr.src = "http://example.org/" + location.search.slice(1);
document.body.appendChild(ifr);
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["*://example.org/"],
},
files: {
"page.html": `<body><script src="page.js"></script></body>`,
"page.js": pageScript,
},
});
await extension.startup();
// This page will load example.org in an iframe.
let url = `moz-extension://${extension.uuid}/page.html`;
let cookiesPromise = promiseLoadedCookies();
let contentPage = await ExtensionTestUtils.loadContentPage(
url + "?checkCookies",
{ extension }
);
// Let's check the cookies received during the last loading.
Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
await contentPage.close();
// Let's navigate.
cookiesPromise = promiseLoadedCookies();
contentPage = await ExtensionTestUtils.loadContentPage(url + "?navigate", {
extension,
});
// Let's check the cookies received during the last loading.
Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
await contentPage.close();
// Let's run a fetch()
cookiesPromise = promiseLoadedCookies();
contentPage = await ExtensionTestUtils.loadContentPage(url + "?fetch", {
extension,
});
// Let's check the cookies received during the last loading.
Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
await contentPage.close();
// Let's run a fetch() from a nested iframe (extension -> example.net ->
// example.org -> fetch)
cookiesPromise = promiseLoadedCookies();
contentPage = await ExtensionTestUtils.loadContentPage(url + "?nestedfetch", {
extension,
});
// Let's check the cookies received during the last loading.
Assert.equal(await cookiesPromise, "none=a");
await contentPage.close();
// Let's run a fetch() from a nested iframe (extension -> example.org -> fetch)
cookiesPromise = promiseLoadedCookies();
contentPage = await ExtensionTestUtils.loadContentPage(
url + "?nestedfetch2",
{
extension,
}
);
// Let's check the cookies received during the last loading.
Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
await contentPage.close();
await extension.unload();
revert_allow_unsafe_parent_loads_when_extensions_not_remote();
});
add_task(async function test_cookies_iframes() {
server.registerPathHandler("/echocookies", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write(
request.hasHeader("Cookie") ? request.getHeader("Cookie") : ""
);
});
server.registerPathHandler("/contentScriptHere", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write("<html></html>");
});
server.registerPathHandler("/pageWithFrames", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write(`
<html>
<iframe src="http://example.com/contentScriptHere"></iframe>
<iframe src="http://example.net/contentScriptHere"></iframe>
</html>
`);
});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["*://example.org/"],
content_scripts: [
{
js: ["contentScript.js"],
matches: [
"*://example.com/contentScriptHere",
"*://example.net/contentScriptHere",
],
run_at: "document_end",
all_frames: true,
},
],
},
files: {
"contentScript.js": async () => {
const res = await fetch("http://example.org/echocookies");
const cookies = await res.text();
browser.test.assertEq(
"none=a",
cookies,
"expected cookies in content script"
);
browser.test.sendMessage("extfetch:" + location.hostname);
},
},
});
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(
);
await Promise.all([
extension.awaitMessage("extfetch:example.com"),
extension.awaitMessage("extfetch:example.net"),
]);
await contentPage.close();
await extension.unload();
});
add_task(async function test_cookies_background() {
async function background() {
const res = await fetch("http://example.org/echocookies", {
credentials: "include",
});
const cookies = await res.text();
browser.test.sendMessage("fetchcookies", cookies);
}
const tests = [
{
permissions: ["http://example.org/*"],
cookies: "none=a; lax=b; strict=c",
},
{
permissions: [],
cookies: "none=a",
},
];
for (let test of tests) {
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: test.permissions,
},
});
server.registerPathHandler("/echocookies", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.setHeader(
"Access-Control-Allow-Origin",
`moz-extension://${extension.uuid}`,
false
);
response.setHeader("Access-Control-Allow-Credentials", "true", false);
response.write(
request.hasHeader("Cookie") ? request.getHeader("Cookie") : ""
);
});
await extension.startup();
equal(
await extension.awaitMessage("fetchcookies"),
test.cookies,
"extension with permissions can see SameSite-restricted cookies"
);
await extension.unload();
}
});
add_task(async function test_cookies_contentScript() {
server.registerPathHandler("/empty", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write("<html><body></body></html>");
});
async function contentScript() {
let res = await fetch("http://example.org/checkCookies");
browser.test.assertEq(location.origin + "/ready", res.url, "request OK");
browser.test.sendMessage("fetch-done");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
content_scripts: [
{
run_at: "document_end",
js: ["contentscript.js"],
matches: ["*://*/*"],
},
],
},
files: {
"contentscript.js": contentScript,
},
});
await extension.startup();
let cookiesPromise = promiseLoadedCookies();
let contentPage = await ExtensionTestUtils.loadContentPage(
);
await extension.awaitMessage("fetch-done");
// Let's check the cookies received during the last loading.
Assert.equal(await cookiesPromise, "none=a; lax=b; strict=c");
await contentPage.close();
await extension.unload();
});