Bug 1644914 - Give out user interactions to session history entries when system principal initiates a load. r=smaug

This is a pretty cheap way of fixing this bug by saying nsDocShell::loadURI calls
done with a system principal will add user interaction to the current page. This takes
advantage of the fact that all UI code for loading URIs goes through this code path.

Note that during debugging I've found other cases where SH entries would be added with
a system principal, most notably when navigating to URL hashes/fragments (example.com#hash).
I'm not sure why this is happening but it doesn't go through nsDocShell::loadURI.

Differential Revision: https://phabricator.services.mozilla.com/D127558
This commit is contained in:
Johann Hofmann 2021-10-11 16:51:01 +00:00
Родитель e664fcf0f0
Коммит 479107443c
5 изменённых файлов: 128 добавлений и 8 удалений

Просмотреть файл

@ -850,6 +850,29 @@ nsresult nsDocShell::LoadURI(nsDocShellLoadState* aLoadState,
"Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI");
// If we have a system triggering principal, we can assume that this load was
// triggered by some UI in the browser chrome, such as the URL bar or
// bookmark bar. This should count as a user interaction for the current sh
// entry, so that the user may navigate back to the current entry, from the
// entry that is going to be added as part of this load.
nsCOMPtr<nsIPrincipal> triggeringPrincipal =
aLoadState->TriggeringPrincipal();
if (triggeringPrincipal && triggeringPrincipal->IsSystemPrincipal()) {
if (mozilla::SessionHistoryInParent()) {
WindowContext* topWc = mBrowsingContext->GetTopWindowContext();
if (topWc && !topWc->IsDiscarded()) {
MOZ_ALWAYS_SUCCEEDS(topWc->SetSHEntryHasUserInteraction(true));
}
} else {
bool oshe = false;
nsCOMPtr<nsISHEntry> currentSHEntry;
GetCurrentSHEntry(getter_AddRefs(currentSHEntry), &oshe);
if (currentSHEntry) {
currentSHEntry->SetHasUserInteraction(true);
}
}
}
rv = InternalLoad(aLoadState);
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -84,6 +84,7 @@ support-files =
skip-if =
os == "linux" && bits == 64 && !debug # Bug 1607713
[browser_backforward_userinteraction_about.js]
[browser_backforward_userinteraction_systemprincipal.js]
[browser_bug1543077-3.js]
[browser_bug1594938.js]
[browser_bug1206879.js]

Просмотреть файл

@ -353,12 +353,6 @@ add_task(async function test_pushState() {
await runTopLevelTest(pushState);
});
// Test that when the pref is flipped, we are skipping history
// entries without user interaction when using loadURI.
add_task(async function test_loadURI() {
await runTopLevelTest(loadURI);
});
// Test that when the pref is flipped, we are skipping history
// entries without user interaction when following a link.
add_task(async function test_followLink() {

Просмотреть файл

@ -26,10 +26,10 @@ add_task(async function test_about_back() {
let browser = tab.linkedBrowser;
assertBackForwardState(false, false);
await loadURI(TEST_PAGE + "?entry=1");
await followLink(TEST_PAGE + "?entry=1");
assertBackForwardState(true, false);
await loadURI(TEST_PAGE + "?entry=2");
await followLink(TEST_PAGE + "?entry=2");
assertBackForwardState(true, false);
// Add some user interaction to entry 2

Просмотреть файл

@ -0,0 +1,102 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_PAGE =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "dummy_page.html";
async function runTest(privilegedLoad) {
// Test with both pref on and off
for (let requireUserInteraction of [true, false]) {
Services.prefs.setBoolPref(
"browser.navigation.requireUserInteraction",
requireUserInteraction
);
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_PAGE + "?entry=0"
);
assertBackForwardState(false, false);
await followLink(TEST_PAGE + "?entry=1");
assertBackForwardState(true, false);
await followLink(TEST_PAGE + "?entry=2");
assertBackForwardState(true, false);
await followLink(TEST_PAGE + "?entry=3");
assertBackForwardState(true, false);
// Entry 4 will be added through a user action in browser chrome,
// giving user interaction to entry 3. Entry 4 should not gain automatic
// user interaction.
await privilegedLoad(TEST_PAGE + "?entry=4");
assertBackForwardState(true, false);
await followLink(TEST_PAGE + "?entry=5");
assertBackForwardState(true, false);
if (!requireUserInteraction) {
await goBack(TEST_PAGE + "?entry=4");
}
await goBack(TEST_PAGE + "?entry=3");
if (!requireUserInteraction) {
await goBack(TEST_PAGE + "?entry=2");
await goBack(TEST_PAGE + "?entry=1");
}
assertBackForwardState(true, true);
await goBack(TEST_PAGE + "?entry=0");
assertBackForwardState(false, true);
if (!requireUserInteraction) {
await goForward(TEST_PAGE + "?entry=1");
await goForward(TEST_PAGE + "?entry=2");
}
await goForward(TEST_PAGE + "?entry=3");
assertBackForwardState(true, true);
if (!requireUserInteraction) {
await goForward(TEST_PAGE + "?entry=4");
}
await goForward(TEST_PAGE + "?entry=5");
assertBackForwardState(true, false);
BrowserTestUtils.removeTab(tab);
}
Services.prefs.clearUserPref("browser.navigation.requireUserInteraction");
}
// Test that we add a user interaction flag to the previous site when loading
// a new site from user interaction with privileged UI, e.g. through the
// URL bar.
add_task(async function test_urlBar() {
await runTest(async function(url) {
info(`Loading ${url} via the URL bar.`);
let browser = gBrowser.selectedBrowser;
let loaded = BrowserTestUtils.browserLoaded(browser, false, url);
gURLBar.focus();
gURLBar.value = url;
gURLBar.goButton.click();
await loaded;
});
});