tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 22e501aa0ae6f19b439861b27355afc2349ab72e
parent 8ac9b654258da137a48005f179a897c15b5e8a24
Author: Henrik Skupin <mail@hskupin.info>
Date:   Thu,  6 Nov 2025 07:25:11 +0000

Bug 1996845 - [dom] Fix the replacement detection for the browsing-context-discarded notification. r=nika

Differential Revision: https://phabricator.services.mozilla.com/D271416

Diffstat:
Mdocshell/base/BrowsingContext.cpp | 2+-
Mdocshell/test/browser/browser_browsing_context_discarded.js | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 74 insertions(+), 21 deletions(-)

diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp @@ -1115,7 +1115,7 @@ void BrowsingContext::Detach(bool aFromIPC) { // content process, but may be "replace" if it's known the context being // replaced in the parent process. const char16_t* why = u"discard"; - if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) { + if (XRE_IsParentProcess() && Canonical()->IsReplaced()) { why = u"replace"; } obs->NotifyObservers(ToSupports(this), "browsing-context-discarded", why); diff --git a/docshell/test/browser/browser_browsing_context_discarded.js b/docshell/test/browser/browser_browsing_context_discarded.js @@ -3,13 +3,13 @@ const TOPIC = "browsing-context-discarded"; async function observeDiscarded(browsingContexts, callback) { - let discarded = []; + let discarded = new Map(); - let promise = BrowserUtils.promiseObserved(TOPIC, subject => { + let promise = BrowserUtils.promiseObserved(TOPIC, (subject, why) => { ok(BrowsingContext.isInstance(subject), "subject to be a BrowsingContext"); - discarded.push(subject); + discarded.set(subject, why); - return browsingContexts.every(item => discarded.includes(item)); + return browsingContexts.every(item => discarded.has(item)); }); await callback(); await promise; @@ -17,39 +17,64 @@ async function observeDiscarded(browsingContexts, callback) { return discarded; } +function check_reason(discardedContexts, expected) { + discardedContexts.forEach((why, browsingContext) => { + if (expected.has(browsingContext)) { + is(why, expected.get(browsingContext)); + } + }); +} + add_task(async function toplevelForNewWindow() { - let win = await BrowserTestUtils.openNewBrowserWindow(); - let browsingContext = win.gBrowser.selectedBrowser.browsingContext; + const win = await BrowserTestUtils.openNewBrowserWindow(); + const browsingContext = win.gBrowser.selectedBrowser.browsingContext; + + const expected = new Map([ + [win.browsingContext, "discard"], + [browsingContext, "discard"], + ]); - await observeDiscarded([win.browsingContext, browsingContext], async () => { + const discarded = await observeDiscarded([...expected.keys()], async () => { await BrowserTestUtils.closeWindow(win); }); + + check_reason(discarded, expected); }); add_task(async function toplevelForNewTab() { - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); - let browsingContext = tab.linkedBrowser.browsingContext; + const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); + const browsingContext = tab.linkedBrowser.browsingContext; + + const expected = new Map([[browsingContext, "discard"]]); - let discarded = await observeDiscarded([browsingContext], () => { + const discarded = await observeDiscarded([...expected.keys()], () => { BrowserTestUtils.removeTab(tab); }); ok( - !discarded.includes(window.browsingContext), + !discarded.has(window.browsingContext), "no notification for the current window's chrome browsing context" ); + + check_reason(discarded, expected); }); add_task(async function subframe() { - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); - let browsingContext = await SpecialPowers.spawn(tab.linkedBrowser, [], () => { - let iframe = content.document.createElement("iframe"); - content.document.body.appendChild(iframe); - iframe.contentWindow.location = "https://example.com/"; - return iframe.browsingContext; - }); + const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); + const frameBrowsingContext = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + const iframe = content.document.createElement("iframe"); + content.document.body.appendChild(iframe); + iframe.contentWindow.location = "https://example.com/"; + return iframe.browsingContext; + } + ); - let discarded = await observeDiscarded([browsingContext], async () => { + const expected = new Map([[frameBrowsingContext, "discard"]]); + + const discarded = await observeDiscarded([...expected.keys()], async () => { await SpecialPowers.spawn(tab.linkedBrowser, [], () => { let iframe = content.document.querySelector("iframe"); iframe.remove(); @@ -57,9 +82,37 @@ add_task(async function subframe() { }); ok( - !discarded.includes(tab.browsingContext), + !discarded.has(tab.linkedBrowser.browsingContext), "no notification for toplevel browsing context" ); + ok( + !discarded.has(window.browsingContext), + "no notification for the current window's chrome browsing context" + ); + + check_reason(discarded, expected); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function replaceToplevel() { + const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser); + const browsingContext = tab.linkedBrowser.browsingContext; + + const expected = new Map([[browsingContext, "replace"]]); + + const discarded = await observeDiscarded([...expected.keys()], async () => { + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.location = "about:newtab"; + }); + }); + + ok( + !discarded.has(window.browsingContext), + "no notification for the current window's chrome browsing context" + ); + + check_reason(discarded, expected); BrowserTestUtils.removeTab(tab); });