/* -*- 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 "nsIDocShellTreeItem.h" #include "nsIScriptSecurityManager.h" #include "nsIWebNavigation.h" #include "mozilla/OriginAttributes.h" #include "mozilla/NullPrincipal.h" nsDocShellLoadState::nsDocShellLoadState() : mResultPrincipalURIIsSome(false) , mKeepResultPrincipalURIIfSet(false) , mLoadReplace(false) , mInheritPrincipal(false) , mPrincipalIsExplicit(false) , mForceAllowDataURI(false) , mOriginalFrameSrc(false) , mSendReferrer(true) , mReferrerPolicy(mozilla::net::RP_Unset) , mLoadType(LOAD_NORMAL) , mIsSrcdocLoad(false) , mLoadFlags(0) , mFirstParty(false) , mTypeHint(VoidCString()) , mFileName(VoidString()) , mDocShellInternalLoadFlags(0) , mIsFromProcessingFrameAttributes(false) { } nsDocShellLoadState::~nsDocShellLoadState() { } nsIURI* nsDocShellLoadState::Referrer() const { return mReferrer; } void nsDocShellLoadState::SetReferrer(nsIURI* aReferrer) { mReferrer = aReferrer; } 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; } 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::ForceAllowDataURI() const { return mForceAllowDataURI; } void nsDocShellLoadState::SetForceAllowDataURI(bool aForceAllowDataURI) { mForceAllowDataURI = aForceAllowDataURI; } bool nsDocShellLoadState::OriginalFrameSrc() const { return mOriginalFrameSrc; } void nsDocShellLoadState::SetOriginalFrameSrc(bool aOriginalFrameSrc) { mOriginalFrameSrc = aOriginalFrameSrc; } 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; } 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; } bool nsDocShellLoadState::SendReferrer() const { return mSendReferrer; } void nsDocShellLoadState::SetSendReferrer(bool aSendReferrer) { mSendReferrer = aSendReferrer; } uint32_t nsDocShellLoadState::ReferrerPolicy() const { return mReferrerPolicy; } void nsDocShellLoadState::SetReferrerPolicy(mozilla::net::ReferrerPolicy aReferrerPolicy) { mReferrerPolicy = aReferrerPolicy; } bool nsDocShellLoadState::IsSrcdocLoad() const { return mIsSrcdocLoad; } const nsString& nsDocShellLoadState::SrcdocData() const { return mSrcdocData; } void nsDocShellLoadState::SetSrcdocData(const nsAString& aSrcdocData) { mSrcdocData = aSrcdocData; mIsSrcdocLoad = true; } nsIDocShell* nsDocShellLoadState::SourceDocShell() const { return mSourceDocShell; } void nsDocShellLoadState::SetSourceDocShell(nsIDocShell* aSourceDocShell) { mSourceDocShell = aSourceDocShell; } nsIURI* nsDocShellLoadState::BaseURI() const { return mBaseURI; } void nsDocShellLoadState::SetBaseURI(nsIURI* aBaseURI) { mBaseURI = aBaseURI; } void nsDocShellLoadState::GetMaybeResultPrincipalURI(mozilla::Maybe>& aRPURI) const { bool isSome = ResultPrincipalURIIsSome(); aRPURI.reset(); if (!isSome) { return; } nsCOMPtr uri = ResultPrincipalURI(); aRPURI.emplace(std::move(uri)); } void nsDocShellLoadState::SetMaybeResultPrincipalURI(mozilla::Maybe> const& aRPURI) { SetResultPrincipalURI(aRPURI.refOr(nullptr)); SetResultPrincipalURIIsSome(aRPURI.isSome()); } uint32_t nsDocShellLoadState::LoadFlags() const { return mLoadFlags; } void nsDocShellLoadState::SetLoadFlags(uint32_t aLoadFlags) { mLoadFlags = aLoadFlags; } bool nsDocShellLoadState::FirstParty() const { return mFirstParty; } void nsDocShellLoadState::SetFirstParty(bool aFirstParty) { mFirstParty = aFirstParty; } 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) { mFileName = aFileName; } uint32_t nsDocShellLoadState::DocShellInternalLoadFlags() const { return mDocShellInternalLoadFlags; } void nsDocShellLoadState::SetDocShellInternalLoadFlags(uint32_t aFlags) { mDocShellInternalLoadFlags = aFlags; } nsresult nsDocShellLoadState::SetupInheritingPrincipal(uint32_t aItemType, 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 && aItemType != nsIDocShellTreeItem::typeChrome) { if (nsContentUtils::IsSystemPrincipal(mPrincipalToInherit)) { 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::CreateWithInheritedAttributes(aOriginAttributes, false); 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; // If mFirstParty is true and the pref 'privacy.firstparty.isolate' is // enabled, we will set firstPartyDomain on the origin attributes. mPrincipalToInherit = NullPrincipal::CreateWithInheritedAttributes(aOriginAttributes, mFirstParty); } 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 (mReferrer) { mTriggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(mReferrer, aOriginAttributes); if (!mTriggeringPrincipal) { return NS_ERROR_FAILURE; } } else { #ifndef ANDROID MOZ_ASSERT(false, "LoadURI: System principal required."); #endif mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal(); } } return NS_OK; } void nsDocShellLoadState::CalculateDocShellInternalLoadFlags() { MOZ_ASSERT(mDocShellInternalLoadFlags == 0, "Shouldn't have any load flags set at this point."); if (mInheritPrincipal) { MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(mPrincipalToInherit), "Should not inherit SystemPrincipal"); mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL; } if (!mSendReferrer) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; } if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; } if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD; } if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; } if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_COOKIES) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES; } if (mIsSrcdocLoad) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC; } if (mForceAllowDataURI) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI; } if (mOriginalFrameSrc) { mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC; } }