tor-browser

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

commit 5eea86343d639895cb6d00b05270dae576f3bc4c
parent a091e7c4c132680be00a5021386dcad16f6b45df
Author: Henrik Skupin <mail@hskupin.info>
Date:   Mon,  1 Dec 2025 20:43:58 +0000

Bug 2000801 - [remote] Update Navigable Manager for parent process browsing contexts. r=jdescottes

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

Diffstat:
Mremote/shared/NavigableManager.sys.mjs | 67+++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mremote/shared/test/browser/browser_NavigableManager.js | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 157 insertions(+), 18 deletions(-)

diff --git a/remote/shared/NavigableManager.sys.mjs b/remote/shared/NavigableManager.sys.mjs @@ -5,6 +5,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { + BiMap: "chrome://remote/content/shared/BiMap.sys.mjs", BrowsingContextListener: "chrome://remote/content/shared/listeners/BrowsingContextListener.sys.mjs", generateUUID: "chrome://remote/content/shared/UUID.sys.mjs", @@ -23,10 +24,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * that is not implemented in Firefox. */ class NavigableManagerClass { - #tracking; #browserIds; + #chromeNavigables; #contextListener; #navigableIds; + #tracking; constructor() { this.#tracking = false; @@ -38,6 +40,10 @@ class NavigableManagerClass { // context id from the formerly known browser. this.#browserIds = new WeakMap(); + // Maps canonical browsing contexts from the parent process + // to a uuid and vice versa. + this.#chromeNavigables = new lazy.BiMap(); + // Maps browsing contexts to uuid: WeakMap.<BrowsingContext, string>. this.#navigableIds = new WeakMap(); @@ -77,19 +83,23 @@ class NavigableManagerClass { * @param {string} id * A browsing context unique id (created by getIdForBrowsingContext). * - * @returns {BrowsingContext=} + * @returns {BrowsingContext|null} * The browsing context found for this id, null if none was found or * browsing context is discarded. */ getBrowsingContextById(id) { let browsingContext; - const browser = this.getBrowserById(id); - if (browser) { - // top-level browsing context - browsingContext = browser.browsingContext; + if (this.#chromeNavigables.hasId(id)) { + browsingContext = this.#chromeNavigables.getObject(id); } else { - browsingContext = BrowsingContext.get(id); + const browser = this.getBrowserById(id); + if (browser) { + // top-level browsing context + browsingContext = browser.browsingContext; + } else { + browsingContext = BrowsingContext.get(id); + } } if (!browsingContext || browsingContext.isDiscarded) { @@ -120,11 +130,10 @@ class NavigableManagerClass { return null; } - const key = browser.permanentKey; - if (!this.#browserIds.has(key)) { - this.#browserIds.set(key, lazy.generateUUID()); - } - return this.#browserIds.get(key); + return this.#browserIds.getOrInsertComputed( + browser.permanentKey, + lazy.generateUUID + ); } /** @@ -143,6 +152,12 @@ class NavigableManagerClass { return null; } + if (!browsingContext.isContent) { + // When the browsing context runs in the parent process we + // can use the browsing context as key because it's stable. + return this.#chromeNavigables.getOrInsert(browsingContext); + } + if (!browsingContext.parent) { // For top-level browsing contexts always try to use the browser // as navigable first because it survives a cross-process navigation. @@ -194,14 +209,16 @@ class NavigableManagerClass { return; } - lazy.TabManager.getBrowsers().forEach(browser => - this.#setIdForBrowsingContext(browser.browsingContext) - ); - this.#contextListener = new lazy.BrowsingContextListener(); this.#contextListener.on("attached", this.#onContextAttached); + this.#contextListener.on("discarded", this.#onContextDiscarded); this.#contextListener.startListening(); + // Register as well all browsing contexts from already open tabs. + lazy.TabManager.getBrowsers().forEach(browser => + this.#setIdForBrowsingContext(browser.browsingContext) + ); + this.#tracking = true; } @@ -210,9 +227,12 @@ class NavigableManagerClass { return; } + this.#contextListener.off("attached", this.#onContextAttached); + this.#contextListener.off("discarded", this.#onContextDiscarded); this.#contextListener.stopListening(); this.#contextListener = null; + this.#chromeNavigables.clear(); this.#browserIds = new WeakMap(); this.#navigableIds = new WeakMap(); @@ -255,8 +275,19 @@ class NavigableManagerClass { #onContextAttached = (_, data = {}) => { const { browsingContext } = data; - if (lazy.TabManager.isValidCanonicalBrowsingContext(browsingContext)) { - this.#setIdForBrowsingContext(browsingContext); + if (!browsingContext.isContent) { + this.#chromeNavigables.getOrInsert(browsingContext); + return; + } + + this.#setIdForBrowsingContext(browsingContext); + }; + + #onContextDiscarded = (_, data = {}) => { + const { browsingContext } = data; + + if (!browsingContext.isContent) { + this.#chromeNavigables.deleteByValue(browsingContext); } }; } diff --git a/remote/shared/test/browser/browser_NavigableManager.js b/remote/shared/test/browser/browser_NavigableManager.js @@ -439,4 +439,112 @@ describe("NavigableManager", function () { "Got a valid uuid for the top-level context" ); }); + + it("Get the Navigable id for a chrome browsing context", async function test_getIdForChromeBrowsingContext() { + // Get the parent process browsing context (chrome scope) + const chromeContext = window.browsingContext; + + ok(!chromeContext.isContent, "Chrome context is not a content context"); + + const chromeContextId = + NavigableManager.getIdForBrowsingContext(chromeContext); + + Assert.stringMatches( + chromeContextId, + uuidRegex, + "Got a valid uuid for chrome browsing context" + ); + + is( + NavigableManager.getIdForBrowsingContext(chromeContext), + chromeContextId, + "Id is always the same for the same chrome browsing context" + ); + + const chromeContext2 = BrowsingContext.getFromWindow( + Services.wm.getMostRecentWindow("navigator:browser") + ); + is( + NavigableManager.getIdForBrowsingContext(chromeContext2), + chromeContextId, + "Same chrome context returns same id when retrieved differently" + ); + }); + + it("Get chrome browsing context by its Navigable id", async function test_getChromeBrowsingContextById() { + const chromeContext = BrowsingContext.getFromWindow(window); + + ok(!chromeContext.isContent, "Chrome context is not a content context"); + + const chromeContextId = + NavigableManager.getIdForBrowsingContext(chromeContext); + + is( + NavigableManager.getBrowsingContextById(chromeContextId), + chromeContext, + "Chrome browsing context can be retrieved by its id" + ); + }); + + it("Chrome browsing contexts have different ids than content contexts", async function test_chromeVsContentIds() { + const { newContext } = testData; + const chromeContext = BrowsingContext.getFromWindow(window); + + const chromeContextId = + NavigableManager.getIdForBrowsingContext(chromeContext); + const contentContextId = + NavigableManager.getIdForBrowsingContext(newContext); + + Assert.stringMatches( + chromeContextId, + uuidRegex, + "Chrome context has valid uuid" + ); + Assert.stringMatches( + contentContextId, + uuidRegex, + "Content context has valid uuid" + ); + + isnot( + chromeContextId, + contentContextId, + "Chrome and content contexts have different ids" + ); + }); + + it("Chrome browsing context cleanup on discard", async function test_chromeBrowsingContextDiscard() { + // Open a new window to get a chrome browsing context we can close + const newWindow = await BrowserTestUtils.openNewBrowserWindow(); + const newChromeContext = BrowsingContext.getFromWindow(newWindow); + + ok( + !newChromeContext.isContent, + "New window's chrome context is not a content context" + ); + + const chromeContextId = + NavigableManager.getIdForBrowsingContext(newChromeContext); + + Assert.stringMatches( + chromeContextId, + uuidRegex, + "Got a valid uuid for new window's chrome context" + ); + + is( + NavigableManager.getBrowsingContextById(chromeContextId), + newChromeContext, + "Chrome browsing context can be retrieved by id" + ); + + // Close the new window + await BrowserTestUtils.closeWindow(newWindow); + + is( + NavigableManager.getBrowsingContextById(chromeContextId), + null, + "Discarded chrome browsing context has no navigable id" + ); + }); });