summaryrefslogtreecommitdiffstats
path: root/docshell/base/nsDocShellLoadState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'docshell/base/nsDocShellLoadState.cpp')
-rw-r--r--docshell/base/nsDocShellLoadState.cpp1325
1 files changed, 1325 insertions, 0 deletions
diff --git a/docshell/base/nsDocShellLoadState.cpp b/docshell/base/nsDocShellLoadState.cpp
new file mode 100644
index 0000000000..587617e73d
--- /dev/null
+++ b/docshell/base/nsDocShellLoadState.cpp
@@ -0,0 +1,1325 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsDocShellLoadState.h"
+#include "nsIDocShell.h"
+#include "nsDocShell.h"
+#include "nsIProtocolHandler.h"
+#include "nsISHEntry.h"
+#include "nsIURIFixup.h"
+#include "nsIWebNavigation.h"
+#include "nsIChannel.h"
+#include "nsIURLQueryStringStripper.h"
+#include "nsIXULRuntime.h"
+#include "nsNetUtil.h"
+#include "nsQueryObject.h"
+#include "ReferrerInfo.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Components.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/LoadURIOptionsBinding.h"
+#include "mozilla/StaticPrefs_browser.h"
+#include "mozilla/StaticPrefs_fission.h"
+#include "mozilla/Telemetry.h"
+
+#include "mozilla/OriginAttributes.h"
+#include "mozilla/NullPrincipal.h"
+#include "mozilla/StaticPtr.h"
+
+#include "mozilla/dom/PContent.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+// Global reference to the URI fixup service.
+static mozilla::StaticRefPtr<nsIURIFixup> sURIFixup;
+
+nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI)
+ : nsDocShellLoadState(aURI, nsContentUtils::GenerateLoadIdentifier()) {}
+
+nsDocShellLoadState::nsDocShellLoadState(
+ const DocShellLoadStateInit& aLoadState, mozilla::ipc::IProtocol* aActor,
+ bool* aReadSuccess)
+ : mNotifiedBeforeUnloadListeners(false),
+ mLoadIdentifier(aLoadState.LoadIdentifier()) {
+ // If we return early, we failed to read in the data.
+ *aReadSuccess = false;
+ if (!aLoadState.URI()) {
+ MOZ_ASSERT_UNREACHABLE("Cannot create a LoadState with a null URI!");
+ return;
+ }
+
+ mResultPrincipalURI = aLoadState.ResultPrincipalURI();
+ mResultPrincipalURIIsSome = aLoadState.ResultPrincipalURIIsSome();
+ mKeepResultPrincipalURIIfSet = aLoadState.KeepResultPrincipalURIIfSet();
+ mLoadReplace = aLoadState.LoadReplace();
+ mInheritPrincipal = aLoadState.InheritPrincipal();
+ mPrincipalIsExplicit = aLoadState.PrincipalIsExplicit();
+ mForceAllowDataURI = aLoadState.ForceAllowDataURI();
+ mIsExemptFromHTTPSFirstMode = aLoadState.IsExemptFromHTTPSFirstMode();
+ mOriginalFrameSrc = aLoadState.OriginalFrameSrc();
+ mIsFormSubmission = aLoadState.IsFormSubmission();
+ mLoadType = aLoadState.LoadType();
+ mTarget = aLoadState.Target();
+ mTargetBrowsingContext = aLoadState.TargetBrowsingContext();
+ mLoadFlags = aLoadState.LoadFlags();
+ mInternalLoadFlags = aLoadState.InternalLoadFlags();
+ mFirstParty = aLoadState.FirstParty();
+ mHasValidUserGestureActivation = aLoadState.HasValidUserGestureActivation();
+ mAllowFocusMove = aLoadState.AllowFocusMove();
+ mTypeHint = aLoadState.TypeHint();
+ mFileName = aLoadState.FileName();
+ mIsFromProcessingFrameAttributes =
+ aLoadState.IsFromProcessingFrameAttributes();
+ mReferrerInfo = aLoadState.ReferrerInfo();
+ mURI = aLoadState.URI();
+ mOriginalURI = aLoadState.OriginalURI();
+ mSourceBrowsingContext = aLoadState.SourceBrowsingContext();
+ mBaseURI = aLoadState.BaseURI();
+ mTriggeringPrincipal = aLoadState.TriggeringPrincipal();
+ mPrincipalToInherit = aLoadState.PrincipalToInherit();
+ mPartitionedPrincipalToInherit = aLoadState.PartitionedPrincipalToInherit();
+ mTriggeringSandboxFlags = aLoadState.TriggeringSandboxFlags();
+ mTriggeringWindowId = aLoadState.TriggeringWindowId();
+ mTriggeringStorageAccess = aLoadState.TriggeringStorageAccess();
+ mTriggeringRemoteType = aLoadState.TriggeringRemoteType();
+ mWasSchemelessInput = aLoadState.WasSchemelessInput();
+ mCsp = aLoadState.Csp();
+ mOriginalURIString = aLoadState.OriginalURIString();
+ mCancelContentJSEpoch = aLoadState.CancelContentJSEpoch();
+ mPostDataStream = aLoadState.PostDataStream();
+ mHeadersStream = aLoadState.HeadersStream();
+ mSrcdocData = aLoadState.SrcdocData();
+ mChannelInitialized = aLoadState.ChannelInitialized();
+ mIsMetaRefresh = aLoadState.IsMetaRefresh();
+ if (aLoadState.loadingSessionHistoryInfo().isSome()) {
+ mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(
+ aLoadState.loadingSessionHistoryInfo().ref());
+ }
+ mUnstrippedURI = aLoadState.UnstrippedURI();
+ mRemoteTypeOverride = aLoadState.RemoteTypeOverride();
+
+ // We know this was created remotely, as we just received it over IPC.
+ mWasCreatedRemotely = true;
+
+ // If we're in the parent process, potentially validate against a LoadState
+ // which we sent to the source content process.
+ if (XRE_IsParentProcess()) {
+ mozilla::ipc::IToplevelProtocol* top = aActor->ToplevelProtocol();
+ if (!top ||
+ top->GetProtocolId() != mozilla::ipc::ProtocolId::PContentMsgStart ||
+ top->GetSide() != mozilla::ipc::ParentSide) {
+ aActor->FatalError("nsDocShellLoadState must be received over PContent");
+ return;
+ }
+ ContentParent* cp = static_cast<ContentParent*>(top);
+
+ // If this load was sent down to the content process as a navigation
+ // request, ensure it still matches the one we sent down.
+ if (RefPtr<nsDocShellLoadState> originalState =
+ cp->TakePendingLoadStateForId(mLoadIdentifier)) {
+ if (const char* mismatch = ValidateWithOriginalState(originalState)) {
+ aActor->FatalError(
+ nsPrintfCString(
+ "nsDocShellLoadState %s changed while in content process",
+ mismatch)
+ .get());
+ return;
+ }
+ } else if (mTriggeringRemoteType != cp->GetRemoteType()) {
+ // If we don't have a previous load to compare to, the content process
+ // must be the triggering process.
+ aActor->FatalError(
+ "nsDocShellLoadState with invalid triggering remote type");
+ return;
+ }
+ }
+
+ // We successfully read in the data - return a success value.
+ *aReadSuccess = true;
+}
+
+nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
+ : mReferrerInfo(aOther.mReferrerInfo),
+ mURI(aOther.mURI),
+ mOriginalURI(aOther.mOriginalURI),
+ mResultPrincipalURI(aOther.mResultPrincipalURI),
+ mResultPrincipalURIIsSome(aOther.mResultPrincipalURIIsSome),
+ mTriggeringPrincipal(aOther.mTriggeringPrincipal),
+ mTriggeringSandboxFlags(aOther.mTriggeringSandboxFlags),
+ mTriggeringWindowId(aOther.mTriggeringWindowId),
+ mTriggeringStorageAccess(aOther.mTriggeringStorageAccess),
+ mCsp(aOther.mCsp),
+ mKeepResultPrincipalURIIfSet(aOther.mKeepResultPrincipalURIIfSet),
+ mLoadReplace(aOther.mLoadReplace),
+ mInheritPrincipal(aOther.mInheritPrincipal),
+ mPrincipalIsExplicit(aOther.mPrincipalIsExplicit),
+ mNotifiedBeforeUnloadListeners(aOther.mNotifiedBeforeUnloadListeners),
+ mPrincipalToInherit(aOther.mPrincipalToInherit),
+ mPartitionedPrincipalToInherit(aOther.mPartitionedPrincipalToInherit),
+ mForceAllowDataURI(aOther.mForceAllowDataURI),
+ mIsExemptFromHTTPSFirstMode(aOther.mIsExemptFromHTTPSFirstMode),
+ mOriginalFrameSrc(aOther.mOriginalFrameSrc),
+ mIsFormSubmission(aOther.mIsFormSubmission),
+ mLoadType(aOther.mLoadType),
+ mSHEntry(aOther.mSHEntry),
+ mTarget(aOther.mTarget),
+ mTargetBrowsingContext(aOther.mTargetBrowsingContext),
+ mPostDataStream(aOther.mPostDataStream),
+ mHeadersStream(aOther.mHeadersStream),
+ mSrcdocData(aOther.mSrcdocData),
+ mSourceBrowsingContext(aOther.mSourceBrowsingContext),
+ mBaseURI(aOther.mBaseURI),
+ mLoadFlags(aOther.mLoadFlags),
+ mInternalLoadFlags(aOther.mInternalLoadFlags),
+ mFirstParty(aOther.mFirstParty),
+ mHasValidUserGestureActivation(aOther.mHasValidUserGestureActivation),
+ mAllowFocusMove(aOther.mAllowFocusMove),
+ mTypeHint(aOther.mTypeHint),
+ mFileName(aOther.mFileName),
+ mIsFromProcessingFrameAttributes(aOther.mIsFromProcessingFrameAttributes),
+ mPendingRedirectedChannel(aOther.mPendingRedirectedChannel),
+ mOriginalURIString(aOther.mOriginalURIString),
+ mCancelContentJSEpoch(aOther.mCancelContentJSEpoch),
+ mLoadIdentifier(aOther.mLoadIdentifier),
+ mChannelInitialized(aOther.mChannelInitialized),
+ mIsMetaRefresh(aOther.mIsMetaRefresh),
+ mWasCreatedRemotely(aOther.mWasCreatedRemotely),
+ mUnstrippedURI(aOther.mUnstrippedURI),
+ mRemoteTypeOverride(aOther.mRemoteTypeOverride),
+ mTriggeringRemoteType(aOther.mTriggeringRemoteType),
+ mWasSchemelessInput(aOther.mWasSchemelessInput) {
+ MOZ_DIAGNOSTIC_ASSERT(
+ XRE_IsParentProcess(),
+ "Cloning a nsDocShellLoadState with the same load identifier is only "
+ "allowed in the parent process, as it could break triggering remote type "
+ "tracking in content.");
+ if (aOther.mLoadingSessionHistoryInfo) {
+ mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(
+ *aOther.mLoadingSessionHistoryInfo);
+ }
+}
+
+nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier)
+ : mURI(aURI),
+ mResultPrincipalURIIsSome(false),
+ mTriggeringSandboxFlags(0),
+ mTriggeringWindowId(0),
+ mTriggeringStorageAccess(false),
+ mKeepResultPrincipalURIIfSet(false),
+ mLoadReplace(false),
+ mInheritPrincipal(false),
+ mPrincipalIsExplicit(false),
+ mNotifiedBeforeUnloadListeners(false),
+ mForceAllowDataURI(false),
+ mIsExemptFromHTTPSFirstMode(false),
+ mOriginalFrameSrc(false),
+ mIsFormSubmission(false),
+ mLoadType(LOAD_NORMAL),
+ mSrcdocData(VoidString()),
+ mLoadFlags(0),
+ mInternalLoadFlags(0),
+ mFirstParty(false),
+ mHasValidUserGestureActivation(false),
+ mAllowFocusMove(false),
+ mTypeHint(VoidCString()),
+ mFileName(VoidString()),
+ mIsFromProcessingFrameAttributes(false),
+ mLoadIdentifier(aLoadIdentifier),
+ mChannelInitialized(false),
+ mIsMetaRefresh(false),
+ mWasCreatedRemotely(false),
+ mTriggeringRemoteType(XRE_IsContentProcess()
+ ? ContentChild::GetSingleton()->GetRemoteType()
+ : NOT_REMOTE_TYPE),
+ mWasSchemelessInput(false) {
+ MOZ_ASSERT(aURI, "Cannot create a LoadState with a null URI!");
+}
+
+nsDocShellLoadState::~nsDocShellLoadState() {
+ if (mWasCreatedRemotely && XRE_IsContentProcess()) {
+ ContentChild::GetSingleton()->SendCleanupPendingLoadState(mLoadIdentifier);
+ }
+}
+
+nsresult nsDocShellLoadState::CreateFromPendingChannel(
+ nsIChannel* aPendingChannel, uint64_t aLoadIdentifier,
+ uint64_t aRegistrarId, nsDocShellLoadState** aResult) {
+ // Create the nsDocShellLoadState object with default state pulled from the
+ // passed-in channel.
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = aPendingChannel->GetURI(getter_AddRefs(uri));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ RefPtr<nsDocShellLoadState> loadState =
+ new nsDocShellLoadState(uri, aLoadIdentifier);
+ loadState->mPendingRedirectedChannel = aPendingChannel;
+ loadState->mChannelRegistrarId = aRegistrarId;
+
+ // Pull relevant state from the channel, and store it on the
+ // nsDocShellLoadState.
+ nsCOMPtr<nsIURI> originalUri;
+ rv = aPendingChannel->GetOriginalURI(getter_AddRefs(originalUri));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ loadState->SetOriginalURI(originalUri);
+
+ nsCOMPtr<nsILoadInfo> loadInfo = aPendingChannel->LoadInfo();
+ loadState->SetTriggeringPrincipal(loadInfo->TriggeringPrincipal());
+
+ // Return the newly created loadState.
+ loadState.forget(aResult);
+ return NS_OK;
+}
+
+static uint32_t WebNavigationFlagsToFixupFlags(nsIURI* aURI,
+ const nsACString& aURIString,
+ uint32_t aNavigationFlags) {
+ if (aURI) {
+ aNavigationFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+ }
+ uint32_t fixupFlags = nsIURIFixup::FIXUP_FLAG_NONE;
+ if (aNavigationFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
+ fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+ }
+ if (aNavigationFlags & nsIWebNavigation::LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
+ fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
+ }
+ return fixupFlags;
+};
+
+nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
+ BrowsingContext* aBrowsingContext, const nsAString& aURI,
+ const LoadURIOptions& aLoadURIOptions, nsDocShellLoadState** aResult) {
+ uint32_t loadFlags = aLoadURIOptions.mLoadFlags;
+
+ NS_ASSERTION(
+ (loadFlags & nsDocShell::INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0,
+ "Unexpected flags");
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_OK;
+
+ NS_ConvertUTF16toUTF8 uriString(aURI);
+ // Cleanup the empty spaces that might be on each end.
+ uriString.Trim(" ");
+ // Eliminate embedded newlines, which single-line text fields now allow:
+ uriString.StripCRLF();
+ NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
+
+ // Just create a URI and see what happens...
+ rv = NS_NewURI(getter_AddRefs(uri), uriString);
+ bool fixup = true;
+ if (NS_SUCCEEDED(rv) && uri &&
+ (uri->SchemeIs("about") || uri->SchemeIs("chrome"))) {
+ // Avoid third party fixup as a performance optimization.
+ loadFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+ fixup = false;
+ } else if (!sURIFixup && !XRE_IsContentProcess()) {
+ nsCOMPtr<nsIURIFixup> uriFixup = components::URIFixup::Service();
+ if (uriFixup) {
+ sURIFixup = uriFixup;
+ ClearOnShutdown(&sURIFixup);
+ } else {
+ fixup = false;
+ }
+ }
+
+ nsAutoString searchProvider, keyword;
+ RefPtr<nsIInputStream> fixupStream;
+ if (fixup) {
+ uint32_t fixupFlags =
+ WebNavigationFlagsToFixupFlags(uri, uriString, loadFlags);
+
+ // 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 &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+ }
+ // Ensure URIFixup will use the right search engine in Private Browsing.
+ if (aBrowsingContext->UsePrivateBrowsing()) {
+ fixupFlags |= nsIURIFixup::FIXUP_FLAG_PRIVATE_CONTEXT;
+ }
+
+ if (!XRE_IsContentProcess()) {
+ nsCOMPtr<nsIURIFixupInfo> fixupInfo;
+ sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
+ getter_AddRefs(fixupInfo));
+ if (fixupInfo) {
+ // We could fix the uri, clear NS_ERROR_MALFORMED_URI.
+ rv = NS_OK;
+ fixupInfo->GetPreferredURI(getter_AddRefs(uri));
+ fixupInfo->SetConsumer(aBrowsingContext);
+ fixupInfo->GetKeywordProviderName(searchProvider);
+ fixupInfo->GetKeywordAsSent(keyword);
+ // GetFixupURIInfo only returns a post data stream if it succeeded
+ // and changed the URI, in which case we should override the
+ // passed-in post data by passing this as an override arg to
+ // our internal method.
+ fixupInfo->GetPostData(getter_AddRefs(fixupStream));
+
+ if (fixupInfo &&
+ loadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
+ nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
+ if (serv) {
+ serv->NotifyObservers(fixupInfo, "keyword-uri-fixup",
+ PromiseFlatString(aURI).get());
+ }
+ }
+ nsDocShell::MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
+ }
+ }
+ }
+
+ if (rv == NS_ERROR_MALFORMED_URI) {
+ MOZ_ASSERT(!uri);
+ return rv;
+ }
+
+ if (NS_FAILED(rv) || !uri) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<nsDocShellLoadState> loadState;
+ rv = CreateFromLoadURIOptions(
+ aBrowsingContext, uri, aLoadURIOptions, loadFlags,
+ fixupStream ? fixupStream : aLoadURIOptions.mPostData,
+ getter_AddRefs(loadState));
+ NS_ENSURE_SUCCESS(rv, rv);
+ loadState->SetOriginalURIString(uriString);
+ loadState.forget(aResult);
+ return NS_OK;
+}
+
+nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
+ BrowsingContext* aBrowsingContext, nsIURI* aURI,
+ const LoadURIOptions& aLoadURIOptions, nsDocShellLoadState** aResult) {
+ return CreateFromLoadURIOptions(aBrowsingContext, aURI, aLoadURIOptions,
+ aLoadURIOptions.mLoadFlags,
+ aLoadURIOptions.mPostData, aResult);
+}
+
+nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
+ BrowsingContext* aBrowsingContext, nsIURI* aURI,
+ const LoadURIOptions& aLoadURIOptions, uint32_t aLoadFlagsOverride,
+ nsIInputStream* aPostDataOverride, nsDocShellLoadState** aResult) {
+ nsresult rv = NS_OK;
+ uint32_t loadFlags = aLoadFlagsOverride;
+ RefPtr<nsIInputStream> postData = aPostDataOverride;
+ uint64_t available;
+ if (postData) {
+ rv = postData->Available(&available);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (available == 0) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+
+ if (aLoadURIOptions.mHeaders) {
+ rv = aLoadURIOptions.mHeaders->Available(&available);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (available == 0) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+
+ bool forceAllowDataURI =
+ loadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+
+ // Don't pass certain flags that aren't needed and end up confusing
+ // ConvertLoadTypeToDocShellInfoLoadType. We do need to ensure that they are
+ // passed to LoadURI though, since it uses them.
+ uint32_t extraFlags = (loadFlags & EXTRA_LOAD_FLAGS);
+ loadFlags &= ~EXTRA_LOAD_FLAGS;
+
+ RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aURI);
+ loadState->SetReferrerInfo(aLoadURIOptions.mReferrerInfo);
+
+ loadState->SetLoadType(MAKE_LOAD_TYPE(LOAD_NORMAL, loadFlags));
+
+ loadState->SetLoadFlags(extraFlags);
+ loadState->SetFirstParty(true);
+ loadState->SetHasValidUserGestureActivation(
+ aLoadURIOptions.mHasValidUserGestureActivation);
+ loadState->SetTriggeringSandboxFlags(aLoadURIOptions.mTriggeringSandboxFlags);
+ loadState->SetTriggeringWindowId(aLoadURIOptions.mTriggeringWindowId);
+ loadState->SetTriggeringStorageAccess(
+ aLoadURIOptions.mTriggeringStorageAccess);
+ loadState->SetPostDataStream(postData);
+ loadState->SetHeadersStream(aLoadURIOptions.mHeaders);
+ loadState->SetBaseURI(aLoadURIOptions.mBaseURI);
+ loadState->SetTriggeringPrincipal(aLoadURIOptions.mTriggeringPrincipal);
+ loadState->SetCsp(aLoadURIOptions.mCsp);
+ loadState->SetForceAllowDataURI(forceAllowDataURI);
+ if (aLoadURIOptions.mCancelContentJSEpoch) {
+ loadState->SetCancelContentJSEpoch(aLoadURIOptions.mCancelContentJSEpoch);
+ }
+
+ if (aLoadURIOptions.mTriggeringRemoteType.WasPassed()) {
+ if (XRE_IsParentProcess()) {
+ loadState->SetTriggeringRemoteType(
+ aLoadURIOptions.mTriggeringRemoteType.Value());
+ } else if (ContentChild::GetSingleton()->GetRemoteType() !=
+ aLoadURIOptions.mTriggeringRemoteType.Value()) {
+ NS_WARNING("Invalid TriggeringRemoteType from LoadURIOptions in content");
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+
+ if (aLoadURIOptions.mRemoteTypeOverride.WasPassed()) {
+ loadState->SetRemoteTypeOverride(
+ aLoadURIOptions.mRemoteTypeOverride.Value());
+ }
+
+ loadState->SetWasSchemelessInput(aLoadURIOptions.mWasSchemelessInput);
+
+ loadState.forget(aResult);
+ return NS_OK;
+}
+
+nsIReferrerInfo* nsDocShellLoadState::GetReferrerInfo() const {
+ return mReferrerInfo;
+}
+
+void nsDocShellLoadState::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
+ mReferrerInfo = aReferrerInfo;
+}
+
+nsIURI* nsDocShellLoadState::URI() const { return mURI; }
+
+void nsDocShellLoadState::SetURI(nsIURI* aURI) { mURI = aURI; }
+
+nsIURI* nsDocShellLoadState::OriginalURI() const { return mOriginalURI; }
+
+void nsDocShellLoadState::SetOriginalURI(nsIURI* aOriginalURI) {
+ mOriginalURI = aOriginalURI;
+}
+
+nsIURI* nsDocShellLoadState::ResultPrincipalURI() const {
+ return mResultPrincipalURI;
+}
+
+void nsDocShellLoadState::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
+ mResultPrincipalURI = aResultPrincipalURI;
+}
+
+bool nsDocShellLoadState::ResultPrincipalURIIsSome() const {
+ return mResultPrincipalURIIsSome;
+}
+
+void nsDocShellLoadState::SetResultPrincipalURIIsSome(bool aIsSome) {
+ mResultPrincipalURIIsSome = aIsSome;
+}
+
+bool nsDocShellLoadState::KeepResultPrincipalURIIfSet() const {
+ return mKeepResultPrincipalURIIfSet;
+}
+
+void nsDocShellLoadState::SetKeepResultPrincipalURIIfSet(bool aKeep) {
+ mKeepResultPrincipalURIIfSet = aKeep;
+}
+
+bool nsDocShellLoadState::LoadReplace() const { return mLoadReplace; }
+
+void nsDocShellLoadState::SetLoadReplace(bool aLoadReplace) {
+ mLoadReplace = aLoadReplace;
+}
+
+nsIPrincipal* nsDocShellLoadState::TriggeringPrincipal() const {
+ return mTriggeringPrincipal;
+}
+
+void nsDocShellLoadState::SetTriggeringPrincipal(
+ nsIPrincipal* aTriggeringPrincipal) {
+ mTriggeringPrincipal = aTriggeringPrincipal;
+}
+
+nsIPrincipal* nsDocShellLoadState::PrincipalToInherit() const {
+ return mPrincipalToInherit;
+}
+
+void nsDocShellLoadState::SetPrincipalToInherit(
+ nsIPrincipal* aPrincipalToInherit) {
+ mPrincipalToInherit = aPrincipalToInherit;
+}
+
+nsIPrincipal* nsDocShellLoadState::PartitionedPrincipalToInherit() const {
+ return mPartitionedPrincipalToInherit;
+}
+
+void nsDocShellLoadState::SetPartitionedPrincipalToInherit(
+ nsIPrincipal* aPartitionedPrincipalToInherit) {
+ mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
+}
+
+void nsDocShellLoadState::SetCsp(nsIContentSecurityPolicy* aCsp) {
+ mCsp = aCsp;
+}
+
+nsIContentSecurityPolicy* nsDocShellLoadState::Csp() const { return mCsp; }
+
+void nsDocShellLoadState::SetTriggeringSandboxFlags(uint32_t flags) {
+ mTriggeringSandboxFlags = flags;
+}
+
+uint32_t nsDocShellLoadState::TriggeringSandboxFlags() const {
+ return mTriggeringSandboxFlags;
+}
+
+void nsDocShellLoadState::SetTriggeringWindowId(uint64_t aTriggeringWindowId) {
+ mTriggeringWindowId = aTriggeringWindowId;
+}
+
+uint64_t nsDocShellLoadState::TriggeringWindowId() const {
+ return mTriggeringWindowId;
+}
+
+void nsDocShellLoadState::SetTriggeringStorageAccess(
+ bool aTriggeringStorageAccess) {
+ mTriggeringStorageAccess = aTriggeringStorageAccess;
+}
+
+bool nsDocShellLoadState::TriggeringStorageAccess() const {
+ return mTriggeringStorageAccess;
+}
+
+bool nsDocShellLoadState::InheritPrincipal() const { return mInheritPrincipal; }
+
+void nsDocShellLoadState::SetInheritPrincipal(bool aInheritPrincipal) {
+ mInheritPrincipal = aInheritPrincipal;
+}
+
+bool nsDocShellLoadState::PrincipalIsExplicit() const {
+ return mPrincipalIsExplicit;
+}
+
+void nsDocShellLoadState::SetPrincipalIsExplicit(bool aPrincipalIsExplicit) {
+ mPrincipalIsExplicit = aPrincipalIsExplicit;
+}
+
+bool nsDocShellLoadState::NotifiedBeforeUnloadListeners() const {
+ return mNotifiedBeforeUnloadListeners;
+}
+
+void nsDocShellLoadState::SetNotifiedBeforeUnloadListeners(
+ bool aNotifiedBeforeUnloadListeners) {
+ mNotifiedBeforeUnloadListeners = aNotifiedBeforeUnloadListeners;
+}
+
+bool nsDocShellLoadState::ForceAllowDataURI() const {
+ return mForceAllowDataURI;
+}
+
+void nsDocShellLoadState::SetForceAllowDataURI(bool aForceAllowDataURI) {
+ mForceAllowDataURI = aForceAllowDataURI;
+}
+
+bool nsDocShellLoadState::IsExemptFromHTTPSFirstMode() const {
+ return mIsExemptFromHTTPSFirstMode;
+}
+
+void nsDocShellLoadState::SetIsExemptFromHTTPSFirstMode(
+ bool aIsExemptFromHTTPSFirstMode) {
+ mIsExemptFromHTTPSFirstMode = aIsExemptFromHTTPSFirstMode;
+}
+
+bool nsDocShellLoadState::OriginalFrameSrc() const { return mOriginalFrameSrc; }
+
+void nsDocShellLoadState::SetOriginalFrameSrc(bool aOriginalFrameSrc) {
+ mOriginalFrameSrc = aOriginalFrameSrc;
+}
+
+bool nsDocShellLoadState::IsFormSubmission() const { return mIsFormSubmission; }
+
+void nsDocShellLoadState::SetIsFormSubmission(bool aIsFormSubmission) {
+ mIsFormSubmission = aIsFormSubmission;
+}
+
+uint32_t nsDocShellLoadState::LoadType() const { return mLoadType; }
+
+void nsDocShellLoadState::SetLoadType(uint32_t aLoadType) {
+ mLoadType = aLoadType;
+}
+
+nsISHEntry* nsDocShellLoadState::SHEntry() const { return mSHEntry; }
+
+void nsDocShellLoadState::SetSHEntry(nsISHEntry* aSHEntry) {
+ mSHEntry = aSHEntry;
+ nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(aSHEntry);
+ if (she) {
+ mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(she);
+ } else {
+ mLoadingSessionHistoryInfo = nullptr;
+ }
+}
+
+void nsDocShellLoadState::SetLoadingSessionHistoryInfo(
+ const mozilla::dom::LoadingSessionHistoryInfo& aLoadingInfo) {
+ SetLoadingSessionHistoryInfo(
+ MakeUnique<mozilla::dom::LoadingSessionHistoryInfo>(aLoadingInfo));
+}
+
+void nsDocShellLoadState::SetLoadingSessionHistoryInfo(
+ mozilla::UniquePtr<mozilla::dom::LoadingSessionHistoryInfo> aLoadingInfo) {
+ mLoadingSessionHistoryInfo = std::move(aLoadingInfo);
+}
+
+const mozilla::dom::LoadingSessionHistoryInfo*
+nsDocShellLoadState::GetLoadingSessionHistoryInfo() const {
+ return mLoadingSessionHistoryInfo.get();
+}
+
+void nsDocShellLoadState::SetLoadIsFromSessionHistory(
+ int32_t aOffset, bool aLoadingCurrentEntry) {
+ if (mLoadingSessionHistoryInfo) {
+ mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory = true;
+ mLoadingSessionHistoryInfo->mOffset = aOffset;
+ mLoadingSessionHistoryInfo->mLoadingCurrentEntry = aLoadingCurrentEntry;
+ }
+}
+
+void nsDocShellLoadState::ClearLoadIsFromSessionHistory() {
+ if (mLoadingSessionHistoryInfo) {
+ mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory = false;
+ }
+ mSHEntry = nullptr;
+}
+
+bool nsDocShellLoadState::LoadIsFromSessionHistory() const {
+ return mLoadingSessionHistoryInfo
+ ? mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory
+ : !!mSHEntry;
+}
+
+void nsDocShellLoadState::MaybeStripTrackerQueryStrings(
+ BrowsingContext* aContext) {
+ MOZ_ASSERT(aContext);
+
+ // Return early if the triggering principal doesn't exist. This could happen
+ // when loading a URL by using a browsing context in the Browser Toolbox.
+ if (!TriggeringPrincipal()) {
+ return;
+ }
+
+ // We don't need to strip for sub frames because the query string has been
+ // stripped in the top-level content. Also, we don't apply stripping if it
+ // is triggered by addons.
+ //
+ // Note that we don't need to do the stripping if the channel has been
+ // initialized. This means that this has been loaded speculatively in the
+ // parent process before and the stripping was happening by then.
+ if (GetChannelInitialized() || !aContext->IsTopContent() ||
+ BasePrincipal::Cast(TriggeringPrincipal())->AddonPolicy()) {
+ return;
+ }
+
+ // We don't strip the URI if it's the same-site navigation. Note that we will
+ // consider the system principal triggered load as third-party in case the
+ // user copies and pastes a URL which has tracking query parameters or an
+ // loading from external applications, such as clicking a link in an email
+ // client.
+ bool isThirdPartyURI = false;
+ if (!TriggeringPrincipal()->IsSystemPrincipal() &&
+ (NS_FAILED(
+ TriggeringPrincipal()->IsThirdPartyURI(URI(), &isThirdPartyURI)) ||
+ !isThirdPartyURI)) {
+ return;
+ }
+
+ Telemetry::AccumulateCategorical(
+ Telemetry::LABELS_QUERY_STRIPPING_COUNT::Navigation);
+
+ nsCOMPtr<nsIURI> strippedURI;
+
+ nsresult rv;
+ nsCOMPtr<nsIURLQueryStringStripper> queryStripper =
+ components::URLQueryStringStripper::Service(&rv);
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ uint32_t numStripped;
+
+ queryStripper->Strip(URI(), aContext->UsePrivateBrowsing(),
+ getter_AddRefs(strippedURI), &numStripped);
+ if (numStripped) {
+ if (!mUnstrippedURI) {
+ mUnstrippedURI = URI();
+ }
+ SetURI(strippedURI);
+
+ Telemetry::AccumulateCategorical(
+ Telemetry::LABELS_QUERY_STRIPPING_COUNT::StripForNavigation);
+ Telemetry::Accumulate(Telemetry::QUERY_STRIPPING_PARAM_COUNT, numStripped);
+ }
+
+#ifdef DEBUG
+ // Make sure that unstripped URI is the same as URI() but only the query
+ // string could be different.
+ if (mUnstrippedURI) {
+ nsCOMPtr<nsIURI> uri;
+ Unused << queryStripper->Strip(mUnstrippedURI,
+ aContext->UsePrivateBrowsing(),
+ getter_AddRefs(uri), &numStripped);
+ bool equals = false;
+ Unused << URI()->Equals(uri, &equals);
+ MOZ_ASSERT(equals);
+ }
+#endif
+}
+
+const nsString& nsDocShellLoadState::Target() const { return mTarget; }
+
+void nsDocShellLoadState::SetTarget(const nsAString& aTarget) {
+ mTarget = aTarget;
+}
+
+nsIInputStream* nsDocShellLoadState::PostDataStream() const {
+ return mPostDataStream;
+}
+
+void nsDocShellLoadState::SetPostDataStream(nsIInputStream* aStream) {
+ mPostDataStream = aStream;
+}
+
+nsIInputStream* nsDocShellLoadState::HeadersStream() const {
+ return mHeadersStream;
+}
+
+void nsDocShellLoadState::SetHeadersStream(nsIInputStream* aHeadersStream) {
+ mHeadersStream = aHeadersStream;
+}
+
+const nsString& nsDocShellLoadState::SrcdocData() const { return mSrcdocData; }
+
+void nsDocShellLoadState::SetSrcdocData(const nsAString& aSrcdocData) {
+ mSrcdocData = aSrcdocData;
+}
+
+void nsDocShellLoadState::SetSourceBrowsingContext(
+ BrowsingContext* aSourceBrowsingContext) {
+ mSourceBrowsingContext = aSourceBrowsingContext;
+}
+
+void nsDocShellLoadState::SetTargetBrowsingContext(
+ BrowsingContext* aTargetBrowsingContext) {
+ mTargetBrowsingContext = aTargetBrowsingContext;
+}
+
+nsIURI* nsDocShellLoadState::BaseURI() const { return mBaseURI; }
+
+void nsDocShellLoadState::SetBaseURI(nsIURI* aBaseURI) { mBaseURI = aBaseURI; }
+
+void nsDocShellLoadState::GetMaybeResultPrincipalURI(
+ mozilla::Maybe<nsCOMPtr<nsIURI>>& aRPURI) const {
+ bool isSome = ResultPrincipalURIIsSome();
+ aRPURI.reset();
+
+ if (!isSome) {
+ return;
+ }
+
+ nsCOMPtr<nsIURI> uri = ResultPrincipalURI();
+ aRPURI.emplace(std::move(uri));
+}
+
+void nsDocShellLoadState::SetMaybeResultPrincipalURI(
+ mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI) {
+ SetResultPrincipalURI(aRPURI.refOr(nullptr));
+ SetResultPrincipalURIIsSome(aRPURI.isSome());
+}
+
+uint32_t nsDocShellLoadState::LoadFlags() const { return mLoadFlags; }
+
+void nsDocShellLoadState::SetLoadFlags(uint32_t aLoadFlags) {
+ mLoadFlags = aLoadFlags;
+}
+
+void nsDocShellLoadState::SetLoadFlag(uint32_t aFlag) { mLoadFlags |= aFlag; }
+
+void nsDocShellLoadState::UnsetLoadFlag(uint32_t aFlag) {
+ mLoadFlags &= ~aFlag;
+}
+
+bool nsDocShellLoadState::HasLoadFlags(uint32_t aFlags) {
+ return (mLoadFlags & aFlags) == aFlags;
+}
+
+uint32_t nsDocShellLoadState::InternalLoadFlags() const {
+ return mInternalLoadFlags;
+}
+
+void nsDocShellLoadState::SetInternalLoadFlags(uint32_t aLoadFlags) {
+ mInternalLoadFlags = aLoadFlags;
+}
+
+void nsDocShellLoadState::SetInternalLoadFlag(uint32_t aFlag) {
+ mInternalLoadFlags |= aFlag;
+}
+
+void nsDocShellLoadState::UnsetInternalLoadFlag(uint32_t aFlag) {
+ mInternalLoadFlags &= ~aFlag;
+}
+
+bool nsDocShellLoadState::HasInternalLoadFlags(uint32_t aFlags) {
+ return (mInternalLoadFlags & aFlags) == aFlags;
+}
+
+bool nsDocShellLoadState::FirstParty() const { return mFirstParty; }
+
+void nsDocShellLoadState::SetFirstParty(bool aFirstParty) {
+ mFirstParty = aFirstParty;
+}
+
+bool nsDocShellLoadState::HasValidUserGestureActivation() const {
+ return mHasValidUserGestureActivation;
+}
+
+void nsDocShellLoadState::SetHasValidUserGestureActivation(
+ bool aHasValidUserGestureActivation) {
+ mHasValidUserGestureActivation = aHasValidUserGestureActivation;
+}
+
+const nsCString& nsDocShellLoadState::TypeHint() const { return mTypeHint; }
+
+void nsDocShellLoadState::SetTypeHint(const nsCString& aTypeHint) {
+ mTypeHint = aTypeHint;
+}
+
+const nsString& nsDocShellLoadState::FileName() const { return mFileName; }
+
+void nsDocShellLoadState::SetFileName(const nsAString& aFileName) {
+ MOZ_DIAGNOSTIC_ASSERT(aFileName.FindChar(char16_t(0)) == kNotFound,
+ "The filename should never contain null characters");
+ mFileName = aFileName;
+}
+
+const nsCString& nsDocShellLoadState::GetEffectiveTriggeringRemoteType() const {
+ // Consider non-errorpage loads from session history as being triggred by the
+ // parent process, as we'll validate them against the history entry.
+ //
+ // NOTE: Keep this check in-sync with the session-history validation check in
+ // `DocumentLoadListener::Open`!
+ if (LoadIsFromSessionHistory() && LoadType() != LOAD_ERROR_PAGE) {
+ return NOT_REMOTE_TYPE;
+ }
+ return mTriggeringRemoteType;
+}
+
+void nsDocShellLoadState::SetTriggeringRemoteType(
+ const nsACString& aTriggeringRemoteType) {
+ MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "only settable in parent");
+ mTriggeringRemoteType = aTriggeringRemoteType;
+}
+
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+void nsDocShellLoadState::AssertProcessCouldTriggerLoadIfSystem() {
+ // Early check to see if we're trying to start a file URI load with a system
+ // principal within a web content process.
+ // If this assertion fails, the load will fail later during
+ // nsContentSecurityManager checks, however this assertion should happen
+ // closer to whichever caller is triggering the system-principal load.
+ if (mozilla::SessionHistoryInParent() &&
+ TriggeringPrincipal()->IsSystemPrincipal() &&
+ mozilla::dom::IsWebRemoteType(GetEffectiveTriggeringRemoteType())) {
+ bool localFile = false;
+ if (NS_SUCCEEDED(NS_URIChainHasFlags(
+ URI(), nsIProtocolHandler::URI_IS_LOCAL_FILE, &localFile)) &&
+ localFile) {
+ NS_WARNING(nsPrintfCString("Unexpected system load of file URI (%s) from "
+ "web content process",
+ URI()->GetSpecOrDefault().get())
+ .get());
+ MOZ_CRASH("Unexpected system load of file URI from web content process");
+ }
+ }
+}
+#endif
+
+nsresult nsDocShellLoadState::SetupInheritingPrincipal(
+ BrowsingContext::Type aType,
+ const mozilla::OriginAttributes& aOriginAttributes) {
+ // We need a principalToInherit.
+ //
+ // If principalIsExplicit is not set there are 4 possibilities:
+ // (1) If the system principal or an expanded principal was passed
+ // in and we're a typeContent docshell, inherit the principal
+ // from the current document instead.
+ // (2) In all other cases when the principal passed in is not null,
+ // use that principal.
+ // (3) If the caller has allowed inheriting from the current document,
+ // or if we're being called from system code (eg chrome JS or pure
+ // C++) then inheritPrincipal should be true and InternalLoad will get
+ // a principal from the current document. If none of these things are
+ // true, then
+ // (4) we don't pass a principal into the channel, and a principal will be
+ // created later from the channel's internal data.
+ //
+ // If principalIsExplicit *is* set, there are 4 possibilities
+ // (1) If the system principal or an expanded principal was passed in
+ // and we're a typeContent docshell, return an error.
+ // (2) In all other cases when the principal passed in is not null,
+ // use that principal.
+ // (3) If the caller has allowed inheriting from the current document,
+ // then inheritPrincipal should be true and InternalLoad will get
+ // a principal from the current document. If none of these things are
+ // true, then
+ // (4) we dont' pass a principal into the channel, and a principal will be
+ // created later from the channel's internal data.
+ mPrincipalToInherit = mTriggeringPrincipal;
+ if (mPrincipalToInherit && aType != BrowsingContext::Type::Chrome) {
+ if (mPrincipalToInherit->IsSystemPrincipal()) {
+ if (mPrincipalIsExplicit) {
+ return NS_ERROR_DOM_SECURITY_ERR;
+ }
+ mPrincipalToInherit = nullptr;
+ mInheritPrincipal = true;
+ } else if (nsContentUtils::IsExpandedPrincipal(mPrincipalToInherit)) {
+ if (mPrincipalIsExplicit) {
+ return NS_ERROR_DOM_SECURITY_ERR;
+ }
+ // Don't inherit from the current page. Just do the safe thing
+ // and pretend that we were loaded by a nullprincipal.
+ //
+ // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
+ // have origin attributes.
+ mPrincipalToInherit = NullPrincipal::Create(aOriginAttributes);
+ mInheritPrincipal = false;
+ }
+ }
+
+ if (!mPrincipalToInherit && !mInheritPrincipal && !mPrincipalIsExplicit) {
+ // See if there's system or chrome JS code running
+ mInheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
+ }
+
+ if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
+ mInheritPrincipal = false;
+ // Create a new null principal URI based on our precursor principal.
+ nsCOMPtr<nsIURI> nullPrincipalURI =
+ NullPrincipal::CreateURI(mPrincipalToInherit);
+ // If mFirstParty is true and the pref 'privacy.firstparty.isolate' is
+ // enabled, we will set firstPartyDomain on the origin attributes.
+ OriginAttributes attrs(aOriginAttributes);
+ if (mFirstParty) {
+ attrs.SetFirstPartyDomain(true, nullPrincipalURI);
+ }
+ mPrincipalToInherit = NullPrincipal::Create(attrs, nullPrincipalURI);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsDocShellLoadState::SetupTriggeringPrincipal(
+ const mozilla::OriginAttributes& aOriginAttributes) {
+ // If the triggeringPrincipal is not set, we first try to create a principal
+ // from the referrer, since the referrer URI reflects the web origin that
+ // triggered the load. If there is no referrer URI, we fall back to using the
+ // SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
+ // and no referrer simulate a load that was triggered by the system. It's
+ // important to note that this block of code needs to appear *after* the block
+ // where we munge the principalToInherit, because otherwise we would never
+ // enter code blocks checking if the principalToInherit is null and we will
+ // end up with a wrong inheritPrincipal flag.
+ if (!mTriggeringPrincipal) {
+ if (mReferrerInfo) {
+ nsCOMPtr<nsIURI> referrer = mReferrerInfo->GetOriginalReferrer();
+ mTriggeringPrincipal =
+ BasePrincipal::CreateContentPrincipal(referrer, aOriginAttributes);
+
+ if (!mTriggeringPrincipal) {
+ return NS_ERROR_FAILURE;
+ }
+ } else {
+ mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal();
+ }
+ }
+ return NS_OK;
+}
+
+void nsDocShellLoadState::CalculateLoadURIFlags() {
+ if (mInheritPrincipal) {
+ MOZ_ASSERT(
+ !mPrincipalToInherit || !mPrincipalToInherit->IsSystemPrincipal(),
+ "Should not inherit SystemPrincipal");
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
+ }
+
+ if (mReferrerInfo && !mReferrerInfo->GetSendReferrer()) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
+ }
+ if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
+ mInternalLoadFlags |=
+ nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+ }
+
+ if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
+ }
+
+ if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
+ }
+
+ if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
+ }
+
+ if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE) {
+ mInternalLoadFlags |=
+ nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE;
+ }
+
+ if (!mSrcdocData.IsVoid()) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
+ }
+
+ if (mForceAllowDataURI) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+ }
+
+ if (mOriginalFrameSrc) {
+ mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
+ }
+}
+
+nsLoadFlags nsDocShellLoadState::CalculateChannelLoadFlags(
+ BrowsingContext* aBrowsingContext, Maybe<bool> aUriModified,
+ Maybe<bool> aIsEmbeddingBlockedError) {
+ MOZ_ASSERT(aBrowsingContext);
+
+ nsLoadFlags loadFlags = aBrowsingContext->GetDefaultLoadFlags();
+
+ if (FirstParty()) {
+ // tag first party URL loads
+ loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
+ }
+
+ const uint32_t loadType = LoadType();
+
+ // These values aren't available for loads initiated in the Parent process.
+ MOZ_ASSERT_IF(loadType == LOAD_HISTORY, aUriModified.isSome());
+ MOZ_ASSERT_IF(loadType == LOAD_ERROR_PAGE, aIsEmbeddingBlockedError.isSome());
+
+ if (loadType == LOAD_ERROR_PAGE) {
+ // Error pages are LOAD_BACKGROUND, unless it's an
+ // XFO / frame-ancestors error for which we want an error page to load
+ // but additionally want the onload() event to fire.
+ if (!*aIsEmbeddingBlockedError) {
+ loadFlags |= nsIChannel::LOAD_BACKGROUND;
+ }
+ }
+
+ // Mark the channel as being a document URI and allow content sniffing...
+ loadFlags |=
+ nsIChannel::LOAD_DOCUMENT_URI | nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
+
+ if (nsDocShell::SandboxFlagsImplyCookies(
+ aBrowsingContext->GetSandboxFlags())) {
+ loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
+ }
+
+ // Load attributes depend on load type...
+ switch (loadType) {
+ case LOAD_HISTORY: {
+ // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
+ // push/replaceState (bug 669671).
+ if (!*aUriModified) {
+ loadFlags |= nsIRequest::VALIDATE_NEVER;
+ }
+ break;
+ }
+
+ case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE:
+ case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE:
+ loadFlags |=
+ nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::LOAD_FRESH_CONNECTION;
+ [[fallthrough]];
+
+ case LOAD_REFRESH:
+ loadFlags |= nsIRequest::VALIDATE_ALWAYS;
+ break;
+
+ case LOAD_NORMAL_BYPASS_CACHE:
+ case LOAD_NORMAL_BYPASS_PROXY:
+ case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
+ case LOAD_RELOAD_BYPASS_CACHE:
+ case LOAD_RELOAD_BYPASS_PROXY:
+ case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+ case LOAD_REPLACE_BYPASS_CACHE:
+ loadFlags |=
+ nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::LOAD_FRESH_CONNECTION;
+ break;
+
+ case LOAD_RELOAD_NORMAL:
+ if (!StaticPrefs::
+ browser_soft_reload_only_force_validate_top_level_document()) {
+ loadFlags |= nsIRequest::VALIDATE_ALWAYS;
+ break;
+ }
+ [[fallthrough]];
+ case LOAD_NORMAL:
+ case LOAD_LINK:
+ // Set cache checking flags
+ switch (StaticPrefs::browser_cache_check_doc_frequency()) {
+ case 0:
+ loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
+ break;
+ case 1:
+ loadFlags |= nsIRequest::VALIDATE_ALWAYS;
+ break;
+ case 2:
+ loadFlags |= nsIRequest::VALIDATE_NEVER;
+ break;
+ }
+ break;
+ }
+
+ if (HasInternalLoadFlags(nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER)) {
+ loadFlags |= nsIChannel::LOAD_BYPASS_URL_CLASSIFIER;
+ }
+
+ // If the user pressed shift-reload, then do not allow ServiceWorker
+ // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
+ if (IsForceReloadType(loadType)) {
+ loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
+ }
+
+ return loadFlags;
+}
+
+const char* nsDocShellLoadState::ValidateWithOriginalState(
+ nsDocShellLoadState* aOriginalState) {
+ MOZ_ASSERT(mLoadIdentifier == aOriginalState->mLoadIdentifier);
+
+ // Check that `aOriginalState` is sufficiently similar to this state that
+ // they're performing the same load.
+ auto uriEq = [](nsIURI* a, nsIURI* b) -> bool {
+ bool eq = false;
+ return a == b || (a && b && NS_SUCCEEDED(a->Equals(b, &eq)) && eq);
+ };
+ if (!uriEq(mURI, aOriginalState->mURI)) {
+ return "URI";
+ }
+ if (!uriEq(mUnstrippedURI, aOriginalState->mUnstrippedURI)) {
+ return "UnstrippedURI";
+ }
+ if (!uriEq(mOriginalURI, aOriginalState->mOriginalURI)) {
+ return "OriginalURI";
+ }
+ if (!uriEq(mBaseURI, aOriginalState->mBaseURI)) {
+ return "BaseURI";
+ }
+
+ if (!mTriggeringPrincipal->Equals(aOriginalState->mTriggeringPrincipal)) {
+ return "TriggeringPrincipal";
+ }
+ if (mTriggeringSandboxFlags != aOriginalState->mTriggeringSandboxFlags) {
+ return "TriggeringSandboxFlags";
+ }
+ if (mTriggeringRemoteType != aOriginalState->mTriggeringRemoteType) {
+ return "TriggeringRemoteType";
+ }
+
+ if (mOriginalURIString != aOriginalState->mOriginalURIString) {
+ return "OriginalURIString";
+ }
+
+ if (mRemoteTypeOverride != aOriginalState->mRemoteTypeOverride) {
+ return "RemoteTypeOverride";
+ }
+
+ if (mSourceBrowsingContext.ContextId() !=
+ aOriginalState->mSourceBrowsingContext.ContextId()) {
+ return "SourceBrowsingContext";
+ }
+
+ // FIXME: Consider calculating less information in the target process so that
+ // we can validate more properties more easily.
+ // FIXME: Identify what other flags will not change when sent through a
+ // content process.
+
+ return nullptr;
+}
+
+DocShellLoadStateInit nsDocShellLoadState::Serialize(
+ mozilla::ipc::IProtocol* aActor) {
+ MOZ_ASSERT(aActor);
+ DocShellLoadStateInit loadState;
+ loadState.ResultPrincipalURI() = mResultPrincipalURI;
+ loadState.ResultPrincipalURIIsSome() = mResultPrincipalURIIsSome;
+ loadState.KeepResultPrincipalURIIfSet() = mKeepResultPrincipalURIIfSet;
+ loadState.LoadReplace() = mLoadReplace;
+ loadState.InheritPrincipal() = mInheritPrincipal;
+ loadState.PrincipalIsExplicit() = mPrincipalIsExplicit;
+ loadState.ForceAllowDataURI() = mForceAllowDataURI;
+ loadState.IsExemptFromHTTPSFirstMode() = mIsExemptFromHTTPSFirstMode;
+ loadState.OriginalFrameSrc() = mOriginalFrameSrc;
+ loadState.IsFormSubmission() = mIsFormSubmission;
+ loadState.LoadType() = mLoadType;
+ loadState.Target() = mTarget;
+ loadState.TargetBrowsingContext() = mTargetBrowsingContext;
+ loadState.LoadFlags() = mLoadFlags;
+ loadState.InternalLoadFlags() = mInternalLoadFlags;
+ loadState.FirstParty() = mFirstParty;
+ loadState.HasValidUserGestureActivation() = mHasValidUserGestureActivation;
+ loadState.AllowFocusMove() = mAllowFocusMove;
+ loadState.TypeHint() = mTypeHint;
+ loadState.FileName() = mFileName;
+ loadState.IsFromProcessingFrameAttributes() =
+ mIsFromProcessingFrameAttributes;
+ loadState.URI() = mURI;
+ loadState.OriginalURI() = mOriginalURI;
+ loadState.SourceBrowsingContext() = mSourceBrowsingContext;
+ loadState.BaseURI() = mBaseURI;
+ loadState.TriggeringPrincipal() = mTriggeringPrincipal;
+ loadState.PrincipalToInherit() = mPrincipalToInherit;
+ loadState.PartitionedPrincipalToInherit() = mPartitionedPrincipalToInherit;
+ loadState.TriggeringSandboxFlags() = mTriggeringSandboxFlags;
+ loadState.TriggeringWindowId() = mTriggeringWindowId;
+ loadState.TriggeringStorageAccess() = mTriggeringStorageAccess;
+ loadState.TriggeringRemoteType() = mTriggeringRemoteType;
+ loadState.WasSchemelessInput() = mWasSchemelessInput;
+ loadState.Csp() = mCsp;
+ loadState.OriginalURIString() = mOriginalURIString;
+ loadState.CancelContentJSEpoch() = mCancelContentJSEpoch;
+ loadState.ReferrerInfo() = mReferrerInfo;
+ loadState.PostDataStream() = mPostDataStream;
+ loadState.HeadersStream() = mHeadersStream;
+ loadState.SrcdocData() = mSrcdocData;
+ loadState.ResultPrincipalURI() = mResultPrincipalURI;
+ loadState.LoadIdentifier() = mLoadIdentifier;
+ loadState.ChannelInitialized() = mChannelInitialized;
+ loadState.IsMetaRefresh() = mIsMetaRefresh;
+ if (mLoadingSessionHistoryInfo) {
+ loadState.loadingSessionHistoryInfo().emplace(*mLoadingSessionHistoryInfo);
+ }
+ loadState.UnstrippedURI() = mUnstrippedURI;
+ loadState.RemoteTypeOverride() = mRemoteTypeOverride;
+
+ if (XRE_IsParentProcess()) {
+ mozilla::ipc::IToplevelProtocol* top = aActor->ToplevelProtocol();
+ MOZ_RELEASE_ASSERT(top &&
+ top->GetProtocolId() ==
+ mozilla::ipc::ProtocolId::PContentMsgStart &&
+ top->GetSide() == mozilla::ipc::ParentSide,
+ "nsDocShellLoadState must be sent over PContent");
+ ContentParent* cp = static_cast<ContentParent*>(top);
+ cp->StorePendingLoadState(this);
+ }
+
+ return loadState;
+}
+
+nsIURI* nsDocShellLoadState::GetUnstrippedURI() const { return mUnstrippedURI; }
+
+void nsDocShellLoadState::SetUnstrippedURI(nsIURI* aUnstrippedURI) {
+ mUnstrippedURI = aUnstrippedURI;
+}