diff --git a/docshell/base/nsDefaultURIFixup.cpp b/docshell/base/nsDefaultURIFixup.cpp index 999d7a578cb9..ef7ff4333fee 100644 --- a/docshell/base/nsDefaultURIFixup.cpp +++ b/docshell/base/nsDefaultURIFixup.cpp @@ -14,6 +14,7 @@ #include "nsISearchService.h" #include "nsIURIFixup.h" #include "nsIURIMutator.h" +#include "nsIWebNavigation.h" #include "nsDefaultURIFixup.h" #include "mozilla/Preferences.h" #include "mozilla/dom/ContentChild.h" @@ -381,6 +382,27 @@ nsDefaultURIFixup::GetFixupURIInfo(const nsACString& aStringURI, return rv; } +NS_IMETHODIMP +nsDefaultURIFixup::WebNavigationFlagsToFixupFlags(const nsACString& aStringURI, + uint32_t aDocShellFlags, + uint32_t* aFixupFlags) { + nsCOMPtr uri; + NS_NewURI(getter_AddRefs(uri), aStringURI); + if (uri) { + aDocShellFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; + } + + *aFixupFlags = 0; + if (aDocShellFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { + *aFixupFlags |= FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; + } + if (aDocShellFlags & nsIWebNavigation::LOAD_FLAGS_FIXUP_SCHEME_TYPOS) { + *aFixupFlags |= FIXUP_FLAG_FIX_SCHEME_TYPOS; + } + + return NS_OK; +} + NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword, nsIInputStream** aPostData, diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 0451a446da49..fb4a9dbd5b7b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -3916,10 +3916,6 @@ nsresult nsDocShell::LoadURI(const nsAString& aURI, nsCOMPtr postData(aLoadURIOptions.mPostData); nsresult rv = NS_OK; - // Create a URI from our string; if that succeeds, we want to - // change loadFlags to not include the ALLOW_THIRD_PARTY_FIXUP - // flag. - NS_ConvertUTF16toUTF8 uriString(aURI); // Cleanup the empty spaces that might be on each end. uriString.Trim(" "); @@ -3931,24 +3927,19 @@ nsresult nsDocShell::LoadURI(const nsAString& aURI, return NS_ERROR_FAILURE; } - rv = NS_NewURI(getter_AddRefs(uri), uriString); - if (uri) { - loadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; - } - nsCOMPtr fixupInfo; if (sURIFixup) { - // Call the fixup object. This will clobber the rv from NS_NewURI - // above, but that's fine with us. Note that we need to do this even - // if NS_NewURI returned a URI, because fixup handles nested URIs, etc - // (things like view-source:mozilla.org for example). - uint32_t fixupFlags = 0; - if (loadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { - fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; - } - if (loadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) { - fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS; + uint32_t fixupFlags; + rv = sURIFixup->WebNavigationFlagsToFixupFlags(uriString, loadFlags, + &fixupFlags); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + // If we don't allow keyword lookups for this URL string, make sure to + // update loadFlags to indicate this as well. + if (!(fixupFlags & nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) { + loadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; } + nsCOMPtr fixupStream; rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags, getter_AddRefs(fixupStream), @@ -3973,9 +3964,11 @@ nsresult nsDocShell::LoadURI(const nsAString& aURI, PromiseFlatString(aURI).get()); } } + } else { + // No fixup service so just create a URI and see what happens... + rv = NS_NewURI(getter_AddRefs(uri), uriString); + loadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; } - // else no fixup service so just use the URI we created and see - // what happens if (NS_ERROR_MALFORMED_URI == rv) { if (DisplayLoadError(rv, uri, PromiseFlatString(aURI).get(), nullptr) && diff --git a/docshell/base/nsIURIFixup.idl b/docshell/base/nsIURIFixup.idl index 34298bd67f00..028536d169ca 100644 --- a/docshell/base/nsIURIFixup.idl +++ b/docshell/base/nsIURIFixup.idl @@ -135,6 +135,17 @@ interface nsIURIFixup : nsISupports in unsigned long aFixupFlags, [optional] out nsIInputStream aPostData); + /** + * Convert load flags from nsIWebNavigation to URI fixup flags for use in + * createFixupURI or getFixupURIInfo. + * + * @param aURIText Candidate URI; used for determining whether to + * allow keyword lookups. + * @param aDocShellFlags Load flags from nsIDocShell to convert. + */ + unsigned long webNavigationFlagsToFixupFlags( + in AUTF8String aURIText, in unsigned long aDocShellFlags); + /** * Converts the specified keyword string into a URI. Note that it's the * caller's responsibility to check whether keywords are enabled and diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index 469336ae6dd9..a1ffdc931f87 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -3401,6 +3401,14 @@ nsresult BrowserChild::CanCancelContentJS( rv = history->GetEntryAtIndex(current, getter_AddRefs(entry)); NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr currentURI = entry->GetURI(); + if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") && + !currentURI->SchemeIs("file")) { + // Only cancel content JS for http(s) and file URIs. Other URIs are probably + // internal and we should just let them run to completion. + return NS_OK; + } + if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) { aNavigationIndex = current - 1; } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) { @@ -3410,9 +3418,13 @@ nsresult BrowserChild::CanCancelContentJS( return NS_ERROR_FAILURE; } - nsCOMPtr currentURI = entry->GetURI(); - CanCancelContentJSBetweenURIs(currentURI, aNavigationURI, aCanCancel); + // If navigating directly to a URL (e.g. via hitting Enter in the location + // bar), then we can cancel anytime the next URL is different from the + // current, *excluding* the ref ("#"). + bool equals; + rv = currentURI->EqualsExceptRef(aNavigationURI, &equals); NS_ENSURE_SUCCESS(rv, rv); + *aCanCancel = !equals; return NS_OK; } // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't @@ -3427,15 +3439,22 @@ nsresult BrowserChild::CanCancelContentJS( NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr laterEntry = delta == 1 ? nextEntry : entry; - nsCOMPtr uri = entry->GetURI(); + nsCOMPtr thisURI = entry->GetURI(); nsCOMPtr nextURI = nextEntry->GetURI(); // If we changed origin and the load wasn't in a subframe, we know it was // a full document load, so we can cancel the content JS safely. if (!laterEntry->GetIsSubFrame()) { - CanCancelContentJSBetweenURIs(uri, nextURI, aCanCancel); + nsAutoCString thisHost; + rv = thisURI->GetPrePath(thisHost); NS_ENSURE_SUCCESS(rv, rv); - if (*aCanCancel) { + + nsAutoCString nextHost; + rv = nextURI->GetPrePath(nextHost); + NS_ENSURE_SUCCESS(rv, rv); + + if (!thisHost.Equals(nextHost)) { + *aCanCancel = true; return NS_OK; } } @@ -3446,27 +3465,6 @@ nsresult BrowserChild::CanCancelContentJS( return NS_OK; } -nsresult BrowserChild::CanCancelContentJSBetweenURIs(nsIURI* aFirstURI, - nsIURI* aSecondURI, - bool* aCanCancel) { - nsresult rv; - *aCanCancel = false; - - nsAutoCString firstHost; - rv = aFirstURI->GetHostPort(firstHost); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoCString secondHost; - rv = aSecondURI->GetHostPort(secondHost); - NS_ENSURE_SUCCESS(rv, rv); - - if (!firstHost.Equals(secondHost)) { - *aCanCancel = true; - } - - return NS_OK; -} - void BrowserChild::BeforeUnloadAdded() { // Don't bother notifying the parent if we don't have an IPC link open. if (mBeforeUnloadListeners == 0 && IPCOpen()) { diff --git a/dom/ipc/BrowserChild.h b/dom/ipc/BrowserChild.h index 18caef46282c..ff18bc831c20 100644 --- a/dom/ipc/BrowserChild.h +++ b/dom/ipc/BrowserChild.h @@ -827,9 +827,6 @@ class BrowserChild final : public BrowserChildBase, Maybe& aWebProgressData, RequestData& aRequestData); - nsresult CanCancelContentJSBetweenURIs(nsIURI* aFirstURI, nsIURI* aSecondURI, - bool* aCanCancel); - class DelayedDeleteRunnable; TextureFactoryIdentifier mTextureFactoryIdentifier; diff --git a/dom/ipc/BrowserHost.cpp b/dom/ipc/BrowserHost.cpp index 45ef2530dab1..072b96221b99 100644 --- a/dom/ipc/BrowserHost.cpp +++ b/dom/ipc/BrowserHost.cpp @@ -357,7 +357,10 @@ NS_IMETHODIMP BrowserHost::MaybeCancelContentJSExecutionFromScript( nsIRemoteTab::NavigationType aNavigationType, JS::Handle aCancelContentJSOptions, JSContext* aCx) { - if (!mRoot) { + // If we're in the process of creating a new window (via window.open), then + // the load that called this function isn't a "normal" load and should be + // ignored for the purposes of cancelling content JS. + if (!mRoot || mRoot->CreatingWindow()) { return NS_OK; } dom::CancelContentJSOptions cancelContentJSOptions; diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h index a5ec81767874..63eab0776fd4 100644 --- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -189,6 +189,13 @@ class BrowserParent final : public PBrowserParent, */ bool IsDestroyed() const { return mIsDestroyed; } + /** + * Returns whether we're in the process of creating a new window (from + * window.open). If so, LoadURL calls are being skipped until everything is + * set up. For further details, see `mCreatingWindow` below. + */ + bool CreatingWindow() const { return mCreatingWindow; } + /* * Visit each BrowserParent in the tree formed by PBrowser and * PBrowserBridge, including `this`. diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index 97d823200359..76efbc356a03 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -381,10 +381,16 @@ bool HangMonitorChild::InterruptCallback() { } } - // Only handle the interrupt for cancelling content JS if we have an actual - // window associated with this context... + // Only handle the interrupt for cancelling content JS if we have a + // non-privileged script (i.e. not part of Gecko or an add-on). JS::RootedObject global(mContext, JS::CurrentGlobalOrNull(mContext)); - RefPtr win = xpc::WindowOrNull(global); + nsIPrincipal* principal = xpc::GetObjectPrincipal(global); + if (principal && (principal->IsSystemPrincipal() || + principal->GetIsAddonOrExpandedAddonPrincipal())) { + return true; + } + + nsCOMPtr win = xpc::WindowOrNull(global); if (!win) { return true; } @@ -409,10 +415,17 @@ bool HangMonitorChild::InterruptCallback() { } if (cancelContentJS) { + js::AutoAssertNoContentJS nojs(mContext); + TabId currentJSTabId = BrowserChild::GetFrom(win)->GetTabId(); + if (currentJSTabId != cancelContentJSTab) { + // The currently-executing content JS doesn't belong to the tab that + // requested cancellation of JS. Just return and let the JS continue. + return true; + } + RefPtr browserChild = BrowserChild::FindBrowserChild(cancelContentJSTab); if (browserChild) { - js::AutoAssertNoContentJS nojs(mContext); nsresult rv; nsCOMPtr uri; diff --git a/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm index 598be1b4a246..5e6956508935 100644 --- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm +++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm @@ -12,10 +12,6 @@ ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils", ChromeUtils.defineModuleGetter(this, "E10SUtils", "resource://gre/modules/E10SUtils.jsm"); -function makeURI(url) { - return Services.io.newURI(url); -} - function RemoteWebNavigation() { this.wrappedJSObject = this; this._cancelContentJSEpoch = 1; @@ -77,14 +73,18 @@ RemoteWebNavigation.prototype = { }, loadURI(aURI, aLoadURIOptions) { let uri; + try { + let fixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(); + let fixupFlags = fixup.webNavigationFlagsToFixupFlags( + aURI, aLoadURIOptions.loadFlags); + uri = fixup.createFixupURI(aURI, fixupFlags); - // We know the url is going to be loaded, let's start requesting network - // connection before the content process asks. - // Note that we might have already setup the speculative connection in some - // cases, especially when the url is from location bar or its popup menu. - if (aURI.startsWith("http:") || aURI.startsWith("https:")) { - try { - uri = makeURI(aURI); + // We know the url is going to be loaded, let's start requesting network + // connection before the content process asks. + // Note that we might have already setup 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 principal = aLoadURIOptions.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 @@ -97,10 +97,10 @@ RemoteWebNavigation.prototype = { principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs); } Services.io.speculativeConnect(uri, principal, null); - } catch (ex) { - // Can't setup speculative connection for this uri string for some - // reason (such as failing to parse the URI), just ignore it. } + } catch (ex) { + // Can't setup speculative connection for this uri string for some + // reason (such as failing to parse the URI), just ignore it. } let cancelContentJSEpoch = this._cancelContentJSEpoch++; @@ -138,7 +138,7 @@ RemoteWebNavigation.prototype = { _currentURI: null, get currentURI() { if (!this._currentURI) { - this._currentURI = makeURI("about:blank"); + this._currentURI = Services.io.newURI("about:blank"); } return this._currentURI;