tor-browser

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

commit 6f18fa3f98d2a9370ba9843b93f94efacd85ae93
parent 70d833b7b5bb7bd25bc575326d19b9d8ee004933
Author: Stephen Thompson <sthompson@mozilla.com>
Date:   Mon, 29 Dec 2025 15:52:18 +0000

Bug 2005598 - update canonical URL on pushState r=dwalker,tabbrowser-reviewers

When TabNotesController.onLocationChange detects a tab navigating due to `history.pushState()`, it will request that the CanonicalURL actor re-detect the canonical URL in that tab. This allows the tab note state to change appropriately when navigating within a web site that uses `history.pushState()`.

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

Diffstat:
Mbrowser/components/tabnotes/CanonicalURLChild.sys.mjs | 13+++++++++++++
Mbrowser/components/tabnotes/TabNotesController.sys.mjs | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/browser/components/tabnotes/CanonicalURLChild.sys.mjs b/browser/components/tabnotes/CanonicalURLChild.sys.mjs @@ -27,6 +27,19 @@ export class CanonicalURLChild extends JSWindowActorChild { } /** + * Called when a message is received from the parent process. + * + * @param {ReceiveMessageArgument} msg + */ + receiveMessage(msg) { + switch (msg.name) { + case "CanonicalURL:Detect": + this.#discoverCanonicalUrl(); + break; + } + } + + /** * Find a canonical URL in the document and tell the parent about it. */ #discoverCanonicalUrl() { diff --git a/browser/components/tabnotes/TabNotesController.sys.mjs b/browser/components/tabnotes/TabNotesController.sys.mjs @@ -5,6 +5,8 @@ */ import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; +/** @import { CanonicalURLParent } from "./CanonicalURLParent.sys.mjs" */ + const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs", @@ -174,11 +176,57 @@ class TabNotesControllerClass { if (!aWebProgress.isTopLevel) { return; } - // If we're still on the same page, the tab note indicator does not need to change. + if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) { + if ( + aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD || + aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_HISTORY + ) { + // User is reloading/returning to the same document via history. We + // can count on CanonicalURLChild to listen for `pageshow` and tell us + // about the canonical URL at the new location. + lazy.logConsole.debug( + "reload/history navigation, waiting for pageshow", + aLocation.spec + ); + return; + } + + if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_HASHCHANGE) { + // The web site modified the hash/fragment identifier part of the URL + // directly. TODO: determine how and whether to handle `hashchange`. + lazy.logConsole.debug("fragment identifier changed", aLocation.spec); + return; + } + + if (aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE) { + // Web page is using `history.pushState()` to change URLs. There isn't + // a way for CanonicalURLChild to detect this in the content process, + // so we need to ask it to recalculate canonical URLs to see if they + // changed. + /** @type {CanonicalURLParent|undefined} */ + let parent = + aBrowser.browsingContext?.currentWindowGlobal.getActor( + "CanonicalURL" + ); + + parent?.sendAsyncMessage("CanonicalURL:Detect"); + lazy.logConsole.debug( + "requesting CanonicalURL:Detect due to history.pushState", + aLocation.spec + ); + return; + } + + // General same document case: we are navigating in the same document, + // so the tab note indicator does not need to change. return; } + // General case: we are doing normal navigation to another URL, so we + // clear the canonical URL/tab note state on the tab and wait for + // `CanonicalURL:Identified` to tell us whether the new location has + // a tab note. const tab = aBrowser.ownerGlobal.gBrowser.getTabForBrowser(aBrowser); tab.canonicalUrl = undefined; tab.hasTabNote = false;