diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs b/toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs new file mode 100644 index 0000000000..2d33706427 --- /dev/null +++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs @@ -0,0 +1,209 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", +}); + +// This object implements the JS parts of nsIWebNavigation. +export class RemoteWebNavigation { + constructor(aBrowser) { + this._browser = aBrowser; + this._cancelContentJSEpoch = 1; + this._currentURI = null; + this._canGoBack = false; + this._canGoForward = false; + this.referringURI = null; + } + + swapBrowser(aBrowser) { + this._browser = aBrowser; + } + + maybeCancelContentJSExecution(aNavigationType, aOptions = {}) { + const epoch = this._cancelContentJSEpoch++; + this._browser.frameLoader.remoteTab.maybeCancelContentJSExecution( + aNavigationType, + { ...aOptions, epoch } + ); + return epoch; + } + + get canGoBack() { + if (Services.appinfo.sessionHistoryInParent) { + return this._browser.browsingContext.sessionHistory?.index > 0; + } + return this._canGoBack; + } + + get canGoForward() { + if (Services.appinfo.sessionHistoryInParent) { + let sessionHistory = this._browser.browsingContext.sessionHistory; + return sessionHistory?.index < sessionHistory?.count - 1; + } + return this._canGoForward; + } + + goBack(requireUserInteraction = false) { + let cancelContentJSEpoch = this.maybeCancelContentJSExecution( + Ci.nsIRemoteTab.NAVIGATE_BACK + ); + this._browser.browsingContext.goBack( + cancelContentJSEpoch, + requireUserInteraction, + true + ); + } + goForward(requireUserInteraction = false) { + let cancelContentJSEpoch = this.maybeCancelContentJSExecution( + Ci.nsIRemoteTab.NAVIGATE_FORWARD + ); + this._browser.browsingContext.goForward( + cancelContentJSEpoch, + requireUserInteraction, + true + ); + } + gotoIndex(aIndex) { + let cancelContentJSEpoch = this.maybeCancelContentJSExecution( + Ci.nsIRemoteTab.NAVIGATE_INDEX, + { index: aIndex } + ); + this._browser.browsingContext.goToIndex(aIndex, cancelContentJSEpoch, true); + } + + _speculativeConnect(uri, loadURIOptions) { + try { + // Let's start a network connection before the content process asks. + // Note that we might have already set up the speculative connection in + // some cases, especially when the url is from location bar or its popup + // menu. + if (uri.schemeIs("http") || uri.schemeIs("https")) { + let isBrowserPrivate = lazy.PrivateBrowsingUtils.isBrowserPrivate( + this._browser + ); + let principal = loadURIOptions.triggeringPrincipal; + // We usually have a triggeringPrincipal assigned, but in case we + // don't have one or if it's a SystemPrincipal, let's create it with OA + // inferred from the current context. + if (!principal || principal.isSystemPrincipal) { + let attrs = { + userContextId: this._browser.getAttribute("usercontextid") || 0, + privateBrowsingId: isBrowserPrivate ? 1 : 0, + }; + principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + attrs + ); + } + Services.io.speculativeConnect(uri, principal, null, false); + } + } catch (ex) { + // Can't setup speculative connection for this uri for some + // reason, just ignore it. + } + } + + loadURI(uri, loadURIOptions) { + this._speculativeConnect(uri, loadURIOptions); + let cancelContentJSEpoch = this.maybeCancelContentJSExecution( + Ci.nsIRemoteTab.NAVIGATE_URL, + { uri } + ); + this._browser.browsingContext.loadURI(uri, { + ...loadURIOptions, + cancelContentJSEpoch, + }); + } + + fixupAndLoadURIString(uriString, loadURIOptions) { + let uri; + try { + let fixupFlags = Services.uriFixup.webNavigationFlagsToFixupFlags( + uriString, + loadURIOptions.loadFlags + ); + let isBrowserPrivate = lazy.PrivateBrowsingUtils.isBrowserPrivate( + this._browser + ); + if (isBrowserPrivate) { + fixupFlags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT; + } + + uri = Services.uriFixup.getFixupURIInfo( + uriString, + fixupFlags + ).preferredURI; + } catch (ex) { + // In rare cases `uriFixup` can throw. We ignore this here, but it's + // likely that the fixupAndLoadURIString call below will still throw, + // hopefully with more details. + } + if (uri) { + this._speculativeConnect(uri, loadURIOptions); + } + + let cancelContentJSEpoch = this.maybeCancelContentJSExecution( + Ci.nsIRemoteTab.NAVIGATE_URL, + { uri } + ); + // For now, continue to use fixup here, but note that ideally we should be + // doing fixup only once and reusing the URI we created above. Addressing + // this is bug 1815509. + this._browser.browsingContext.fixupAndLoadURIString(uriString, { + ...loadURIOptions, + cancelContentJSEpoch, + }); + } + + reload(aReloadFlags) { + this._browser.browsingContext.reload(aReloadFlags); + } + stop(aStopFlags) { + this._browser.browsingContext.stop(aStopFlags); + } + + get document() { + return this._browser.contentDocument; + } + + get currentURI() { + if (!this._currentURI) { + this._currentURI = Services.io.newURI("about:blank"); + } + return this._currentURI; + } + set currentURI(aURI) { + // Bug 1498600 verify usages of systemPrincipal here + let loadURIOptions = { + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }; + this.loadURI(aURI.spec, loadURIOptions); + } + + // Bug 1233803 - accessing the sessionHistory of remote browsers should be + // done in content scripts. + get sessionHistory() { + throw new Components.Exception( + "Not implemented", + Cr.NS_ERROR_NOT_IMPLEMENTED + ); + } + set sessionHistory(aValue) { + throw new Components.Exception( + "Not implemented", + Cr.NS_ERROR_NOT_IMPLEMENTED + ); + } + + _sendMessage(aMessage, aData) { + try { + this._browser.sendMessageToActor(aMessage, aData, "WebNavigation"); + } catch (e) { + console.error(e); + } + } +} |