summaryrefslogtreecommitdiffstats
path: root/toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs209
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);
+ }
+ }
+}