diff --git a/dom/security/test/moz.build b/dom/security/test/moz.build index 0fb27de75208..b50e6359ed01 100644 --- a/dom/security/test/moz.build +++ b/dom/security/test/moz.build @@ -38,4 +38,5 @@ BROWSER_CHROME_MANIFESTS += [ "https-first/browser.ini", "https-only/browser.ini", "mixedcontentblocker/browser.ini", + "sec-fetch/browser.ini", ] diff --git a/dom/security/test/sec-fetch/browser.ini b/dom/security/test/sec-fetch/browser.ini new file mode 100644 index 000000000000..b9642b438e04 --- /dev/null +++ b/dom/security/test/sec-fetch/browser.ini @@ -0,0 +1,4 @@ +[DEFAULT] +support-files = file_no_cache.sjs + +[browser_navigation.js] diff --git a/dom/security/test/sec-fetch/browser_navigation.js b/dom/security/test/sec-fetch/browser_navigation.js new file mode 100644 index 000000000000..fbfb15376839 --- /dev/null +++ b/dom/security/test/sec-fetch/browser_navigation.js @@ -0,0 +1,186 @@ +"use strict"; + +const REQUEST_URL = + "https://example.com/browser/dom/security/test/sec-fetch/file_no_cache.sjs"; + +let gTestCounter = 0; +let gExpectedHeader = {}; + +async function setup() { + waitForExplicitFinish(); + + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.secFetch.enabled", true]], + }); +} + +function checkSecFetchUser(subject, topic, data) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + if (!channel.URI.spec.startsWith("https://example.com/")) { + return; + } + + info(`testing headers for load of ${channel.URI.spec}`); + + const secFetchHeaders = [ + "sec-fetch-mode", + "sec-fetch-dest", + "sec-fetch-user", + "sec-fetch-site", + ]; + + secFetchHeaders.forEach(header => { + const expectedValue = gExpectedHeader[header]; + try { + is( + channel.getRequestHeader(header), + expectedValue, + `${header} is set to ${expectedValue}` + ); + } catch (e) { + if (expectedValue) { + ok(false, "required headers are set"); + } else { + ok(true, `${header} should not be set`); + } + } + }); + + gTestCounter++; +} + +async function testNavigations() { + gTestCounter = 0; + + // Load initial site + let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + BrowserTestUtils.loadURI(gBrowser, REQUEST_URL + "?test1"); + await loaded; + + // Load another site + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.document.notifyUserGestureActivation(); // simulate user activation + let test2Button = content.document.getElementById("test2_button"); + test2Button.click(); + content.document.clearUserGestureActivation(); + }); + await loaded; + // Load another site + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.document.notifyUserGestureActivation(); // simulate user activation + let test3Button = content.document.getElementById("test3_button"); + test3Button.click(); + content.document.clearUserGestureActivation(); + }); + await loaded; + + gExpectedHeader = { + "sec-fetch-mode": "navigate", + "sec-fetch-dest": "document", + "sec-fetch-site": "same-origin", + "sec-fetch-user": "?1", + }; + + // Register the http request observer. + // All following actions should cause requests with the sec-fetch-user header + // set. + Services.obs.addObserver(checkSecFetchUser, "http-on-stop-request"); + + // Go back one site by clicking the back button + info("Clicking back button"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + document.notifyUserGestureActivation(); // simulate user activation + let backButton = document.getElementById("back-button"); + backButton.click(); + document.clearUserGestureActivation(); + await loaded; + + // Reload the site by clicking the reload button + info("Clicking reload button"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + document.notifyUserGestureActivation(); // simulate user activation + let reloadButton = document.getElementById("reload-button"); + await TestUtils.waitForCondition(() => { + return !reloadButton.disabled; + }); + reloadButton.click(); + document.clearUserGestureActivation(); + await loaded; + + // Go forward one site by clicking the forward button + info("Clicking forward button"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + document.notifyUserGestureActivation(); // simulate user activation + let forwardButton = document.getElementById("forward-button"); + forwardButton.click(); + document.clearUserGestureActivation(); + await loaded; + + // Testing history.back/forward... + + info("going back with history.back"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.document.notifyUserGestureActivation(); // simulate user activation + content.history.back(); + content.document.clearUserGestureActivation(); + }); + await loaded; + + info("going forward with history.forward"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.document.notifyUserGestureActivation(); // simulate user activation + content.history.forward(); + content.document.clearUserGestureActivation(); + }); + await loaded; + + gExpectedHeader = { + "sec-fetch-mode": "navigate", + "sec-fetch-dest": "document", + "sec-fetch-site": "same-origin", + }; + + info("going back with history.back without user activation"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.history.back(); + }); + await loaded; + + info("going forward with history.forward without user activation"); + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.history.forward(); + }); + await loaded; + + ok(gTestCounter === 7, "testing that all five actions have been tested."); + + Services.obs.removeObserver(checkSecFetchUser, "http-on-stop-request"); +} + +add_task(async function() { + waitForExplicitFinish(); + + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.secFetch.enabled", true]], + }); + + await testNavigations(); + + // If fission is enabled we also want to test the navigations with the bfcache + // in the parent. + if (SpecialPowers.getBoolPref("fission.autostart")) { + await SpecialPowers.pushPrefEnv({ + set: [["fission.bfcacheInParent", true]], + }); + + await testNavigations(); + } + + finish(); +});