// Bug 1722489 - HTTPS-Only Mode - Tests evaluation order
// https://bugzilla.mozilla.org/show_bug.cgi?id=1722489
// This test ensures that an http request to an hsts host
// gets upgraded by hsts and not by https-only.
"use strict";
// Set bools to track that tests ended.
let readMessage =
false;
let testFinished =
false;
// Visit a secure site that sends an HSTS header to set up the rest of the
// test.
add_task(async
function see_hsts_header() {
let setHstsUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) +
"hsts_headers.sjs";
Services.obs.addObserver(observer,
"http-on-examine-response");
let promiseLoaded = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
setHstsUrl
);
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, setHstsUrl);
await promiseLoaded;
await BrowserTestUtils.waitForCondition(() => readMessage);
// Clean up
Services.obs.removeObserver(observer,
"http-on-examine-response");
});
// Test that HTTPS_Only is not performed if HSTS host is visited.
add_task(async
function () {
// A longer timeout is necessary for this test than the plain mochitests
// due to opening a new tab with the web console.
requestLongerTimeout(4);
// Enable HTTPS-Only Mode and register console-listener
await SpecialPowers.pushPrefEnv({
set: [[
"dom.security.https_only_mode",
true]],
});
Services.console.registerListener(onNewMessage);
const RESOURCE_LINK =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) +
"hsts_headers.sjs";
// 1. Upgrade page to https://>
let promiseLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
BrowserTestUtils.startLoadingURIString(
gBrowser.selectedBrowser,
RESOURCE_LINK
);
await promiseLoaded;
await BrowserTestUtils.waitForCondition(() => testFinished);
// Clean up
Services.console.unregisterListener(onNewMessage);
await SpecialPowers.popPrefEnv();
});
// Test that when clicking on #fragment with a different scheme (http vs https)
// DOES cause an actual navigation with HSTS, even though https-only mode is
// enabled.
add_task(async
function () {
await SpecialPowers.pushPrefEnv({
set: [
[
"dom.security.https_only_mode",
true],
[
"dom.security.https_only_mode_break_upgrade_downgrade_endless_loop",
false,
],
],
});
const TEST_PAGE =
"http://example.com/browser/dom/security/test/https-only/file_fragment_noscript.html";
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: TEST_PAGE,
waitForLoad:
true,
},
async
function (browser) {
const UPGRADED_URL = TEST_PAGE.replace(
"http:",
"https:");
await SpecialPowers.spawn(browser, [UPGRADED_URL], async
function (url) {
is(content.window.location.href, url);
content.window.addEventListener(
"scroll", () => {
ok(
false,
"scroll event should not trigger");
});
let beforeUnload =
new Promise(resolve => {
content.window.addEventListener(
"beforeunload", resolve, {
once:
true,
});
});
content.window.document.querySelector(
"#clickMeButton").click();
// Wait for unload event.
await beforeUnload;
});
await BrowserTestUtils.browserLoaded(browser);
await SpecialPowers.spawn(browser, [UPGRADED_URL], async
function (url) {
is(content.window.location.href, url +
"#foo");
});
}
);
await SpecialPowers.popPrefEnv();
});
add_task(async
function () {
// Reset HSTS header
readMessage =
false;
let clearHstsUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) +
"hsts_headers.sjs?reset";
Services.obs.addObserver(observer,
"http-on-examine-response");
// reset hsts header
let promiseLoaded = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
clearHstsUrl
);
await BrowserTestUtils.startLoadingURIString(
gBrowser.selectedBrowser,
clearHstsUrl
);
await promiseLoaded;
await BrowserTestUtils.waitForCondition(() => readMessage);
// Clean up
Services.obs.removeObserver(observer,
"http-on-examine-response");
});
function observer(subject, topic) {
info(
"observer called with " + topic);
if (topic ==
"http-on-examine-response") {
onExamineResponse(subject);
}
}
function onExamineResponse(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
// If message was already read or is not related to "example.com",
// don't examine it.
if (!channel.URI.spec.includes(
"example.com") || readMessage) {
return;
}
info(
"onExamineResponse with " + channel.URI.spec);
if (channel.URI.spec.includes(
"reset")) {
try {
let hsts = channel.getResponseHeader(
"Strict-Transport-Security");
is(hsts,
"max-age=0",
"HSTS header is not set");
}
catch (e) {
ok(
false,
"HSTS header still set");
}
readMessage =
true;
return;
}
try {
let hsts = channel.getResponseHeader(
"Strict-Transport-Security");
let csp = channel.getResponseHeader(
"Content-Security-Policy");
// Check that HSTS and CSP upgrade headers are set
is(hsts,
"max-age=60",
"HSTS header is set");
is(csp,
"upgrade-insecure-requests",
"CSP header is set");
}
catch (e) {
ok(
false,
"No header set");
}
readMessage =
true;
}
function onNewMessage(msgObj) {
const message = msgObj.message;
// ensure that request is not upgraded HTTPS-Only.
if (message.includes(
"Upgrading insecure request")) {
ok(
false,
"Top-Level upgrade shouldn't get logged");
testFinished =
true;
}
else if (
message.includes(
"Upgrading insecure speculative TCP connection")
) {
// TODO: Check assertion
// https://bugzilla.mozilla.org/show_bug.cgi?id=1735683
ok(
true,
"Top-Level upgrade shouldn't get logged");
testFinished =
true;
}
else if (gBrowser.selectedBrowser.currentURI.scheme ===
"https") {
ok(
true,
"Top-Level upgrade shouldn't get logged");
testFinished =
true;
}
}