docshell/base/nsDocShellLoadState.cpp
author Valentin Gosu <valentin.gosu@gmail.com>
Wed, 21 Nov 2018 16:28:20 +0000
changeset 503930 78665669badebd0088569691b6c7df09e2286d84
parent 503908 08c81bf2175844b1457258baec46dfd65c596914
child 504902 62089e4c3cc06b7a867e40b1ab75992cb04820ff
permissions -rw-r--r--
Bug 1487964 - Do not report resource-timing subdocument loads triggered by that subdocument r=bzbarsky Differential Revision: https://phabricator.services.mozilla.com/D9503

/* -*- 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<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;
}

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;
  }
}