From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../httpsonlyerror/tests/browser/browser.toml | 17 ++ .../tests/browser/browser_errorpage.js | 191 +++++++++++++++++++++ .../tests/browser/browser_errorpage_timeout.js | 53 ++++++ .../browser/browser_errorpage_www_suggestion.js | 80 +++++++++ .../tests/browser/browser_exception.js | 152 ++++++++++++++++ .../tests/browser/browser_fpi_nested_uri.js | 46 +++++ .../browser/file_errorpage_timeout_server.sjs | 15 ++ .../browser/file_errorpage_www_suggestion.html | 12 ++ .../tests/browser/file_upgrade_insecure_server.sjs | 108 ++++++++++++ .../httpsonlyerror/tests/browser/head.js | 99 +++++++++++ 10 files changed, 773 insertions(+) create mode 100644 toolkit/components/httpsonlyerror/tests/browser/browser.toml create mode 100644 toolkit/components/httpsonlyerror/tests/browser/browser_errorpage.js create mode 100644 toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_timeout.js create mode 100644 toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_www_suggestion.js create mode 100644 toolkit/components/httpsonlyerror/tests/browser/browser_exception.js create mode 100644 toolkit/components/httpsonlyerror/tests/browser/browser_fpi_nested_uri.js create mode 100644 toolkit/components/httpsonlyerror/tests/browser/file_errorpage_timeout_server.sjs create mode 100644 toolkit/components/httpsonlyerror/tests/browser/file_errorpage_www_suggestion.html create mode 100644 toolkit/components/httpsonlyerror/tests/browser/file_upgrade_insecure_server.sjs create mode 100644 toolkit/components/httpsonlyerror/tests/browser/head.js (limited to 'toolkit/components/httpsonlyerror/tests') diff --git a/toolkit/components/httpsonlyerror/tests/browser/browser.toml b/toolkit/components/httpsonlyerror/tests/browser/browser.toml new file mode 100644 index 0000000000..5bbad48226 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/browser.toml @@ -0,0 +1,17 @@ +[DEFAULT] +support-files = ["head.js"] + +["browser_errorpage.js"] +skip-if = ["os == 'linux' && asan && !debug"] # Bug 1658616 + +["browser_errorpage_timeout.js"] +support-files = ["file_errorpage_timeout_server.sjs"] + +["browser_errorpage_www_suggestion.js"] +support-files = ["file_errorpage_www_suggestion.html"] +skip-if = ["os == 'android'"] # no https-only errorpage support in android + +["browser_exception.js"] +support-files = ["file_upgrade_insecure_server.sjs"] + +["browser_fpi_nested_uri.js"] diff --git a/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage.js b/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage.js new file mode 100644 index 0000000000..43f46699c2 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage.js @@ -0,0 +1,191 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const SECURE_PAGE = "https://example.com/"; +const GOOD_PAGE = "http://example.com/"; +const BAD_CERT = "http://expired.example.com/"; +const UNKNOWN_ISSUER = "http://self-signed.example.com/"; + +const { TabStateFlusher } = ChromeUtils.importESModule( + "resource:///modules/sessionstore/TabStateFlusher.sys.mjs" +); + +add_task(async function () { + info("Check that the error pages shows up"); + + await Promise.all([ + testPageWithURI( + GOOD_PAGE, + "Should not show error page on upgradeable website.", + false + ), + testPageWithURI( + BAD_CERT, + "Should show error page on bad-certificate error.", + true + ), + testPageWithURI( + UNKNOWN_ISSUER, + "Should show error page on unkown-issuer error.", + true + ), + ]); +}); + +add_task(async function () { + info("Check that the go-back button returns to previous page"); + + // Test with and without being in an iFrame + for (let useFrame of [false, true]) { + let tab = await openErrorPage(BAD_CERT, useFrame); + let browser = tab.linkedBrowser; + + is( + browser.webNavigation.canGoBack, + false, + "!webNavigation.canGoBack should be false." + ); + is( + browser.webNavigation.canGoForward, + false, + "webNavigation.canGoForward should be false." + ); + + // Populate the shistory entries manually, since it happens asynchronously + // and the following tests will be too soon otherwise. + await TabStateFlusher.flush(browser); + let { entries } = JSON.parse(SessionStore.getTabState(tab)); + is(entries.length, 1, "There should be 1 shistory entry."); + + let bc = browser.browsingContext; + if (useFrame) { + bc = bc.children[0]; + } + + if (useFrame) { + await SpecialPowers.spawn(bc, [], async function () { + let returnButton = content.document.getElementById("goBack"); + is( + returnButton, + null, + "Return-button should not be present in iFrame." + ); + }); + } else { + let locationChangePromise = BrowserTestUtils.waitForLocationChange( + gBrowser, + "about:home" + ); + await SpecialPowers.spawn(bc, [], async function () { + let returnButton = content.document.getElementById("goBack"); + is( + returnButton.getAttribute("autofocus"), + "true", + "Return-button should have focus." + ); + returnButton.click(); + }); + + await locationChangePromise; + + is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack"); + is( + browser.webNavigation.canGoForward, + false, + "!webNavigation.canGoForward" + ); + is(gBrowser.currentURI.spec, "about:home", "Went back"); + } + + BrowserTestUtils.removeTab(gBrowser.selectedTab); + } +}); + +add_task(async function () { + info("Check that the go-back button returns to about:home"); + + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, SECURE_PAGE); + let browser = gBrowser.selectedBrowser; + + let errorPageLoaded = BrowserTestUtils.waitForErrorPage(browser); + BrowserTestUtils.startLoadingURIString(browser, BAD_CERT); + await errorPageLoaded; + + is( + browser.webNavigation.canGoBack, + true, + "webNavigation.canGoBack should be true before navigation." + ); + is( + browser.webNavigation.canGoForward, + false, + "webNavigation.canGoForward should be false before navigation." + ); + + // Populate the shistory entries manually, since it happens asynchronously + // and the following tests will be too soon otherwise. + await TabStateFlusher.flush(browser); + let { entries } = JSON.parse(SessionStore.getTabState(tab)); + is(entries.length, 2, "There should be 1 shistory entries."); + + let pageShownPromise = BrowserTestUtils.waitForContentEvent( + browser, + "pageshow", + true + ); + + // Click on "go back" Button + await SpecialPowers.spawn(browser, [], async function () { + let returnButton = content.document.getElementById("goBack"); + returnButton.click(); + }); + await pageShownPromise; + + is( + browser.webNavigation.canGoBack, + false, + "webNavigation.canGoBack should be false after navigation." + ); + is( + browser.webNavigation.canGoForward, + true, + "webNavigation.canGoForward should be true after navigation." + ); + is( + gBrowser.currentURI.spec, + SECURE_PAGE, + "Should go back to previous page after button click." + ); + + BrowserTestUtils.removeTab(gBrowser.selectedTab); +}); + +// Utils + +async function testPageWithURI(uri, message, expect) { + // Open new Tab with URI + let tab; + if (expect) { + tab = await openErrorPage(uri, false); + } else { + tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri, true); + } + + // Check if HTTPS-Only Error-Page loaded instead + let browser = tab.linkedBrowser; + await SpecialPowers.spawn( + browser, + [message, expect], + function (message, expect) { + const doc = content.document; + let result = doc.documentURI.startsWith("about:httpsonlyerror"); + is(result, expect, message); + } + ); + + // Close tab again + BrowserTestUtils.removeTab(tab); +} diff --git a/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_timeout.js b/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_timeout.js new file mode 100644 index 0000000000..853d93694a --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_timeout.js @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +// We need to request longer timeout because HTTPS-Only Mode sends the +// backround http request with a delay of N milliseconds before the +// actual load gets cancelled. +requestLongerTimeout(5); + +const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); +const TEST_PATH_HTTPS = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const TIMEOUT_PAGE_URI_HTTP = + TEST_PATH_HTTP + "file_errorpage_timeout_server.sjs"; +const TIMEOUT_PAGE_URI_HTTPS = + TEST_PATH_HTTPS + "file_errorpage_timeout_server.sjs"; + +add_task(async function avoid_timeout_and_show_https_only_error_page() { + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + let loaded = BrowserTestUtils.browserLoaded( + browser, + false, // includeSubFrames = false, no need to includeSubFrames + TIMEOUT_PAGE_URI_HTTPS, // Wait for upgraded page to timeout + true // maybeErrorPage = true, because we need the error page to appear + ); + BrowserTestUtils.startLoadingURIString(browser, TIMEOUT_PAGE_URI_HTTP); + await loaded; + + await SpecialPowers.spawn(browser, [], async function () { + const doc = content.document; + let errorPage = doc.body.innerHTML; + // It's possible that fluent has not been translated when running in + // chaos mode, hence let's rather use an element id for verification + // that the https-only mode error page has loaded. + ok( + errorPage.includes("about-httpsonly-button-continue-to-site"), + "Potential time-out in https-only mode should cause error page to appear!" + ); + // Verify that the right title is set. + ok( + errorPage.includes("about-httpsonly-title-site-not-available"), + "Potential time-out in https-only mode should cause error page to appear with right title!" + ); + }); + }); +}); diff --git a/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_www_suggestion.js b/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_www_suggestion.js new file mode 100644 index 0000000000..7e3eac9817 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/browser_errorpage_www_suggestion.js @@ -0,0 +1,80 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; +requestLongerTimeout(2); + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "" +); +const HTML_PATH = "/file_errorpage_www_suggestion.html"; +const KICK_OF_REQUEST_WITH_SUGGESTION = + "http://suggestion-example.com" + TEST_PATH + HTML_PATH; + +add_task(async function () { + info("Check that the www button shows up and leads to a secure www page"); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_only_mode", true], + ["dom.security.https_only_mode_send_http_background_request", false], + ["dom.security.https_only_mode_error_page_user_suggestions", true], + ], + }); + + let browser = gBrowser.selectedBrowser; + let errorPageLoaded = BrowserTestUtils.waitForErrorPage(browser); + BrowserTestUtils.startLoadingURIString( + browser, + KICK_OF_REQUEST_WITH_SUGGESTION + ); + await errorPageLoaded; + + let pageShownPromise = BrowserTestUtils.waitForContentEvent( + browser, + "pageshow", + true + ); + + // There's an arbitrary interval of 2 seconds in which the background + // request for the www page is made. we wait this out to ensure the + // www button has shown up. + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(c => setTimeout(c, 2000)); + + await SpecialPowers.spawn(browser, [], async function () { + let doc = content.document; + let innerHTML = doc.body.innerHTML; + let errorPageL10nId = "about-httpsonly-title-alert"; + let suggestionBoxL10nId = "about-httpsonly-suggestion-box-www-text"; + + ok(innerHTML.includes(errorPageL10nId), "the error page should show up"); + ok(doc.documentURI.startsWith("about:httpsonlyerror")); + ok( + innerHTML.includes(suggestionBoxL10nId), + "the suggestion box should show up" + ); + + // click on www button + let wwwButton = content.document.getElementById("openWWW"); + Assert.notStrictEqual(wwwButton, null, "The www Button should be shown"); + + if (!wwwButton) { + ok(false, "We should not be here"); + } else { + wwwButton.click(); + } + }); + await pageShownPromise; + await SpecialPowers.spawn(browser, [], async function () { + let doc = content.document; + let innerHTML = doc.body.innerHTML; + ok( + innerHTML.includes("You are now on the secure www. page"), + "The secure page should be reached after clicking the button" + ); + ok(doc.documentURI.startsWith("https://www."), "Page should be secure www"); + }); +}); diff --git a/toolkit/components/httpsonlyerror/tests/browser/browser_exception.js b/toolkit/components/httpsonlyerror/tests/browser/browser_exception.js new file mode 100644 index 0000000000..7cf98b467f --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/browser_exception.js @@ -0,0 +1,152 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const ROOT_PATH = getRootDirectory(gTestPath); +const EXPIRED_ROOT_PATH = ROOT_PATH.replace( + "chrome://mochitests/content", + "http://supports-insecure.expired.example.com" +); +const SECURE_ROOT_PATH = ROOT_PATH.replace( + "chrome://mochitests/content", + "http://example.com" +); +const INSECURE_ROOT_PATH = ROOT_PATH.replace( + "chrome://mochitests/content", + "http://example.com" +); + +// This is how this test works: +// +// +----[REQUEST] https://file_upgrade_insecure_server.sjs?queryresult +// | +// | +-[REQUEST] http://file_upgrade_insecure_server.sjs?content +// | | -> Internal HTTPS redirect +// | | +// | +>[RESPONSE] Expired Certificate Response +// | -> HTTPS-Only Mode Error Page shows up +// | -> Click exception button +// | +// | +-[REQUEST] http://file_upgrade_insecure_server.sjs?content +// | | +// | +>[RESPONSE] Webpage with a bunch of sub-resources +// | -> http://file_upgrade_insecure_ser^er.sjs?img +// | -> http://file_upgrade_insecure_server.sjs?xhr +// | -> http://file_upgrade_insecure_server.sjs?iframe +// | -> etc. +// | +// +--->[RESPONSE] List of all recorded requests and whether they were loaded +// with HTTP or not (eg.: img-ok, xhr-ok, iframe-error, ...) + +add_task(async function () { + const testCases = ["default", "private", "firstpartyisolation"]; + for (let i = 0; i < testCases.length; i++) { + // Call sjs-file with setup query-string and store promise + let expectedQueries = new Set([ + "content", + "img", + "iframe", + "xhr", + "nestedimg", + ]); + + const filesLoaded = setupFileServer(); + // Since we don't know when the server has saved all it's variables, + // let's wait a bit before reloading the page. + await new Promise(resolve => executeSoon(resolve)); + + // Create a new private window but reuse the normal one. + let privateWindow = false; + if (testCases[i] === "private") { + privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + } else if (testCases[i] === "firstpartyisolation") { + await SpecialPowers.pushPrefEnv({ + set: [["privacy.firstparty.isolate", true]], + }); + } + + // Create new tab with sjs-file requesting content. + // "supports-insecure.expired.example.com" responds to http and https but + // with an expired certificate + let tab = await openErrorPage( + `${EXPIRED_ROOT_PATH}file_upgrade_insecure_server.sjs?content`, + false, + privateWindow + ); + let browser = tab.linkedBrowser; + + let pageShownPromise = BrowserTestUtils.waitForContentEvent( + browser, + "pageshow", + true + ); + + await waitForAndClickOpenInsecureButton(browser); + + await pageShownPromise; + + // Check if the original page got loaded with http this time + await SpecialPowers.spawn(browser, [], async function () { + let doc = content.document; + ok( + !doc.documentURI.startsWith("http://expired.example.com"), + "Page should load normally after exception button was clicked." + ); + }); + + // Wait for initial sjs request to resolve + let results = await filesLoaded; + + for (let resultIndex in results) { + const response = results[resultIndex]; + // A response looks either like this "iframe-ok" or "[key]-[result]" + const [key, result] = response.split("-", 2); + // try to find the expected result within the results array + if (expectedQueries.has(key)) { + expectedQueries.delete(key); + is(result, "ok", `Request '${key}' should be loaded with HTTP.'`); + } else { + ok(false, `Unexpected response from server (${response})`); + } + } + + // Clean up permissions, tab and potentially preferences + Services.perms.removeAll(); + + if (testCases[i] === "firstpartyisolation") { + await SpecialPowers.popPrefEnv(); + } + + if (privateWindow) { + await BrowserTestUtils.closeWindow(privateWindow); + } else { + gBrowser.removeCurrentTab(); + } + } +}); + +function setupFileServer() { + // We initialize the upgrade-server with the queryresult query-string. + // We'll get a response once all files have been requested and then + // can see if they have been requested with http. + return new Promise((resolve, reject) => { + var xhrRequest = new XMLHttpRequest(); + xhrRequest.open( + "GET", + `${SECURE_ROOT_PATH}file_upgrade_insecure_server.sjs?queryresult=${INSECURE_ROOT_PATH}` + ); + xhrRequest.onload = function (e) { + var results = xhrRequest.responseText.split(","); + resolve(results); + }; + xhrRequest.onerror = e => { + ok(false, "Could not query results from server (" + e.message + ")"); + reject(); + }; + xhrRequest.send(); + }); +} diff --git a/toolkit/components/httpsonlyerror/tests/browser/browser_fpi_nested_uri.js b/toolkit/components/httpsonlyerror/tests/browser/browser_fpi_nested_uri.js new file mode 100644 index 0000000000..45bf718f3f --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/browser_fpi_nested_uri.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that a nested URI (in this case `view-source:`) does not result +// in a redirect loop when HTTPS-Only and First Party Isolation are +// enabled (Bug 1855734). + +const INSECURE_VIEW_SOURCE_URL = "view-source:http://123.123.123.123/"; + +function promiseIsErrorPage() { + return new Promise(resolve => { + BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser).then(() => + resolve(true) + ); + BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => + resolve(false) + ); + }); +} + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_only_mode", true], + ["dom.security.https_only_mode.upgrade_local", true], + ["privacy.firstparty.isolate", true], + ], + }); + + let loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); + info(`Starting to load ${INSECURE_VIEW_SOURCE_URL}`); + BrowserTestUtils.startLoadingURIString(gBrowser, INSECURE_VIEW_SOURCE_URL); + await loaded; + info(`${INSECURE_VIEW_SOURCE_URL} finished loading`); + + loaded = promiseIsErrorPage(); + await waitForAndClickOpenInsecureButton(gBrowser.selectedBrowser); + info(`Waiting for normal or error page to load`); + const isErrorPage = await loaded; + + ok(!isErrorPage, "We should not land on an error page"); + + await Services.perms.removeAll(); +}); diff --git a/toolkit/components/httpsonlyerror/tests/browser/file_errorpage_timeout_server.sjs b/toolkit/components/httpsonlyerror/tests/browser/file_errorpage_timeout_server.sjs new file mode 100644 index 0000000000..f77d5351b5 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/file_errorpage_timeout_server.sjs @@ -0,0 +1,15 @@ +// Custom *.sjs file specifically for the needs of Bug 1657348 + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.scheme === "https") { + // Simulating a timeout by processing the https request + // async and *never* return anything! + response.processAsync(); + return; + } + // we should never get here; just in case, return something unexpected + response.write("do'h"); +} diff --git a/toolkit/components/httpsonlyerror/tests/browser/file_errorpage_www_suggestion.html b/toolkit/components/httpsonlyerror/tests/browser/file_errorpage_www_suggestion.html new file mode 100644 index 0000000000..9d5c42ca73 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/file_errorpage_www_suggestion.html @@ -0,0 +1,12 @@ + + + + + Bug 1665057 - Add www button on https-only error page + + +
+ You are now on the secure www. page +
+ + diff --git a/toolkit/components/httpsonlyerror/tests/browser/file_upgrade_insecure_server.sjs b/toolkit/components/httpsonlyerror/tests/browser/file_upgrade_insecure_server.sjs new file mode 100644 index 0000000000..e05ea7b3a3 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/file_upgrade_insecure_server.sjs @@ -0,0 +1,108 @@ +// Serverside Javascript for browser_exception.js +// Bug 1625156 - Error page for HTTPS Only Mode + +const expectedQueries = ["content", "img", "iframe", "xhr", "nestedimg"]; +const TOTAL_EXPECTED_REQUESTS = expectedQueries.length; + +const CONTENT = path => ` + + + + + + +

Insecure website

+ + + + +`; + +const IFRAME_CONTENT = path => ` + + + + + + +

Nested insecure website

+ + +`; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + var queryString = request.queryString; + + // initialize server variables and save the object state + // of the initial request, which returns async once the + // server has processed all requests. + if (queryString.startsWith("queryresult")) { + response.processAsync(); + setState("totaltests", TOTAL_EXPECTED_REQUESTS.toString()); + setState("receivedQueries", ""); + setState("rootPath", /=(.+)/.exec(queryString)[1]); + setObjectState("queryResult", response); + return; + } + + // just in case error handling for unexpected queries + if (!expectedQueries.includes(queryString)) { + response.write("unexpected-response"); + return; + } + + // make sure all the requested queries are indeed http + const testResult = + queryString + (request.scheme == "http" ? "-ok" : "-error"); + + var receivedQueries = getState("receivedQueries"); + + // images, scripts, etc. get queried twice, do not + // confuse the server by storing the preload as + // well as the actual load. If either the preload + // or the actual load is not https, then we would + // append "-error" in the array and the test would + // fail at the end. + if (receivedQueries.includes(testResult)) { + return; + } + + // append the result to the total query string array + if (receivedQueries != "") { + receivedQueries += ","; + } + receivedQueries += testResult; + setState("receivedQueries", receivedQueries); + + // keep track of how many more requests the server + // is expecting + var totaltests = parseInt(getState("totaltests")); + totaltests -= 1; + setState("totaltests", totaltests.toString()); + + // Respond with html content + if (queryString == "content") { + response.write(CONTENT(getState("rootPath"))); + } else if (queryString == "iframe") { + response.write(IFRAME_CONTENT(getState("rootPath"))); + } + + // if we have received all the requests, we return + // the result back. + if (totaltests == 0) { + getObjectState("queryResult", function (queryResponse) { + if (!queryResponse) { + return; + } + var receivedQueries = getState("receivedQueries"); + queryResponse.write(receivedQueries); + queryResponse.finish(); + }); + } +} diff --git a/toolkit/components/httpsonlyerror/tests/browser/head.js b/toolkit/components/httpsonlyerror/tests/browser/head.js new file mode 100644 index 0000000000..7efbfbe8b5 --- /dev/null +++ b/toolkit/components/httpsonlyerror/tests/browser/head.js @@ -0,0 +1,99 @@ +// Enable HTTPS-Only Mode +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_only_mode", true]], + }); +}); + +// Copied from: https://searchfox.org/mozilla-central/rev/9f074fab9bf905fad62e7cc32faf121195f4ba46/browser/base/content/test/about/head.js + +async function injectErrorPageFrame(tab, src, sandboxed) { + let loadedPromise = BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + true, + null, + true + ); + + await SpecialPowers.spawn( + tab.linkedBrowser, + [src, sandboxed], + async function (frameSrc, frameSandboxed) { + let iframe = content.document.createElement("iframe"); + iframe.src = frameSrc; + if (frameSandboxed) { + iframe.setAttribute("sandbox", "allow-scripts"); + } + content.document.body.appendChild(iframe); + } + ); + + await loadedPromise; +} + +async function openErrorPage(src, useFrame, privateWindow, sandboxed) { + let gb = gBrowser; + if (privateWindow) { + gb = privateWindow.gBrowser; + } + let dummyPage = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" + ) + "dummy_page.html"; + + let tab; + if (useFrame) { + info("Loading error page in an iframe"); + tab = await BrowserTestUtils.openNewForegroundTab(gb, dummyPage); + await injectErrorPageFrame(tab, src, sandboxed); + } else { + let ErrorPageLoaded; + tab = await BrowserTestUtils.openNewForegroundTab( + gb, + () => { + gb.selectedTab = BrowserTestUtils.addTab(gb, src); + let browser = gb.selectedBrowser; + ErrorPageLoaded = BrowserTestUtils.waitForErrorPage(browser); + }, + false + ); + info("Loading and waiting for the error page"); + await ErrorPageLoaded; + } + + return tab; +} + +/** + * On a loaded HTTPS-Only error page, waits until the "Open Insecure" + * button gets enabled and then presses it. + * + * @returns {Promise} + */ +function waitForAndClickOpenInsecureButton(browser) { + return SpecialPowers.spawn(browser, [], async function () { + let openInsecureButton = content.document.getElementById("openInsecure"); + Assert.notEqual( + openInsecureButton, + null, + "openInsecureButton should exist." + ); + info("Waiting for openInsecureButton to be enabled."); + function callback() { + if (!openInsecureButton.inert) { + info("openInsecureButton was enabled, waiting two frames."); + observer.disconnect(); + content.requestAnimationFrame(() => { + content.requestAnimationFrame(() => { + info("clicking openInsecureButton."); + openInsecureButton.click(); + }); + }); + } + } + const observer = new content.MutationObserver(callback); + observer.observe(openInsecureButton, { attributeFilter: ["inert"] }); + callback(); + }); +} -- cgit v1.2.3