/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Tests that HTTP Strict Transport Security (HSTS) headers are noted as appropriate. // Register a cleanup function to clear all accumulated HSTS state when this // test is done. add_task(async function register_cleanup() { registerCleanupFunction(() => { let sss = Cc["@mozilla.org/ssservice;1"].getService( Ci.nsISiteSecurityService ); sss.clearAll(); }); }); // In the absense of HSTS information, no upgrade should happen. add_task(async function test_no_hsts_information_no_upgrade() { let httpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); gBrowser.removeCurrentTab(); }); // 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"; await BrowserTestUtils.openNewForegroundTab(gBrowser, setHstsUrl); gBrowser.removeCurrentTab(); }); // Given a known HSTS host, future http navigations to that domain will be // upgraded. add_task(async function test_http_upgrade() { let httpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); gBrowser.removeCurrentTab(); }); // http navigations to unrelated hosts should not be upgraded. add_task(async function test_unrelated_domain_no_upgrade() { let differentHttpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.org" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, differentHttpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); gBrowser.removeCurrentTab(); }); // http navigations in private contexts shouldn't use information from // non-private contexts, so no upgrade should occur. add_task(async function test_private_window_no_upgrade() { await SpecialPowers.pushPrefEnv({ set: [["dom.security.https_first_pbm", false]], }); let privateWindow = OpenBrowserWindow({ private: true }); await BrowserTestUtils.firstBrowserLoaded(privateWindow, false); let url = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(privateWindow.gBrowser, url); Assert.equal( privateWindow.gBrowser.selectedBrowser.currentURI.scheme, "http" ); privateWindow.gBrowser.removeCurrentTab(); privateWindow.close(); }); // Since the header didn't specify "includeSubdomains", visiting a subdomain // should not result in an upgrade. add_task(async function test_subdomain_no_upgrade() { let subdomainHttpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://test1.example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); gBrowser.removeCurrentTab(); }); // Now visit a secure site that sends an HSTS header that also includes subdomains. add_task(async function see_hsts_header_include_subdomains() { let setHstsUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://example.com" ) + "hsts_headers.sjs?includeSubdomains"; await BrowserTestUtils.openNewForegroundTab(gBrowser, setHstsUrl); gBrowser.removeCurrentTab(); }); // Now visiting a subdomain should result in an upgrade. add_task(async function test_subdomain_upgrade() { let subdomainHttpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://test1.example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); gBrowser.removeCurrentTab(); }); // Visiting a subdomain with https should result in an https URL (this isn't an // upgrade - this test is essentially a consistency check). add_task(async function test_already_https() { let subdomainHttpsUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://test2.example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpsUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); gBrowser.removeCurrentTab(); }); // Test that subresources are upgraded. add_task(async function test_iframe_upgrade() { let framedUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://example.com" ) + "some_content_framed.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { await ContentTaskUtils.waitForCondition(() => { let frame = content.document.getElementById("frame"); if (frame) { return frame.baseURI.startsWith("https://"); } return false; }); }); gBrowser.removeCurrentTab(); }); // Clear state. add_task(async function clear_hsts_state() { let sss = Cc["@mozilla.org/ssservice;1"].getService( Ci.nsISiteSecurityService ); sss.clearAll(); }); // Make sure this test is valid. add_task(async function test_no_hsts_information_no_upgrade_again() { let httpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); gBrowser.removeCurrentTab(); }); // Visit a site with an iframe that loads first-party content that sends an // HSTS header. The header should be heeded because it's first-party. add_task(async function see_hsts_header_in_framed_first_party_context() { let framedUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://example.com" ) + "hsts_headers_framed.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { await ContentTaskUtils.waitForCondition(() => { return content.document.getElementById("done"); }); }); gBrowser.removeCurrentTab(); }); // Check that the framed, first-party header was heeded. add_task(async function test_http_upgrade_after_framed_first_party_header() { let httpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); gBrowser.removeCurrentTab(); }); // Visit a site with an iframe that loads third-party content that sends an // HSTS header. The header should be ignored because it's third-party. add_task(async function see_hsts_header_in_third_party_context() { let framedUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://example.com" ) + "hsts_headers_framed.html?third-party"; await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { await ContentTaskUtils.waitForCondition(() => { return content.document.getElementById("done"); }); }); gBrowser.removeCurrentTab(); }); // Since the HSTS header was not received in a first-party context, no upgrade // should occur. add_task(async function test_no_upgrade_for_third_party_header() { let url = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.org" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, url); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); gBrowser.removeCurrentTab(); }); // Clear state again. add_task(async function clear_hsts_state_again() { let sss = Cc["@mozilla.org/ssservice;1"].getService( Ci.nsISiteSecurityService ); sss.clearAll(); }); // HSTS information encountered in private contexts should not be used in // non-private contexts. add_task( async function test_no_upgrade_for_HSTS_information_from_private_window() { await SpecialPowers.pushPrefEnv({ set: [["dom.security.https_first_pbm", false]], }); let privateWindow = OpenBrowserWindow({ private: true }); await BrowserTestUtils.firstBrowserLoaded(privateWindow, false); let setHstsUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://example.com" ) + "hsts_headers.sjs"; await BrowserTestUtils.openNewForegroundTab( privateWindow.gBrowser, setHstsUrl ); privateWindow.gBrowser.removeCurrentTab(); let httpUrl = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ) + "some_content.html"; await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); gBrowser.removeCurrentTab(); privateWindow.close(); } );