Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<script type="text/javascript" src="head_webrequest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script>
"use strict";
function getExtension() {
async function background() {
let expect;
let urls = ["*://*.example.org/tests/*"];
browser.webRequest.onBeforeRequest.addListener(() => {
browser.test.assertEq(expect.shift(), "onBeforeRequest");
}, {urls}, ["blocking"]);
browser.webRequest.onBeforeSendHeaders.addListener(() => {
browser.test.assertEq(expect.shift(), "onBeforeSendHeaders");
}, {urls}, ["blocking", "requestHeaders"]);
browser.webRequest.onSendHeaders.addListener(() => {
browser.test.assertEq(expect.shift(), "onSendHeaders");
}, {urls}, ["requestHeaders"]);
async function testSecurityInfo(securityInfo, options) {
if (options.certificateChain) {
// Some of the tests here only produce a single cert in the chain.
browser.test.assertTrue(securityInfo.certificates.length >= 1, "have certificate chain");
} else {
browser.test.assertTrue(securityInfo.certificates.length == 1, "no certificate chain");
}
let cert = securityInfo.certificates[0];
let now = Date.now();
browser.test.assertTrue(Number.isInteger(cert.validity.start), "cert start is integer");
browser.test.assertTrue(Number.isInteger(cert.validity.end), "cert end is integer");
browser.test.assertTrue(cert.validity.start < now, "cert start validity is correct");
browser.test.assertTrue(now < cert.validity.end, "cert end validity is correct");
if (options.rawDER) {
for (let cert of securityInfo.certificates) {
browser.test.assertTrue(!!cert.rawDER.length, "have rawDER");
}
}
}
function stripQuery(url) {
// In this whole test we are not interested in the query part of the URL.
// Most tests include a cache buster (bustcache) param in the URL.
return url.split("?")[0];
}
browser.webRequest.onHeadersReceived.addListener(async (details) => {
browser.test.assertEq(expect.shift(), "onHeadersReceived");
// We expect all requests to have been upgraded at this point.
browser.test.assertTrue(details.url.startsWith("https"), "connection is https");
let securityInfo = await browser.webRequest.getSecurityInfo(details.requestId, {});
browser.test.assertTrue(securityInfo && securityInfo.state == "secure",
"security info reflects https");
await testSecurityInfo(securityInfo, {});
securityInfo = await browser.webRequest.getSecurityInfo(details.requestId, {certificateChain: true});
await testSecurityInfo(securityInfo, {certificateChain: true});
securityInfo = await browser.webRequest.getSecurityInfo(details.requestId, {rawDER: true});
await testSecurityInfo(securityInfo, {rawDER: true});
securityInfo = await browser.webRequest.getSecurityInfo(details.requestId, {certificateChain: true, rawDER: true});
await testSecurityInfo(securityInfo, {certificateChain: true, rawDER: true});
browser.test.sendMessage("hsts", securityInfo.hsts);
let headers = details.responseHeaders || [];
for (let header of headers) {
if (header.name.toLowerCase() === "strict-transport-security") {
return;
}
}
if (details.url.includes("addHsts")) {
headers.push({
name: "Strict-Transport-Security",
value: "max-age=31536000000",
});
}
return {responseHeaders: headers};
}, {urls}, ["blocking", "responseHeaders"]);
browser.webRequest.onBeforeRedirect.addListener(() => {
browser.test.assertEq(expect.shift(), "onBeforeRedirect");
}, {urls});
browser.webRequest.onResponseStarted.addListener(() => {
browser.test.assertEq(expect.shift(), "onResponseStarted");
}, {urls});
browser.webRequest.onCompleted.addListener(details => {
browser.test.assertEq(expect.shift(), "onCompleted");
browser.test.sendMessage("onCompleted", stripQuery(details.url));
}, {urls});
browser.webRequest.onErrorOccurred.addListener(details => {
browser.test.notifyFail(`onErrorOccurred ${JSON.stringify(details)}`);
}, {urls});
async function onUpdated(tabId, tabInfo, tab) {
if (tabInfo.status !== "complete" || tab.url === "about:blank") {
return;
}
browser.tabs.remove(tabId);
browser.tabs.onUpdated.removeListener(onUpdated);
browser.test.sendMessage("tabs-done", stripQuery(tab.url));
}
browser.test.onMessage.addListener((url, expected) => {
expect = expected;
browser.tabs.onUpdated.addListener(onUpdated);
browser.tabs.create({url});
});
}
let manifest = {
"permissions": [
"tabs",
"webRequest",
"webRequestBlocking",
"<all_urls>",
],
};
return ExtensionTestUtils.loadExtension({
manifest,
background,
});
}
add_setup(async () => {
// In bug 1605515, we repeatedly saw a missing onHeadersReceived event,
// possibly related to bug 1595610. As a workaround, clear the cache.
await SpecialPowers.spawnChrome([], async () => {
Services.cache2.clear();
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_HSTS, resolve);
});
});
});
// This test makes a request against a server that redirects with a 302.
add_task(async function test_hsts_request() {
const testPath = "example.org/tests/toolkit/components/extensions/test/mochitest";
let extension = getExtension();
await extension.startup();
// simple redirect
extension.sendMessage(
`https://${testPath}/redirect_auto.sjs?redirect_uri=${sample}?bustcache1=${Math.random()}`,
["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders",
"onHeadersReceived", "onBeforeRedirect", "onBeforeRequest",
"onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived",
"onResponseStarted", "onCompleted"]);
is(await extension.awaitMessage("hsts"), false, "First request to this host, not receiving a hsts header");
is(await extension.awaitMessage("hsts"), false, "second (redirected) reqiest to the same host, still no knowledge about the hosts hsts preference");
// Note: stripQuery strips query string added by redirect_auto.
is(await extension.awaitMessage("tabs-done"), sample, "redirection ok");
is(await extension.awaitMessage("onCompleted"), sample, "redirection ok");
// priming hsts
extension.sendMessage(
`https://${testPath}/hsts.sjs`,
["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders",
"onHeadersReceived", "onResponseStarted", "onCompleted"]);
is(await extension.awaitMessage("hsts"), false, "First request to this host, receiving hsts header and saving the hosts STS preference for the next request");
is(await extension.awaitMessage("tabs-done"),
"hsts primed");
is(await extension.awaitMessage("onCompleted"),
// test upgrade
extension.sendMessage(
`http://${testPath}/hsts.sjs`,
["onBeforeRequest", "onBeforeRedirect", "onBeforeRequest",
"onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived",
"onResponseStarted", "onCompleted"]);
is(await extension.awaitMessage("hsts"), true, "second (redirected) reqiest to the same host, we know about the hsts status of the host this time");
is(await extension.awaitMessage("tabs-done"),
"hsts upgraded");
is(await extension.awaitMessage("onCompleted"),
await extension.unload();
});
// This test makes a priming request and adds the STS header, then tests the upgrade.
add_task(async function test_hsts_header() {
const testPath = "test1.example.org/tests/toolkit/components/extensions/test/mochitest";
let extension = getExtension();
await extension.startup();
// priming hsts, this time there is no STS header, onHeadersReceived adds it.
let completed = extension.awaitMessage("onCompleted");
let tabdone = extension.awaitMessage("tabs-done");
extension.sendMessage(
`https://${testPath}/file_sample.html?bustcache2=${Math.random()}&addHsts=true`,
["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders",
"onHeadersReceived", "onResponseStarted", "onCompleted"]);
is(await extension.awaitMessage("hsts"), false, "First reqeuest to this host, we don't know about the hosts STS setting yet");
is(await tabdone, `https://${testPath}/file_sample.html`, "priming request done");
is(await completed, `https://${testPath}/file_sample.html`, "priming request done");
// test upgrade from http to https due to onHeadersReceived adding STS header
completed = extension.awaitMessage("onCompleted");
tabdone = extension.awaitMessage("tabs-done");
extension.sendMessage(
`http://${testPath}/file_sample.html?bustcache3=${Math.random()}`,
["onBeforeRequest", "onBeforeRedirect", "onBeforeRequest",
"onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived",
"onResponseStarted", "onCompleted"]);
is(await extension.awaitMessage("hsts"), true, "We have received an hsts header last request via oneadersReceived");
is(await tabdone, `https://${testPath}/file_sample.html`, "hsts upgraded");
is(await completed, `https://${testPath}/file_sample.html`, "request upgraded");
await extension.unload();
});
add_task(async function test_nonBlocking_securityInfo() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": [
"webRequest",
"<all_urls>",
],
},
async background() {
let tab;
browser.webRequest.onHeadersReceived.addListener(async (details) => {
let securityInfo = await browser.webRequest.getSecurityInfo(details.requestId, {});
browser.test.assertTrue(!securityInfo, "securityInfo undefined on http request");
browser.tabs.remove(tab.id);
browser.test.notifyPass("success");
}, {urls: ["<all_urls>"], types: ["main_frame"]});
tab = await browser.tabs.create({
});
},
});
await extension.startup();
await extension.awaitFinish("success");
await extension.unload();
});
</script>
</head>
<body>
</body>
</html>