tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SessionHistoryEntry.cpp (61583B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SessionHistoryEntry.h"
      8 #include "ipc/IPCMessageUtilsSpecializations.h"
      9 #include "nsDocShell.h"
     10 #include "nsDocShellLoadState.h"
     11 #include "nsFrameLoader.h"
     12 #include "nsIFormPOSTActionChannel.h"
     13 #include "nsIHttpChannel.h"
     14 #include "nsIUploadChannel2.h"
     15 #include "nsIXULRuntime.h"
     16 #include "nsSHEntryShared.h"
     17 #include "nsSHistory.h"
     18 #include "nsStreamUtils.h"
     19 #include "nsStructuredCloneContainer.h"
     20 #include "nsXULAppAPI.h"
     21 #include "mozilla/PresState.h"
     22 #include "mozilla/StaticPrefs_fission.h"
     23 #include "mozilla/dom/BindingIPCUtils.h"
     24 #include "mozilla/dom/BrowserParent.h"
     25 #include "mozilla/dom/CanonicalBrowsingContext.h"
     26 #include "mozilla/dom/ContentChild.h"
     27 #include "mozilla/dom/ContentParent.h"
     28 #include "mozilla/dom/CSPMessageUtils.h"
     29 #include "mozilla/dom/PolicyContainerMessageUtils.h"
     30 #include "mozilla/dom/DocumentBinding.h"
     31 #include "mozilla/dom/DOMTypes.h"
     32 #include "mozilla/dom/NavigationAPIIPCUtils.h"
     33 #include "mozilla/dom/nsCSPContext.h"
     34 #include "mozilla/dom/nsCSPUtils.h"
     35 #include "mozilla/dom/PermissionMessageUtils.h"
     36 #include "mozilla/dom/PolicyContainer.h"
     37 #include "mozilla/dom/ReferrerInfoUtils.h"
     38 #include "mozilla/ipc/ProtocolUtils.h"
     39 #include "mozilla/ipc/URIUtils.h"
     40 
     41 extern mozilla::LazyLogModule gSHLog;
     42 
     43 namespace mozilla {
     44 namespace dom {
     45 
     46 SessionHistoryInfo::SessionHistoryInfo(nsDocShellLoadState* aLoadState,
     47                                       nsIChannel* aChannel)
     48    : mURI(aLoadState->URI()),
     49      mOriginalURI(aLoadState->OriginalURI()),
     50      mResultPrincipalURI(aLoadState->ResultPrincipalURI()),
     51      mUnstrippedURI(aLoadState->GetUnstrippedURI()),
     52      mLoadType(aLoadState->LoadType()),
     53      mSrcdocData(aLoadState->SrcdocData().IsVoid()
     54                      ? Nothing()
     55                      : Some(aLoadState->SrcdocData())),
     56      mBaseURI(aLoadState->BaseURI()),
     57      mNavigationAPIState(static_cast<nsStructuredCloneContainer*>(
     58          aLoadState->GetNavigationAPIState())),
     59      mLoadReplace(aLoadState->LoadReplace()),
     60      mHasUserActivation(aLoadState->HasValidUserGestureActivation()),
     61      mSharedState(SharedState::Create(
     62          aLoadState->TriggeringPrincipal(), aLoadState->PrincipalToInherit(),
     63          aLoadState->PartitionedPrincipalToInherit(),
     64          aLoadState->PolicyContainer(),
     65          /* FIXME Is this correct? */
     66          aLoadState->TypeHint())) {
     67  // Pull the upload stream off of the channel instead of the load state, as
     68  // ownership has already been transferred from the load state to the channel.
     69  if (nsCOMPtr<nsIUploadChannel2> postChannel = do_QueryInterface(aChannel)) {
     70    int64_t contentLength;
     71    MOZ_ALWAYS_SUCCEEDS(postChannel->CloneUploadStream(
     72        &contentLength, getter_AddRefs(mPostData)));
     73    MOZ_ASSERT_IF(mPostData, NS_InputStreamIsCloneable(mPostData));
     74  }
     75 
     76  if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
     77    mReferrerInfo = httpChannel->GetReferrerInfo();
     78  }
     79 
     80  MaybeUpdateTitleFromURI();
     81 }
     82 
     83 SessionHistoryInfo::SessionHistoryInfo(
     84    const SessionHistoryInfo& aSharedStateFrom, nsIURI* aURI)
     85    : mURI(aURI), mSharedState(aSharedStateFrom.mSharedState) {
     86  MaybeUpdateTitleFromURI();
     87  mHasUserInteraction = aSharedStateFrom.mHasUserInteraction;
     88 }
     89 
     90 SessionHistoryInfo::SessionHistoryInfo(
     91    nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
     92    nsIPrincipal* aPrincipalToInherit,
     93    nsIPrincipal* aPartitionedPrincipalToInherit,
     94    nsIPolicyContainer* aPolicyContainer, const nsACString& aContentType)
     95    : mURI(aURI),
     96      mSharedState(SharedState::Create(
     97          aTriggeringPrincipal, aPrincipalToInherit,
     98          aPartitionedPrincipalToInherit, aPolicyContainer, aContentType)) {
     99  MaybeUpdateTitleFromURI();
    100 }
    101 
    102 SessionHistoryInfo::SessionHistoryInfo(
    103    nsIChannel* aChannel, uint32_t aLoadType,
    104    nsIPrincipal* aPartitionedPrincipalToInherit,
    105    nsIPolicyContainer* aPolicyContainer) {
    106  if (NS_FAILED(NS_GetFinalChannelURI(aChannel, getter_AddRefs(mURI)))) {
    107    NS_WARNING("NS_GetFinalChannelURI somehow failed in SessionHistoryInfo?");
    108    aChannel->GetURI(getter_AddRefs(mURI));
    109  }
    110  mLoadType = aLoadType;
    111 
    112  nsCOMPtr<nsILoadInfo> loadInfo;
    113  aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
    114 
    115  loadInfo->GetResultPrincipalURI(getter_AddRefs(mResultPrincipalURI));
    116  loadInfo->GetUnstrippedURI(getter_AddRefs(mUnstrippedURI));
    117  loadInfo->GetTriggeringPrincipal(
    118      getter_AddRefs(mSharedState.Get()->mTriggeringPrincipal));
    119  loadInfo->GetPrincipalToInherit(
    120      getter_AddRefs(mSharedState.Get()->mPrincipalToInherit));
    121 
    122  mSharedState.Get()->mPartitionedPrincipalToInherit =
    123      aPartitionedPrincipalToInherit;
    124  mSharedState.Get()->mPolicyContainer = aPolicyContainer;
    125  aChannel->GetContentType(mSharedState.Get()->mContentType);
    126  aChannel->GetOriginalURI(getter_AddRefs(mOriginalURI));
    127 
    128  uint32_t loadFlags;
    129  aChannel->GetLoadFlags(&loadFlags);
    130  mLoadReplace = !!(loadFlags & nsIChannel::LOAD_REPLACE);
    131 
    132  MaybeUpdateTitleFromURI();
    133 
    134  if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
    135    mReferrerInfo = httpChannel->GetReferrerInfo();
    136  }
    137 }
    138 
    139 void SessionHistoryInfo::Reset(nsIURI* aURI, const nsID& aDocShellID,
    140                               bool aDynamicCreation,
    141                               nsIPrincipal* aTriggeringPrincipal,
    142                               nsIPrincipal* aPrincipalToInherit,
    143                               nsIPrincipal* aPartitionedPrincipalToInherit,
    144                               nsIPolicyContainer* aPolicyContainer,
    145                               const nsACString& aContentType) {
    146  mURI = aURI;
    147  mOriginalURI = nullptr;
    148  mResultPrincipalURI = nullptr;
    149  mUnstrippedURI = nullptr;
    150  mReferrerInfo = nullptr;
    151  // Default title is the URL.
    152  nsAutoCString spec;
    153  if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
    154    CopyUTF8toUTF16(spec, mTitle);
    155  }
    156  mPostData = nullptr;
    157  mLoadType = 0;
    158  mScrollPositionX = 0;
    159  mScrollPositionY = 0;
    160  mStateData = nullptr;
    161  mSrcdocData = Nothing();
    162  mBaseURI = nullptr;
    163  mLoadReplace = false;
    164  mURIWasModified = false;
    165  mScrollRestorationIsManual = false;
    166  mTransient = false;
    167  mHasUserInteraction = false;
    168  mHasUserActivation = false;
    169  mNavigationAPIState = nullptr;
    170 
    171  mSharedState.Get()->mTriggeringPrincipal = aTriggeringPrincipal;
    172  mSharedState.Get()->mPrincipalToInherit = aPrincipalToInherit;
    173  mSharedState.Get()->mPartitionedPrincipalToInherit =
    174      aPartitionedPrincipalToInherit;
    175  mSharedState.Get()->mPolicyContainer = aPolicyContainer;
    176  mSharedState.Get()->mContentType = aContentType;
    177  mSharedState.Get()->mLayoutHistoryState = nullptr;
    178 }
    179 
    180 void SessionHistoryInfo::MaybeUpdateTitleFromURI() {
    181  if (mTitle.IsEmpty() && mURI) {
    182    // Default title is the URL.
    183    nsAutoCString spec;
    184    if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
    185      AppendUTF8toUTF16(spec, mTitle);
    186    }
    187  }
    188 }
    189 
    190 already_AddRefed<nsIInputStream> SessionHistoryInfo::GetPostData() const {
    191  // Return a clone of our post data stream. Our caller will either be
    192  // transferring this stream to a different SessionHistoryInfo, or passing it
    193  // off to necko/another process which will consume it, and we want to preserve
    194  // our local instance.
    195  nsCOMPtr<nsIInputStream> postData;
    196  if (mPostData) {
    197    MOZ_ALWAYS_SUCCEEDS(
    198        NS_CloneInputStream(mPostData, getter_AddRefs(postData)));
    199  }
    200  return postData.forget();
    201 }
    202 
    203 void SessionHistoryInfo::SetPostData(nsIInputStream* aPostData) {
    204  MOZ_ASSERT_IF(aPostData, NS_InputStreamIsCloneable(aPostData));
    205  mPostData = aPostData;
    206 }
    207 
    208 uint64_t SessionHistoryInfo::SharedId() const {
    209  return mSharedState.Get()->mId;
    210 }
    211 
    212 nsILayoutHistoryState* SessionHistoryInfo::GetLayoutHistoryState() {
    213  return mSharedState.Get()->mLayoutHistoryState;
    214 }
    215 
    216 void SessionHistoryInfo::SetLayoutHistoryState(nsILayoutHistoryState* aState) {
    217  mSharedState.Get()->mLayoutHistoryState = aState;
    218  if (mSharedState.Get()->mLayoutHistoryState) {
    219    mSharedState.Get()->mLayoutHistoryState->SetScrollPositionOnly(
    220        !mSharedState.Get()->mSaveLayoutState);
    221  }
    222 }
    223 
    224 nsIPrincipal* SessionHistoryInfo::GetTriggeringPrincipal() const {
    225  return mSharedState.Get()->mTriggeringPrincipal;
    226 }
    227 
    228 nsIPrincipal* SessionHistoryInfo::GetPrincipalToInherit() const {
    229  return mSharedState.Get()->mPrincipalToInherit;
    230 }
    231 
    232 nsIPrincipal* SessionHistoryInfo::GetPartitionedPrincipalToInherit() const {
    233  return mSharedState.Get()->mPartitionedPrincipalToInherit;
    234 }
    235 
    236 void SessionHistoryInfo::SetPartitionedPrincipalToInherit(
    237    nsIPrincipal* aPartitionedPrincipal) {
    238  mSharedState.Get()->mPartitionedPrincipalToInherit = aPartitionedPrincipal;
    239 }
    240 
    241 nsIPolicyContainer* SessionHistoryInfo::GetPolicyContainer() const {
    242  return mSharedState.Get()->mPolicyContainer;
    243 }
    244 
    245 uint32_t SessionHistoryInfo::GetCacheKey() const {
    246  return mSharedState.Get()->mCacheKey;
    247 }
    248 
    249 void SessionHistoryInfo::SetCacheKey(uint32_t aCacheKey) {
    250  mSharedState.Get()->mCacheKey = aCacheKey;
    251 }
    252 
    253 bool SessionHistoryInfo::IsSubFrame() const {
    254  return mSharedState.Get()->mIsFrameNavigation;
    255 }
    256 
    257 nsIStructuredCloneContainer* SessionHistoryInfo::GetNavigationAPIState() const {
    258  return mNavigationAPIState.get();
    259 }
    260 
    261 void SessionHistoryInfo::SetNavigationAPIState(
    262    nsIStructuredCloneContainer* aState) {
    263  mNavigationAPIState = static_cast<nsStructuredCloneContainer*>(aState);
    264 }
    265 
    266 void SessionHistoryInfo::SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag) {
    267  MOZ_ASSERT(XRE_IsParentProcess());
    268  static_cast<SHEntrySharedParentState*>(mSharedState.Get())->mSaveLayoutState =
    269      aSaveLayoutStateFlag;
    270 }
    271 
    272 void SessionHistoryInfo::FillLoadInfo(nsDocShellLoadState& aLoadState) const {
    273  aLoadState.SetOriginalURI(mOriginalURI);
    274  aLoadState.SetMaybeResultPrincipalURI(Some(mResultPrincipalURI));
    275  aLoadState.SetUnstrippedURI(mUnstrippedURI);
    276  aLoadState.SetLoadReplace(mLoadReplace);
    277  nsCOMPtr<nsIInputStream> postData = GetPostData();
    278  aLoadState.SetPostDataStream(postData);
    279  aLoadState.SetReferrerInfo(mReferrerInfo);
    280 
    281  aLoadState.SetTypeHint(mSharedState.Get()->mContentType);
    282  aLoadState.SetTriggeringPrincipal(mSharedState.Get()->mTriggeringPrincipal);
    283  aLoadState.SetPrincipalToInherit(mSharedState.Get()->mPrincipalToInherit);
    284  aLoadState.SetPartitionedPrincipalToInherit(
    285      mSharedState.Get()->mPartitionedPrincipalToInherit);
    286  aLoadState.SetPolicyContainer(mSharedState.Get()->mPolicyContainer);
    287 
    288  // Do not inherit principal from document (security-critical!);
    289  uint32_t flags = nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_NONE;
    290 
    291  // Passing nullptr as aSourceDocShell gives the same behaviour as before
    292  // aSourceDocShell was introduced. According to spec we should be passing
    293  // the source browsing context that was used when the history entry was
    294  // first created. bug 947716 has been created to address this issue.
    295  nsAutoString srcdoc;
    296  nsCOMPtr<nsIURI> baseURI;
    297  if (mSrcdocData) {
    298    srcdoc = mSrcdocData.value();
    299    baseURI = mBaseURI;
    300    flags |= nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
    301  } else {
    302    srcdoc = VoidString();
    303  }
    304  aLoadState.SetSrcdocData(srcdoc);
    305  aLoadState.SetBaseURI(baseURI);
    306  aLoadState.SetInternalLoadFlags(flags);
    307 
    308  aLoadState.SetFirstParty(true);
    309 
    310  // When we create a load state from the history info we already know if
    311  // https-first was able to upgrade the request from http to https. There is no
    312  // point in re-retrying to upgrade. On a reload we still want to check,
    313  // because the exemptions set by the user could have changed.
    314  if ((mLoadType & nsIDocShell::LOAD_CMD_RELOAD) == 0) {
    315    aLoadState.SetIsExemptFromHTTPSFirstMode(true);
    316  }
    317 }
    318 /* static */
    319 SessionHistoryInfo::SharedState SessionHistoryInfo::SharedState::Create(
    320    nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
    321    nsIPrincipal* aPartitionedPrincipalToInherit,
    322    nsIPolicyContainer* aPolicyContainer, const nsACString& aContentType) {
    323  if (XRE_IsParentProcess()) {
    324    return SharedState(new SHEntrySharedParentState(
    325        aTriggeringPrincipal, aPrincipalToInherit,
    326        aPartitionedPrincipalToInherit, aPolicyContainer, aContentType));
    327  }
    328 
    329  return SharedState(MakeUnique<SHEntrySharedState>(
    330      aTriggeringPrincipal, aPrincipalToInherit, aPartitionedPrincipalToInherit,
    331      aPolicyContainer, aContentType));
    332 }
    333 
    334 SessionHistoryInfo::SharedState::SharedState() { Init(); }
    335 
    336 SessionHistoryInfo::SharedState::SharedState(
    337    const SessionHistoryInfo::SharedState& aOther) {
    338  Init(aOther);
    339 }
    340 
    341 SessionHistoryInfo::SharedState::SharedState(
    342    const Maybe<const SessionHistoryInfo::SharedState&>& aOther) {
    343  if (aOther.isSome()) {
    344    Init(aOther.ref());
    345  } else {
    346    Init();
    347  }
    348 }
    349 
    350 SessionHistoryInfo::SharedState::~SharedState() {
    351  if (XRE_IsParentProcess()) {
    352    mParent
    353        .RefPtr<SHEntrySharedParentState>::~RefPtr<SHEntrySharedParentState>();
    354  } else {
    355    mChild.UniquePtr<SHEntrySharedState>::~unique_ptr<
    356        SHEntrySharedState, DefaultDelete<SHEntrySharedState>>();
    357  }
    358 }
    359 
    360 SessionHistoryInfo::SharedState& SessionHistoryInfo::SharedState::operator=(
    361    const SessionHistoryInfo::SharedState& aOther) {
    362  if (this != &aOther) {
    363    if (XRE_IsParentProcess()) {
    364      mParent = aOther.mParent;
    365    } else {
    366      mChild = MakeUnique<SHEntrySharedState>(*aOther.mChild);
    367    }
    368  }
    369  return *this;
    370 }
    371 
    372 SHEntrySharedState* SessionHistoryInfo::SharedState::Get() const {
    373  if (XRE_IsParentProcess()) {
    374    return mParent;
    375  }
    376 
    377  return mChild.get();
    378 }
    379 
    380 void SessionHistoryInfo::SharedState::ChangeId(uint64_t aId) {
    381  if (XRE_IsParentProcess()) {
    382    mParent->ChangeId(aId);
    383  } else {
    384    mChild->mId = aId;
    385  }
    386 }
    387 
    388 void SessionHistoryInfo::SharedState::Init() {
    389  if (XRE_IsParentProcess()) {
    390    new (&mParent)
    391        RefPtr<SHEntrySharedParentState>(new SHEntrySharedParentState());
    392  } else {
    393    new (&mChild)
    394        UniquePtr<SHEntrySharedState>(MakeUnique<SHEntrySharedState>());
    395  }
    396 }
    397 
    398 void SessionHistoryInfo::SharedState::Init(
    399    const SessionHistoryInfo::SharedState& aOther) {
    400  if (XRE_IsParentProcess()) {
    401    new (&mParent) RefPtr<SHEntrySharedParentState>(aOther.mParent);
    402  } else {
    403    new (&mChild) UniquePtr<SHEntrySharedState>(
    404        MakeUnique<SHEntrySharedState>(*aOther.mChild));
    405  }
    406 }
    407 
    408 static uint64_t gLoadingSessionHistoryInfoLoadId = 0;
    409 
    410 nsTHashMap<nsUint64HashKey, SessionHistoryEntry::LoadingEntry>*
    411    SessionHistoryEntry::sLoadIdToEntry = nullptr;
    412 
    413 LoadingSessionHistoryInfo::LoadingSessionHistoryInfo(
    414    SessionHistoryEntry* aEntry)
    415    : mInfo(aEntry->Info()), mLoadId(++gLoadingSessionHistoryInfoLoadId) {
    416  SessionHistoryEntry::SetByLoadId(mLoadId, aEntry);
    417 }
    418 
    419 LoadingSessionHistoryInfo::LoadingSessionHistoryInfo(
    420    SessionHistoryEntry* aEntry, const LoadingSessionHistoryInfo* aInfo)
    421    : mInfo(aEntry->Info()),
    422      mTriggeringEntry(aInfo->mTriggeringEntry),
    423      mTriggeringNavigationType(aInfo->mTriggeringNavigationType),
    424      mLoadId(aInfo->mLoadId),
    425      mLoadIsFromSessionHistory(aInfo->mLoadIsFromSessionHistory),
    426      mOffset(aInfo->mOffset),
    427      mLoadingCurrentEntry(aInfo->mLoadingCurrentEntry) {
    428  MOZ_ASSERT(SessionHistoryEntry::GetByLoadId(mLoadId)->mEntry == aEntry);
    429 }
    430 
    431 LoadingSessionHistoryInfo::LoadingSessionHistoryInfo(
    432    const SessionHistoryInfo& aInfo)
    433    : mInfo(aInfo), mLoadId(UINT64_MAX) {}
    434 
    435 already_AddRefed<nsDocShellLoadState>
    436 LoadingSessionHistoryInfo::CreateLoadInfo() const {
    437  RefPtr<nsDocShellLoadState> loadState(
    438      new nsDocShellLoadState(mInfo.GetURI()));
    439 
    440  mInfo.FillLoadInfo(*loadState);
    441 
    442  loadState->SetLoadingSessionHistoryInfo(*this);
    443 
    444  return loadState.forget();
    445 }
    446 
    447 static uint32_t gEntryID;
    448 
    449 SessionHistoryEntry::LoadingEntry* SessionHistoryEntry::GetByLoadId(
    450    uint64_t aLoadId) {
    451  MOZ_ASSERT(XRE_IsParentProcess());
    452  if (!sLoadIdToEntry) {
    453    return nullptr;
    454  }
    455 
    456  return sLoadIdToEntry->Lookup(aLoadId).DataPtrOrNull();
    457 }
    458 
    459 void SessionHistoryEntry::SetByLoadId(uint64_t aLoadId,
    460                                      SessionHistoryEntry* aEntry) {
    461  if (!sLoadIdToEntry) {
    462    sLoadIdToEntry = new nsTHashMap<nsUint64HashKey, LoadingEntry>();
    463  }
    464 
    465  MOZ_LOG(
    466      gSHLog, LogLevel::Verbose,
    467      ("SessionHistoryEntry::SetByLoadId(%" PRIu64 " - %p)", aLoadId, aEntry));
    468  sLoadIdToEntry->InsertOrUpdate(
    469      aLoadId, LoadingEntry{
    470                   .mEntry = aEntry,
    471                   .mInfoSnapshotForValidation =
    472                       MakeUnique<SessionHistoryInfo>(aEntry->Info()),
    473               });
    474 }
    475 
    476 void SessionHistoryEntry::RemoveLoadId(uint64_t aLoadId) {
    477  MOZ_ASSERT(XRE_IsParentProcess());
    478  if (!sLoadIdToEntry) {
    479    return;
    480  }
    481 
    482  MOZ_LOG(gSHLog, LogLevel::Verbose,
    483          ("SHEntry::RemoveLoadId(%" PRIu64 ")", aLoadId));
    484  sLoadIdToEntry->Remove(aLoadId);
    485 }
    486 
    487 SessionHistoryEntry::SessionHistoryEntry()
    488    : mInfo(new SessionHistoryInfo()), mID(++gEntryID) {
    489  MOZ_ASSERT(mozilla::SessionHistoryInParent());
    490 }
    491 
    492 SessionHistoryEntry::SessionHistoryEntry(nsDocShellLoadState* aLoadState,
    493                                         nsIChannel* aChannel)
    494    : mInfo(new SessionHistoryInfo(aLoadState, aChannel)), mID(++gEntryID) {
    495  MOZ_ASSERT(mozilla::SessionHistoryInParent());
    496 }
    497 
    498 SessionHistoryEntry::SessionHistoryEntry(SessionHistoryInfo* aInfo)
    499    : mInfo(MakeUnique<SessionHistoryInfo>(*aInfo)), mID(++gEntryID) {
    500  MOZ_ASSERT(mozilla::SessionHistoryInParent());
    501 }
    502 
    503 SessionHistoryEntry::SessionHistoryEntry(const SessionHistoryEntry& aEntry)
    504    : mInfo(MakeUnique<SessionHistoryInfo>(*aEntry.mInfo)),
    505      mParent(aEntry.mParent),
    506      mID(aEntry.mID),
    507      mBCHistoryLength(aEntry.mBCHistoryLength) {
    508  MOZ_ASSERT(mozilla::SessionHistoryInParent());
    509 }
    510 
    511 SessionHistoryEntry::~SessionHistoryEntry() {
    512  // Null out the mParent pointers on all our kids.
    513  for (nsISHEntry* entry : mChildren) {
    514    if (entry) {
    515      entry->SetParent(nullptr);
    516    }
    517  }
    518 
    519  if (sLoadIdToEntry) {
    520    sLoadIdToEntry->RemoveIf(
    521        [this](auto& aIter) { return aIter.Data().mEntry == this; });
    522    if (sLoadIdToEntry->IsEmpty()) {
    523      delete sLoadIdToEntry;
    524      sLoadIdToEntry = nullptr;
    525    }
    526  }
    527 }
    528 
    529 NS_IMPL_ISUPPORTS(SessionHistoryEntry, nsISHEntry, SessionHistoryEntry,
    530                  nsISupportsWeakReference)
    531 
    532 NS_IMETHODIMP
    533 SessionHistoryEntry::GetURI(nsIURI** aURI) {
    534  nsCOMPtr<nsIURI> uri = mInfo->mURI;
    535  uri.forget(aURI);
    536  return NS_OK;
    537 }
    538 
    539 NS_IMETHODIMP
    540 SessionHistoryEntry::SetURI(nsIURI* aURI) {
    541  mInfo->mURI = aURI;
    542  return NS_OK;
    543 }
    544 
    545 NS_IMETHODIMP
    546 SessionHistoryEntry::GetOriginalURI(nsIURI** aOriginalURI) {
    547  nsCOMPtr<nsIURI> originalURI = mInfo->mOriginalURI;
    548  originalURI.forget(aOriginalURI);
    549  return NS_OK;
    550 }
    551 
    552 NS_IMETHODIMP
    553 SessionHistoryEntry::SetOriginalURI(nsIURI* aOriginalURI) {
    554  mInfo->mOriginalURI = aOriginalURI;
    555  return NS_OK;
    556 }
    557 
    558 NS_IMETHODIMP
    559 SessionHistoryEntry::GetResultPrincipalURI(nsIURI** aResultPrincipalURI) {
    560  nsCOMPtr<nsIURI> resultPrincipalURI = mInfo->mResultPrincipalURI;
    561  resultPrincipalURI.forget(aResultPrincipalURI);
    562  return NS_OK;
    563 }
    564 
    565 NS_IMETHODIMP
    566 SessionHistoryEntry::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
    567  mInfo->mResultPrincipalURI = aResultPrincipalURI;
    568  return NS_OK;
    569 }
    570 
    571 NS_IMETHODIMP
    572 SessionHistoryEntry::GetUnstrippedURI(nsIURI** aUnstrippedURI) {
    573  nsCOMPtr<nsIURI> unstrippedURI = mInfo->mUnstrippedURI;
    574  unstrippedURI.forget(aUnstrippedURI);
    575  return NS_OK;
    576 }
    577 
    578 NS_IMETHODIMP
    579 SessionHistoryEntry::SetUnstrippedURI(nsIURI* aUnstrippedURI) {
    580  mInfo->mUnstrippedURI = aUnstrippedURI;
    581  return NS_OK;
    582 }
    583 
    584 NS_IMETHODIMP
    585 SessionHistoryEntry::GetLoadReplace(bool* aLoadReplace) {
    586  *aLoadReplace = mInfo->mLoadReplace;
    587  return NS_OK;
    588 }
    589 
    590 NS_IMETHODIMP
    591 SessionHistoryEntry::SetLoadReplace(bool aLoadReplace) {
    592  mInfo->mLoadReplace = aLoadReplace;
    593  return NS_OK;
    594 }
    595 
    596 NS_IMETHODIMP
    597 SessionHistoryEntry::GetTitle(nsAString& aTitle) {
    598  aTitle = mInfo->mTitle;
    599  return NS_OK;
    600 }
    601 
    602 NS_IMETHODIMP
    603 SessionHistoryEntry::SetTitle(const nsAString& aTitle) {
    604  mInfo->SetTitle(aTitle);
    605  return NS_OK;
    606 }
    607 
    608 NS_IMETHODIMP
    609 SessionHistoryEntry::GetName(nsAString& aName) {
    610  aName = mInfo->mName;
    611  return NS_OK;
    612 }
    613 
    614 NS_IMETHODIMP
    615 SessionHistoryEntry::SetName(const nsAString& aName) {
    616  mInfo->mName = aName;
    617  return NS_OK;
    618 }
    619 
    620 NS_IMETHODIMP
    621 SessionHistoryEntry::GetIsSubFrame(bool* aIsSubFrame) {
    622  *aIsSubFrame = SharedInfo()->mIsFrameNavigation;
    623  return NS_OK;
    624 }
    625 
    626 NS_IMETHODIMP
    627 SessionHistoryEntry::SetIsSubFrame(bool aIsSubFrame) {
    628  SharedInfo()->mIsFrameNavigation = aIsSubFrame;
    629  return NS_OK;
    630 }
    631 
    632 NS_IMETHODIMP
    633 SessionHistoryEntry::GetHasUserInteraction(bool* aFlag) {
    634  // The back button and menulist deal with root/top-level
    635  // session history entries, thus we annotate only the root entry.
    636  if (!mParent) {
    637    *aFlag = mInfo->mHasUserInteraction;
    638  } else {
    639    nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
    640    root->GetHasUserInteraction(aFlag);
    641  }
    642  return NS_OK;
    643 }
    644 
    645 NS_IMETHODIMP
    646 SessionHistoryEntry::SetHasUserInteraction(bool aFlag) {
    647  // The back button and menulist deal with root/top-level
    648  // session history entries, thus we annotate only the root entry.
    649  if (!mParent) {
    650    mInfo->mHasUserInteraction = aFlag;
    651  } else {
    652    nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
    653    root->SetHasUserInteraction(aFlag);
    654  }
    655  return NS_OK;
    656 }
    657 
    658 NS_IMETHODIMP
    659 SessionHistoryEntry::GetHasUserActivation(bool* aFlag) {
    660  *aFlag = mInfo->mHasUserActivation;
    661  return NS_OK;
    662 }
    663 
    664 NS_IMETHODIMP
    665 SessionHistoryEntry::SetHasUserActivation(bool aFlag) {
    666  mInfo->mHasUserActivation = aFlag;
    667  return NS_OK;
    668 }
    669 
    670 NS_IMETHODIMP
    671 SessionHistoryEntry::GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) {
    672  nsCOMPtr<nsIReferrerInfo> referrerInfo = mInfo->mReferrerInfo;
    673  referrerInfo.forget(aReferrerInfo);
    674  return NS_OK;
    675 }
    676 
    677 NS_IMETHODIMP
    678 SessionHistoryEntry::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
    679  mInfo->mReferrerInfo = aReferrerInfo;
    680  return NS_OK;
    681 }
    682 
    683 NS_IMETHODIMP
    684 SessionHistoryEntry::GetDocumentViewer(nsIDocumentViewer** aDocumentViewer) {
    685  *aDocumentViewer = nullptr;
    686  return NS_OK;
    687 }
    688 
    689 NS_IMETHODIMP
    690 SessionHistoryEntry::SetDocumentViewer(nsIDocumentViewer* aDocumentViewer) {
    691  MOZ_CRASH("This lives in the child process");
    692  return NS_ERROR_FAILURE;
    693 }
    694 
    695 NS_IMETHODIMP
    696 SessionHistoryEntry::GetIsInBFCache(bool* aResult) {
    697  *aResult = !!SharedInfo()->mFrameLoader;
    698  return NS_OK;
    699 }
    700 
    701 NS_IMETHODIMP
    702 SessionHistoryEntry::GetSticky(bool* aSticky) {
    703  *aSticky = SharedInfo()->mSticky;
    704  return NS_OK;
    705 }
    706 
    707 NS_IMETHODIMP
    708 SessionHistoryEntry::SetSticky(bool aSticky) {
    709  SharedInfo()->mSticky = aSticky;
    710  return NS_OK;
    711 }
    712 
    713 NS_IMETHODIMP
    714 SessionHistoryEntry::GetWindowState(nsISupports** aWindowState) {
    715  MOZ_CRASH("This lives in the child process");
    716  return NS_ERROR_FAILURE;
    717 }
    718 
    719 NS_IMETHODIMP
    720 SessionHistoryEntry::SetWindowState(nsISupports* aWindowState) {
    721  MOZ_CRASH("This lives in the child process");
    722  return NS_ERROR_FAILURE;
    723 }
    724 
    725 NS_IMETHODIMP
    726 SessionHistoryEntry::GetRefreshURIList(nsIMutableArray** aRefreshURIList) {
    727  MOZ_CRASH("This lives in the child process");
    728  return NS_ERROR_FAILURE;
    729 }
    730 
    731 NS_IMETHODIMP
    732 SessionHistoryEntry::SetRefreshURIList(nsIMutableArray* aRefreshURIList) {
    733  MOZ_CRASH("This lives in the child process");
    734  return NS_ERROR_FAILURE;
    735 }
    736 
    737 NS_IMETHODIMP
    738 SessionHistoryEntry::GetPostData(nsIInputStream** aPostData) {
    739  *aPostData = mInfo->GetPostData().take();
    740  return NS_OK;
    741 }
    742 
    743 NS_IMETHODIMP
    744 SessionHistoryEntry::SetPostData(nsIInputStream* aPostData) {
    745  mInfo->SetPostData(aPostData);
    746  return NS_OK;
    747 }
    748 
    749 NS_IMETHODIMP
    750 SessionHistoryEntry::GetHasPostData(bool* aResult) {
    751  *aResult = mInfo->HasPostData();
    752  return NS_OK;
    753 }
    754 
    755 NS_IMETHODIMP
    756 SessionHistoryEntry::GetLayoutHistoryState(
    757    nsILayoutHistoryState** aLayoutHistoryState) {
    758  nsCOMPtr<nsILayoutHistoryState> layoutHistoryState =
    759      SharedInfo()->mLayoutHistoryState;
    760  layoutHistoryState.forget(aLayoutHistoryState);
    761  return NS_OK;
    762 }
    763 
    764 NS_IMETHODIMP
    765 SessionHistoryEntry::SetLayoutHistoryState(
    766    nsILayoutHistoryState* aLayoutHistoryState) {
    767  SharedInfo()->mLayoutHistoryState = aLayoutHistoryState;
    768  if (SharedInfo()->mLayoutHistoryState) {
    769    SharedInfo()->mLayoutHistoryState->SetScrollPositionOnly(
    770        !SharedInfo()->mSaveLayoutState);
    771  }
    772  return NS_OK;
    773 }
    774 
    775 NS_IMETHODIMP
    776 SessionHistoryEntry::GetParent(nsISHEntry** aParent) {
    777  nsCOMPtr<nsISHEntry> parent = do_QueryReferent(mParent);
    778  parent.forget(aParent);
    779  return NS_OK;
    780 }
    781 
    782 NS_IMETHODIMP
    783 SessionHistoryEntry::SetParent(nsISHEntry* aParent) {
    784  mParent = do_GetWeakReference(aParent);
    785  return NS_OK;
    786 }
    787 
    788 NS_IMETHODIMP
    789 SessionHistoryEntry::GetLoadType(uint32_t* aLoadType) {
    790  *aLoadType = mInfo->mLoadType;
    791  return NS_OK;
    792 }
    793 
    794 NS_IMETHODIMP
    795 SessionHistoryEntry::SetLoadType(uint32_t aLoadType) {
    796  mInfo->mLoadType = aLoadType;
    797  return NS_OK;
    798 }
    799 
    800 NS_IMETHODIMP
    801 SessionHistoryEntry::GetID(uint32_t* aID) {
    802  *aID = mID;
    803  return NS_OK;
    804 }
    805 
    806 NS_IMETHODIMP
    807 SessionHistoryEntry::SetID(uint32_t aID) {
    808  mID = aID;
    809  return NS_OK;
    810 }
    811 
    812 NS_IMETHODIMP
    813 SessionHistoryEntry::GetCacheKey(uint32_t* aCacheKey) {
    814  *aCacheKey = SharedInfo()->mCacheKey;
    815  return NS_OK;
    816 }
    817 
    818 NS_IMETHODIMP
    819 SessionHistoryEntry::SetCacheKey(uint32_t aCacheKey) {
    820  SharedInfo()->mCacheKey = aCacheKey;
    821  return NS_OK;
    822 }
    823 
    824 NS_IMETHODIMP
    825 SessionHistoryEntry::GetSaveLayoutStateFlag(bool* aSaveLayoutStateFlag) {
    826  *aSaveLayoutStateFlag = SharedInfo()->mSaveLayoutState;
    827  return NS_OK;
    828 }
    829 
    830 NS_IMETHODIMP
    831 SessionHistoryEntry::SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag) {
    832  SharedInfo()->mSaveLayoutState = aSaveLayoutStateFlag;
    833  return NS_OK;
    834 }
    835 
    836 NS_IMETHODIMP
    837 SessionHistoryEntry::GetContentType(nsACString& aContentType) {
    838  aContentType = SharedInfo()->mContentType;
    839  return NS_OK;
    840 }
    841 
    842 NS_IMETHODIMP
    843 SessionHistoryEntry::SetContentType(const nsACString& aContentType) {
    844  SharedInfo()->mContentType = aContentType;
    845  return NS_OK;
    846 }
    847 
    848 NS_IMETHODIMP
    849 SessionHistoryEntry::GetURIWasModified(bool* aURIWasModified) {
    850  *aURIWasModified = mInfo->mURIWasModified;
    851  return NS_OK;
    852 }
    853 
    854 NS_IMETHODIMP
    855 SessionHistoryEntry::SetURIWasModified(bool aURIWasModified) {
    856  mInfo->mURIWasModified = aURIWasModified;
    857  return NS_OK;
    858 }
    859 
    860 NS_IMETHODIMP
    861 SessionHistoryEntry::GetTriggeringPrincipal(
    862    nsIPrincipal** aTriggeringPrincipal) {
    863  nsCOMPtr<nsIPrincipal> triggeringPrincipal =
    864      SharedInfo()->mTriggeringPrincipal;
    865  triggeringPrincipal.forget(aTriggeringPrincipal);
    866  return NS_OK;
    867 }
    868 
    869 NS_IMETHODIMP
    870 SessionHistoryEntry::SetTriggeringPrincipal(
    871    nsIPrincipal* aTriggeringPrincipal) {
    872  SharedInfo()->mTriggeringPrincipal = aTriggeringPrincipal;
    873  return NS_OK;
    874 }
    875 
    876 NS_IMETHODIMP
    877 SessionHistoryEntry::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
    878  nsCOMPtr<nsIPrincipal> principalToInherit = SharedInfo()->mPrincipalToInherit;
    879  principalToInherit.forget(aPrincipalToInherit);
    880  return NS_OK;
    881 }
    882 
    883 NS_IMETHODIMP
    884 SessionHistoryEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
    885  SharedInfo()->mPrincipalToInherit = aPrincipalToInherit;
    886  return NS_OK;
    887 }
    888 
    889 NS_IMETHODIMP
    890 SessionHistoryEntry::GetPartitionedPrincipalToInherit(
    891    nsIPrincipal** aPartitionedPrincipalToInherit) {
    892  nsCOMPtr<nsIPrincipal> partitionedPrincipalToInherit =
    893      SharedInfo()->mPartitionedPrincipalToInherit;
    894  partitionedPrincipalToInherit.forget(aPartitionedPrincipalToInherit);
    895  return NS_OK;
    896 }
    897 
    898 NS_IMETHODIMP
    899 SessionHistoryEntry::SetPartitionedPrincipalToInherit(
    900    nsIPrincipal* aPartitionedPrincipalToInherit) {
    901  SharedInfo()->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
    902  return NS_OK;
    903 }
    904 
    905 NS_IMETHODIMP
    906 SessionHistoryEntry::GetPolicyContainer(nsIPolicyContainer** aPolicyContainer) {
    907  nsCOMPtr<nsIPolicyContainer> policyContainer = SharedInfo()->mPolicyContainer;
    908  policyContainer.forget(aPolicyContainer);
    909  return NS_OK;
    910 }
    911 
    912 NS_IMETHODIMP
    913 SessionHistoryEntry::SetPolicyContainer(nsIPolicyContainer* aPolicyContainer) {
    914  nsCOMPtr<nsIURI> uri = mInfo->mURI;
    915  if (CSP_ShouldURIInheritCSP(uri)) {
    916    SharedInfo()->mPolicyContainer = aPolicyContainer;
    917  }
    918  return NS_OK;
    919 }
    920 
    921 NS_IMETHODIMP
    922 SessionHistoryEntry::GetStateData(nsIStructuredCloneContainer** aStateData) {
    923  RefPtr<nsStructuredCloneContainer> stateData = mInfo->mStateData;
    924  stateData.forget(aStateData);
    925  return NS_OK;
    926 }
    927 
    928 NS_IMETHODIMP
    929 SessionHistoryEntry::SetStateData(nsIStructuredCloneContainer* aStateData) {
    930  mInfo->mStateData = static_cast<nsStructuredCloneContainer*>(aStateData);
    931  return NS_OK;
    932 }
    933 
    934 const nsID& SessionHistoryEntry::DocshellID() const {
    935  return SharedInfo()->mDocShellID;
    936 }
    937 
    938 NS_IMETHODIMP
    939 SessionHistoryEntry::GetDocshellID(nsID& aDocshellID) {
    940  aDocshellID = DocshellID();
    941  return NS_OK;
    942 }
    943 
    944 NS_IMETHODIMP
    945 SessionHistoryEntry::SetDocshellID(const nsID& aDocshellID) {
    946  SharedInfo()->mDocShellID = aDocshellID;
    947  return NS_OK;
    948 }
    949 
    950 NS_IMETHODIMP
    951 SessionHistoryEntry::GetNavigationKey(nsID& aNavigationKey) {
    952  aNavigationKey = mInfo->NavigationKey();
    953  return NS_OK;
    954 }
    955 
    956 NS_IMETHODIMP
    957 SessionHistoryEntry::SetNavigationKey(const nsID& aNavigationKey) {
    958  mInfo->mNavigationKey = aNavigationKey;
    959  return NS_OK;
    960 }
    961 
    962 NS_IMETHODIMP
    963 SessionHistoryEntry::GetNavigationId(nsID& aNavigationId) {
    964  aNavigationId = mInfo->NavigationId();
    965  return NS_OK;
    966 }
    967 
    968 NS_IMETHODIMP
    969 SessionHistoryEntry::SetNavigationId(const nsID& aNavigationId) {
    970  mInfo->mNavigationId = aNavigationId;
    971  return NS_OK;
    972 }
    973 
    974 NS_IMETHODIMP
    975 SessionHistoryEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry) {
    976  *aIsSrcdocEntry = mInfo->mSrcdocData.isSome();
    977  return NS_OK;
    978 }
    979 
    980 NS_IMETHODIMP
    981 SessionHistoryEntry::GetSrcdocData(nsAString& aSrcdocData) {
    982  aSrcdocData = mInfo->mSrcdocData.valueOr(EmptyString());
    983  return NS_OK;
    984 }
    985 
    986 NS_IMETHODIMP
    987 SessionHistoryEntry::SetSrcdocData(const nsAString& aSrcdocData) {
    988  mInfo->mSrcdocData = Some(nsString(aSrcdocData));
    989  return NS_OK;
    990 }
    991 
    992 NS_IMETHODIMP
    993 SessionHistoryEntry::GetBaseURI(nsIURI** aBaseURI) {
    994  nsCOMPtr<nsIURI> baseURI = mInfo->mBaseURI;
    995  baseURI.forget(aBaseURI);
    996  return NS_OK;
    997 }
    998 
    999 NS_IMETHODIMP
   1000 SessionHistoryEntry::SetBaseURI(nsIURI* aBaseURI) {
   1001  mInfo->mBaseURI = aBaseURI;
   1002  return NS_OK;
   1003 }
   1004 
   1005 NS_IMETHODIMP
   1006 SessionHistoryEntry::GetScrollRestorationIsManual(
   1007    bool* aScrollRestorationIsManual) {
   1008  *aScrollRestorationIsManual = mInfo->mScrollRestorationIsManual;
   1009  return NS_OK;
   1010 }
   1011 
   1012 NS_IMETHODIMP
   1013 SessionHistoryEntry::SetScrollRestorationIsManual(
   1014    bool aScrollRestorationIsManual) {
   1015  mInfo->mScrollRestorationIsManual = aScrollRestorationIsManual;
   1016  return NS_OK;
   1017 }
   1018 
   1019 NS_IMETHODIMP
   1020 SessionHistoryEntry::GetLoadedInThisProcess(bool* aLoadedInThisProcess) {
   1021  // FIXME
   1022  //*aLoadedInThisProcess = mInfo->mLoadedInThisProcess;
   1023  return NS_OK;
   1024 }
   1025 
   1026 NS_IMETHODIMP
   1027 SessionHistoryEntry::GetShistory(nsISHistory** aShistory) {
   1028  nsCOMPtr<nsISHistory> sHistory = do_QueryReferent(SharedInfo()->mSHistory);
   1029  sHistory.forget(aShistory);
   1030  return NS_OK;
   1031 }
   1032 
   1033 NS_IMETHODIMP
   1034 SessionHistoryEntry::SetShistory(nsISHistory* aShistory) {
   1035  nsWeakPtr shistory = do_GetWeakReference(aShistory);
   1036  // mSHistory can not be changed once it's set
   1037  MOZ_ASSERT(!SharedInfo()->mSHistory || (SharedInfo()->mSHistory == shistory));
   1038  SharedInfo()->mSHistory = shistory;
   1039  return NS_OK;
   1040 }
   1041 
   1042 NS_IMETHODIMP
   1043 SessionHistoryEntry::GetLastTouched(uint32_t* aLastTouched) {
   1044  *aLastTouched = SharedInfo()->mLastTouched;
   1045  return NS_OK;
   1046 }
   1047 
   1048 NS_IMETHODIMP
   1049 SessionHistoryEntry::SetLastTouched(uint32_t aLastTouched) {
   1050  SharedInfo()->mLastTouched = aLastTouched;
   1051  return NS_OK;
   1052 }
   1053 
   1054 NS_IMETHODIMP
   1055 SessionHistoryEntry::GetChildCount(int32_t* aChildCount) {
   1056  *aChildCount = mChildren.Length();
   1057  return NS_OK;
   1058 }
   1059 
   1060 NS_IMETHODIMP
   1061 SessionHistoryEntry::IsTransient(bool* aIsTransient) {
   1062  *aIsTransient = mInfo->IsTransient();
   1063  return NS_OK;
   1064 }
   1065 
   1066 NS_IMETHODIMP
   1067 SessionHistoryEntry::SetTransient() {
   1068  mInfo->SetTransient();
   1069  return NS_OK;
   1070 }
   1071 
   1072 NS_IMETHODIMP
   1073 SessionHistoryEntry::GetScrollPosition(int32_t* aX, int32_t* aY) {
   1074  *aX = mInfo->mScrollPositionX;
   1075  *aY = mInfo->mScrollPositionY;
   1076  return NS_OK;
   1077 }
   1078 
   1079 NS_IMETHODIMP
   1080 SessionHistoryEntry::SetScrollPosition(int32_t aX, int32_t aY) {
   1081  mInfo->mScrollPositionX = aX;
   1082  mInfo->mScrollPositionY = aY;
   1083  return NS_OK;
   1084 }
   1085 
   1086 NS_IMETHODIMP_(void)
   1087 SessionHistoryEntry::GetViewerBounds(nsIntRect& bounds) {
   1088  bounds = SharedInfo()->mViewerBounds;
   1089 }
   1090 
   1091 NS_IMETHODIMP_(void)
   1092 SessionHistoryEntry::SetViewerBounds(const nsIntRect& bounds) {
   1093  SharedInfo()->mViewerBounds = bounds;
   1094 }
   1095 
   1096 NS_IMETHODIMP_(void)
   1097 SessionHistoryEntry::AddChildShell(nsIDocShellTreeItem* shell) {
   1098  MOZ_CRASH("This lives in the child process");
   1099 }
   1100 
   1101 NS_IMETHODIMP
   1102 SessionHistoryEntry::ChildShellAt(int32_t index,
   1103                                  nsIDocShellTreeItem** _retval) {
   1104  MOZ_CRASH("This lives in the child process");
   1105  return NS_ERROR_FAILURE;
   1106 }
   1107 
   1108 NS_IMETHODIMP_(void)
   1109 SessionHistoryEntry::ClearChildShells() {
   1110  MOZ_CRASH("This lives in the child process");
   1111 }
   1112 
   1113 NS_IMETHODIMP_(void)
   1114 SessionHistoryEntry::SyncPresentationState() {
   1115  MOZ_CRASH("This lives in the child process");
   1116 }
   1117 
   1118 NS_IMETHODIMP
   1119 SessionHistoryEntry::InitLayoutHistoryState(
   1120    nsILayoutHistoryState** aLayoutHistoryState) {
   1121  if (!SharedInfo()->mLayoutHistoryState) {
   1122    nsCOMPtr<nsILayoutHistoryState> historyState;
   1123    historyState = NS_NewLayoutHistoryState();
   1124    SetLayoutHistoryState(historyState);
   1125  }
   1126 
   1127  return GetLayoutHistoryState(aLayoutHistoryState);
   1128 }
   1129 
   1130 NS_IMETHODIMP
   1131 SessionHistoryEntry::Create(
   1132    nsIURI* aURI, const nsAString& aTitle, nsIInputStream* aInputStream,
   1133    uint32_t aCacheKey, const nsACString& aContentType,
   1134    nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
   1135    nsIPrincipal* aPartitionedPrincipalToInherit,
   1136    nsIPolicyContainer* aPolicyContainer, const nsID& aDocshellID,
   1137    bool aDynamicCreation, nsIURI* aOriginalURI, nsIURI* aResultPrincipalURI,
   1138    nsIURI* aUnstrippedURI, bool aLoadReplace, nsIReferrerInfo* aReferrerInfo,
   1139    const nsAString& aSrcdoc, bool aSrcdocEntry, nsIURI* aBaseURI,
   1140    bool aSaveLayoutState, bool aExpired, bool aUserActivation) {
   1141  MOZ_CRASH("Might need to implement this");
   1142  return NS_ERROR_NOT_IMPLEMENTED;
   1143 }
   1144 
   1145 NS_IMETHODIMP
   1146 SessionHistoryEntry::Clone(nsISHEntry** aEntry) {
   1147  RefPtr<SessionHistoryEntry> entry = new SessionHistoryEntry(*this);
   1148 
   1149  // These are not copied for some reason, we're not sure why.
   1150  entry->mInfo->mLoadType = 0;
   1151  entry->mInfo->mScrollPositionX = 0;
   1152  entry->mInfo->mScrollPositionY = 0;
   1153  entry->mInfo->mScrollRestorationIsManual = false;
   1154 
   1155  entry->mInfo->mHasUserInteraction = false;
   1156 
   1157  entry.forget(aEntry);
   1158 
   1159  return NS_OK;
   1160 }
   1161 
   1162 NS_IMETHODIMP_(nsDocShellEditorData*)
   1163 SessionHistoryEntry::ForgetEditorData() {
   1164  MOZ_CRASH("This lives in the child process");
   1165  return nullptr;
   1166 }
   1167 
   1168 NS_IMETHODIMP_(void)
   1169 SessionHistoryEntry::SetEditorData(nsDocShellEditorData* aData) {
   1170  NS_WARNING("This lives in the child process");
   1171 }
   1172 
   1173 NS_IMETHODIMP_(bool)
   1174 SessionHistoryEntry::HasDetachedEditor() {
   1175  NS_WARNING("This lives in the child process");
   1176  return false;
   1177 }
   1178 
   1179 NS_IMETHODIMP_(bool)
   1180 SessionHistoryEntry::IsDynamicallyAdded() {
   1181  return SharedInfo()->mDynamicallyCreated;
   1182 }
   1183 
   1184 void SessionHistoryEntry::SetWireframe(const Maybe<Wireframe>& aWireframe) {
   1185  mWireframe = aWireframe;
   1186 }
   1187 
   1188 void SessionHistoryEntry::SetIsDynamicallyAdded(bool aDynamic) {
   1189  MOZ_ASSERT_IF(SharedInfo()->mDynamicallyCreated, aDynamic);
   1190  SharedInfo()->mDynamicallyCreated = aDynamic;
   1191 }
   1192 
   1193 NS_IMETHODIMP
   1194 SessionHistoryEntry::HasDynamicallyAddedChild(bool* aHasDynamicallyAddedChild) {
   1195  for (const auto& child : mChildren) {
   1196    if (child && child->IsDynamicallyAdded()) {
   1197      *aHasDynamicallyAddedChild = true;
   1198      return NS_OK;
   1199    }
   1200  }
   1201  *aHasDynamicallyAddedChild = false;
   1202  return NS_OK;
   1203 }
   1204 
   1205 NS_IMETHODIMP_(bool)
   1206 SessionHistoryEntry::HasBFCacheEntry(SHEntrySharedParentState* aEntry) {
   1207  return SharedInfo() == aEntry;
   1208 }
   1209 
   1210 NS_IMETHODIMP
   1211 SessionHistoryEntry::AdoptBFCacheEntry(nsISHEntry* aEntry) {
   1212  nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(aEntry);
   1213  NS_ENSURE_STATE(she && she->mInfo->mSharedState.Get());
   1214 
   1215  mInfo->mSharedState =
   1216      static_cast<SessionHistoryEntry*>(aEntry)->mInfo->mSharedState;
   1217 
   1218  return NS_OK;
   1219 }
   1220 
   1221 NS_IMETHODIMP
   1222 SessionHistoryEntry::AbandonBFCacheEntry() {
   1223  MOZ_CRASH("This lives in the child process");
   1224  return NS_ERROR_FAILURE;
   1225 }
   1226 
   1227 NS_IMETHODIMP
   1228 SessionHistoryEntry::SharesDocumentWith(nsISHEntry* aEntry,
   1229                                        bool* aSharesDocumentWith) {
   1230  SessionHistoryEntry* entry = static_cast<SessionHistoryEntry*>(aEntry);
   1231 
   1232  MOZ_ASSERT_IF(entry->SharedInfo() != SharedInfo(),
   1233                entry->SharedInfo()->GetId() != SharedInfo()->GetId());
   1234 
   1235  *aSharesDocumentWith = entry->SharedInfo() == SharedInfo();
   1236  return NS_OK;
   1237 }
   1238 
   1239 NS_IMETHODIMP
   1240 SessionHistoryEntry::SetLoadTypeAsHistory() {
   1241  mInfo->mLoadType = LOAD_HISTORY;
   1242  return NS_OK;
   1243 }
   1244 
   1245 NS_IMETHODIMP
   1246 SessionHistoryEntry::AddChild(nsISHEntry* aChild, int32_t aOffset,
   1247                              bool aUseRemoteSubframes) {
   1248  nsCOMPtr<SessionHistoryEntry> child = do_QueryInterface(aChild);
   1249  MOZ_ASSERT_IF(aChild, child);
   1250  AddChild(child, aOffset, aUseRemoteSubframes);
   1251 
   1252  return NS_OK;
   1253 }
   1254 
   1255 void SessionHistoryEntry::AddChild(SessionHistoryEntry* aChild, int32_t aOffset,
   1256                                   bool aUseRemoteSubframes) {
   1257  if (aChild) {
   1258    aChild->SetParent(this);
   1259  }
   1260 
   1261  if (aOffset < 0) {
   1262    mChildren.AppendElement(aChild);
   1263    return;
   1264  }
   1265 
   1266  //
   1267  // Bug 52670: Ensure children are added in order.
   1268  //
   1269  //  Later frames in the child list may load faster and get appended
   1270  //  before earlier frames, causing session history to be scrambled.
   1271  //  By growing the list here, they are added to the right position.
   1272 
   1273  int32_t length = mChildren.Length();
   1274 
   1275  //  Assert that aOffset will not be so high as to grow us a lot.
   1276  NS_ASSERTION(aOffset < length + 1023, "Large frames array!\n");
   1277 
   1278  // If the new child is dynamically added, try to add it to aOffset, but if
   1279  // there are non-dynamically added children, the child must be after those.
   1280  if (aChild && aChild->IsDynamicallyAdded()) {
   1281    int32_t lastNonDyn = aOffset - 1;
   1282    for (int32_t i = aOffset; i < length; ++i) {
   1283      SessionHistoryEntry* entry = mChildren[i];
   1284      if (entry) {
   1285        if (entry->IsDynamicallyAdded()) {
   1286          break;
   1287        }
   1288 
   1289        lastNonDyn = i;
   1290      }
   1291    }
   1292 
   1293    // If aOffset is larger than Length(), we must first truncate the array.
   1294    if (aOffset > length) {
   1295      mChildren.SetLength(aOffset);
   1296    }
   1297 
   1298    mChildren.InsertElementAt(lastNonDyn + 1, aChild);
   1299 
   1300    return;
   1301  }
   1302 
   1303  // If the new child isn't dynamically added, it should be set to aOffset.
   1304  // If there are dynamically added children before that, those must be moved
   1305  // to be after aOffset.
   1306  if (length > 0) {
   1307    int32_t start = std::min(length - 1, aOffset);
   1308    int32_t dynEntryIndex = -1;
   1309    DebugOnly<SessionHistoryEntry*> dynEntry = nullptr;
   1310    for (int32_t i = start; i >= 0; --i) {
   1311      SessionHistoryEntry* entry = mChildren[i];
   1312      if (entry) {
   1313        if (!entry->IsDynamicallyAdded()) {
   1314          break;
   1315        }
   1316 
   1317        dynEntryIndex = i;
   1318        dynEntry = entry;
   1319      }
   1320    }
   1321 
   1322    if (dynEntryIndex >= 0) {
   1323      mChildren.InsertElementsAt(dynEntryIndex, aOffset - dynEntryIndex + 1);
   1324      NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
   1325    }
   1326  }
   1327 
   1328  // Make sure there isn't anything at aOffset.
   1329  if ((uint32_t)aOffset < mChildren.Length()) {
   1330    SessionHistoryEntry* oldChild = mChildren[aOffset];
   1331    if (oldChild && oldChild != aChild) {
   1332      // Under Fission, this can happen when a network-created iframe starts
   1333      // out in-process, moves out-of-process, and then switches back. At that
   1334      // point, we'll create a new network-created DocShell at the same index
   1335      // where we already have an entry for the original network-created
   1336      // DocShell.
   1337      //
   1338      // This should ideally stop being an issue once the Fission-aware
   1339      // session history rewrite is complete.
   1340      NS_ASSERTION(
   1341          aUseRemoteSubframes || NS_IsAboutBlank(oldChild->Info().GetURI()),
   1342          "Adding a child where we already have a child? This may misbehave");
   1343      oldChild->SetParent(nullptr);
   1344    }
   1345  } else {
   1346    mChildren.SetLength(aOffset + 1);
   1347  }
   1348 
   1349  mChildren.ReplaceElementAt(aOffset, aChild);
   1350 }
   1351 
   1352 NS_IMETHODIMP
   1353 SessionHistoryEntry::RemoveChild(nsISHEntry* aChild) {
   1354  NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
   1355 
   1356  nsCOMPtr<SessionHistoryEntry> child = do_QueryInterface(aChild);
   1357  MOZ_ASSERT(child);
   1358  RemoveChild(child);
   1359 
   1360  return NS_OK;
   1361 }
   1362 
   1363 void SessionHistoryEntry::RemoveChild(SessionHistoryEntry* aChild) {
   1364  bool childRemoved = false;
   1365  if (aChild->IsDynamicallyAdded()) {
   1366    childRemoved = mChildren.RemoveElement(aChild);
   1367  } else {
   1368    int32_t index = mChildren.IndexOf(aChild);
   1369    if (index >= 0) {
   1370      // Other alive non-dynamic child docshells still keep mChildOffset,
   1371      // so we don't want to change the indices here.
   1372      mChildren.ReplaceElementAt(index, nullptr);
   1373      childRemoved = true;
   1374    }
   1375  }
   1376 
   1377  if (childRemoved) {
   1378    aChild->SetParent(nullptr);
   1379 
   1380    // reduce the child count, i.e. remove empty children at the end
   1381    for (int32_t i = mChildren.Length() - 1; i >= 0 && !mChildren[i]; --i) {
   1382      mChildren.RemoveElementAt(i);
   1383    }
   1384  }
   1385 }
   1386 
   1387 NS_IMETHODIMP
   1388 SessionHistoryEntry::GetChildAt(int32_t aIndex, nsISHEntry** aChild) {
   1389  nsCOMPtr<nsISHEntry> child = mChildren.SafeElementAt(aIndex);
   1390  child.forget(aChild);
   1391  return NS_OK;
   1392 }
   1393 
   1394 NS_IMETHODIMP_(void)
   1395 SessionHistoryEntry::GetChildSHEntryIfHasNoDynamicallyAddedChild(
   1396    int32_t aChildOffset, nsISHEntry** aChild) {
   1397  *aChild = nullptr;
   1398 
   1399  bool dynamicallyAddedChild = false;
   1400  HasDynamicallyAddedChild(&dynamicallyAddedChild);
   1401  if (dynamicallyAddedChild) {
   1402    return;
   1403  }
   1404 
   1405  // If the user did a shift-reload on this frameset page,
   1406  // we don't want to load the subframes from history.
   1407  if (IsForceReloadType(mInfo->mLoadType) || mInfo->mLoadType == LOAD_REFRESH) {
   1408    return;
   1409  }
   1410 
   1411  /* Before looking for the subframe's url, check
   1412   * the expiration status of the parent. If the parent
   1413   * has expired from cache, then subframes will not be
   1414   * loaded from history in certain situations.
   1415   * If the user pressed reload and the parent frame has expired
   1416   *  from cache, we do not want to load the child frame from history.
   1417   */
   1418  if (SharedInfo()->mExpired && (mInfo->mLoadType == LOAD_RELOAD_NORMAL)) {
   1419    // The parent has expired. Return null.
   1420    *aChild = nullptr;
   1421    return;
   1422  }
   1423  // Get the child subframe from session history.
   1424  GetChildAt(aChildOffset, aChild);
   1425  if (*aChild) {
   1426    // Set the parent's Load Type on the child
   1427    (*aChild)->SetLoadType(mInfo->mLoadType);
   1428  }
   1429 }
   1430 
   1431 NS_IMETHODIMP
   1432 SessionHistoryEntry::ReplaceChild(nsISHEntry* aNewChild) {
   1433  NS_ENSURE_STATE(aNewChild);
   1434 
   1435  nsCOMPtr<SessionHistoryEntry> newChild = do_QueryInterface(aNewChild);
   1436  MOZ_ASSERT(newChild);
   1437  return ReplaceChild(newChild) ? NS_OK : NS_ERROR_FAILURE;
   1438 }
   1439 
   1440 bool SessionHistoryEntry::ReplaceChild(SessionHistoryEntry* aNewChild) {
   1441  const nsID& docshellID = aNewChild->DocshellID();
   1442 
   1443  for (uint32_t i = 0; i < mChildren.Length(); ++i) {
   1444    if (mChildren[i] && docshellID == mChildren[i]->DocshellID()) {
   1445      mChildren[i]->SetParent(nullptr);
   1446      mChildren.ReplaceElementAt(i, aNewChild);
   1447      aNewChild->SetParent(this);
   1448 
   1449      return true;
   1450    }
   1451  }
   1452 
   1453  return false;
   1454 }
   1455 
   1456 NS_IMETHODIMP_(void)
   1457 SessionHistoryEntry::ClearEntry() {
   1458  int32_t childCount = GetChildCount();
   1459  // Remove all children of this entry
   1460  for (int32_t i = childCount; i > 0; --i) {
   1461    nsCOMPtr<nsISHEntry> child;
   1462    GetChildAt(i - 1, getter_AddRefs(child));
   1463    RemoveChild(child);
   1464  }
   1465 }
   1466 
   1467 NS_IMETHODIMP
   1468 SessionHistoryEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
   1469  NS_WARNING("We shouldn't be calling this!");
   1470  return NS_OK;
   1471 }
   1472 
   1473 NS_IMETHODIMP
   1474 SessionHistoryEntry::GetBfcacheID(uint64_t* aBfcacheID) {
   1475  *aBfcacheID = SharedInfo()->mId;
   1476  return NS_OK;
   1477 }
   1478 
   1479 NS_IMETHODIMP
   1480 SessionHistoryEntry::GetWireframe(JSContext* aCx,
   1481                                  JS::MutableHandle<JS::Value> aOut) {
   1482  if (mWireframe.isNothing()) {
   1483    aOut.set(JS::NullValue());
   1484  } else if (NS_WARN_IF(!mWireframe->ToObjectInternal(aCx, aOut))) {
   1485    return NS_ERROR_FAILURE;
   1486  }
   1487  return NS_OK;
   1488 }
   1489 
   1490 NS_IMETHODIMP
   1491 SessionHistoryEntry::SetWireframe(JSContext* aCx, JS::Handle<JS::Value> aArg) {
   1492  if (aArg.isNullOrUndefined()) {
   1493    mWireframe = Nothing();
   1494    return NS_OK;
   1495  }
   1496 
   1497  Wireframe wireframe;
   1498  if (aArg.isObject() && wireframe.Init(aCx, aArg)) {
   1499    mWireframe = Some(std::move(wireframe));
   1500    return NS_OK;
   1501  }
   1502 
   1503  return NS_ERROR_INVALID_ARG;
   1504 }
   1505 
   1506 NS_IMETHODIMP_(void)
   1507 SessionHistoryEntry::SyncTreesForSubframeNavigation(
   1508    nsISHEntry* aEntry, mozilla::dom::BrowsingContext* aTopBC,
   1509    mozilla::dom::BrowsingContext* aIgnoreBC) {
   1510  // XXX Keep this in sync with nsSHEntry::SyncTreesForSubframeNavigation.
   1511  //
   1512  // We need to sync up the browsing context and session history trees for
   1513  // subframe navigation.  If the load was in a subframe, we forward up to
   1514  // the top browsing context, which will then recursively sync up all browsing
   1515  // contexts to their corresponding entries in the new session history tree. If
   1516  // we don't do this, then we can cache a content viewer on the wrong cloned
   1517  // entry, and subsequently restore it at the wrong time.
   1518  nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
   1519  if (newRootEntry) {
   1520    // newRootEntry is now the new root entry.
   1521    // Find the old root entry as well.
   1522 
   1523    // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
   1524    // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
   1525    nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(this);
   1526 
   1527    if (oldRootEntry) {
   1528      nsSHistory::SwapEntriesData data = {aIgnoreBC, newRootEntry, nullptr};
   1529      nsSHistory::SetChildHistoryEntry(oldRootEntry, aTopBC, 0, &data);
   1530    }
   1531  }
   1532 }
   1533 
   1534 void SessionHistoryEntry::ReplaceWith(const SessionHistoryEntry& aSource) {
   1535  mInfo = MakeUnique<SessionHistoryInfo>(*aSource.mInfo);
   1536  mChildren.Clear();
   1537 }
   1538 
   1539 SHEntrySharedParentState* SessionHistoryEntry::SharedInfo() const {
   1540  return static_cast<SHEntrySharedParentState*>(mInfo->mSharedState.Get());
   1541 }
   1542 
   1543 void SessionHistoryEntry::SetFrameLoader(nsFrameLoader* aFrameLoader) {
   1544  MOZ_DIAGNOSTIC_ASSERT(!aFrameLoader || !SharedInfo()->mFrameLoader);
   1545  // If the pref is disabled, we still allow evicting the existing entries.
   1546  MOZ_RELEASE_ASSERT(!aFrameLoader || mozilla::BFCacheInParent());
   1547  SharedInfo()->SetFrameLoader(aFrameLoader);
   1548  if (aFrameLoader) {
   1549    if (BrowsingContext* bc = aFrameLoader->GetMaybePendingBrowsingContext()) {
   1550      if (BrowserParent* bp = bc->Canonical()->GetBrowserParent()) {
   1551        bp->VisitAll([&](BrowserParent* aBp) { aBp->Deactivated(); });
   1552      }
   1553    }
   1554 
   1555    // When a new frameloader is stored, try to evict some older
   1556    // frameloaders. Non-SHIP session history has a similar call in
   1557    // nsDocumentViewer::Show.
   1558    nsCOMPtr<nsISHistory> shistory;
   1559    GetShistory(getter_AddRefs(shistory));
   1560    if (shistory) {
   1561      int32_t index = 0;
   1562      shistory->GetIndex(&index);
   1563      shistory->EvictOutOfRangeDocumentViewers(index);
   1564    }
   1565  }
   1566 }
   1567 
   1568 nsFrameLoader* SessionHistoryEntry::GetFrameLoader() {
   1569  return SharedInfo()->mFrameLoader;
   1570 }
   1571 
   1572 void SessionHistoryEntry::SetInfo(SessionHistoryInfo* aInfo) {
   1573  // FIXME Assert that we're not changing shared state!
   1574  mInfo = MakeUnique<SessionHistoryInfo>(*aInfo);
   1575 }
   1576 
   1577 already_AddRefed<nsIURI> SessionHistoryInfo::GetURIOrInheritedForAboutBlank()
   1578    const {
   1579  if (mURI && NS_IsAboutBlankAllowQueryAndFragment(mURI)) {
   1580    auto* principal = GetPrincipalToInherit();
   1581    if (principal) {
   1582      return principal->GetURI();
   1583    }
   1584  }
   1585  return do_AddRef(mURI);
   1586 }
   1587 
   1588 already_AddRefed<nsIURI> SessionHistoryEntry::GetURIOrInheritedForAboutBlank()
   1589    const {
   1590  return mInfo->GetURIOrInheritedForAboutBlank();
   1591 }
   1592 
   1593 }  // namespace dom
   1594 }  // namespace mozilla
   1595 
   1596 namespace IPC {
   1597 
   1598 void ParamTraits<mozilla::dom::SessionHistoryInfo>::Write(
   1599    IPC::MessageWriter* aWriter,
   1600    const mozilla::dom::SessionHistoryInfo& aParam) {
   1601  nsCOMPtr<nsIInputStream> postData = aParam.GetPostData();
   1602 
   1603  mozilla::Maybe<std::tuple<uint32_t, mozilla::dom::ClonedMessageData>>
   1604      stateData;
   1605  if (aParam.mStateData) {
   1606    stateData.emplace();
   1607    // FIXME: We should fail more aggressively if this fails, as currently we'll
   1608    // just early return and the deserialization will break.
   1609    NS_ENSURE_SUCCESS_VOID(
   1610        aParam.mStateData->GetFormatVersion(&std::get<0>(*stateData)));
   1611    NS_ENSURE_TRUE_VOID(
   1612        aParam.mStateData->BuildClonedMessageData(std::get<1>(*stateData)));
   1613  }
   1614 
   1615  mozilla::Maybe<std::tuple<uint32_t, mozilla::dom::ClonedMessageData>>
   1616      navigationState;
   1617  if (aParam.mNavigationAPIState) {
   1618    navigationState.emplace();
   1619    NS_ENSURE_SUCCESS_VOID(aParam.mNavigationAPIState->GetFormatVersion(
   1620        &std::get<0>(*navigationState)));
   1621    NS_ENSURE_TRUE_VOID(aParam.mNavigationAPIState->BuildClonedMessageData(
   1622        std::get<1>(*navigationState)));
   1623  }
   1624 
   1625  WriteParam(aWriter, aParam.mURI);
   1626  WriteParam(aWriter, aParam.mOriginalURI);
   1627  WriteParam(aWriter, aParam.mResultPrincipalURI);
   1628  WriteParam(aWriter, aParam.mUnstrippedURI);
   1629  WriteParam(aWriter, aParam.mReferrerInfo);
   1630  WriteParam(aWriter, aParam.mTitle);
   1631  WriteParam(aWriter, aParam.mName);
   1632  WriteParam(aWriter, postData);
   1633  WriteParam(aWriter, aParam.mLoadType);
   1634  WriteParam(aWriter, aParam.mScrollPositionX);
   1635  WriteParam(aWriter, aParam.mScrollPositionY);
   1636  WriteParam(aWriter, stateData);
   1637  WriteParam(aWriter, aParam.mSrcdocData);
   1638  WriteParam(aWriter, aParam.mBaseURI);
   1639  WriteParam(aWriter, aParam.mNavigationKey);
   1640  WriteParam(aWriter, aParam.mNavigationId);
   1641  WriteParam(aWriter, aParam.mLoadReplace);
   1642  WriteParam(aWriter, aParam.mURIWasModified);
   1643  WriteParam(aWriter, aParam.mScrollRestorationIsManual);
   1644  WriteParam(aWriter, aParam.mTransient);
   1645  WriteParam(aWriter, aParam.mHasUserInteraction);
   1646  WriteParam(aWriter, aParam.mHasUserActivation);
   1647  WriteParam(aWriter, aParam.mSharedState.Get()->mId);
   1648  WriteParam(aWriter, aParam.mSharedState.Get()->mTriggeringPrincipal);
   1649  WriteParam(aWriter, aParam.mSharedState.Get()->mPrincipalToInherit);
   1650  WriteParam(aWriter,
   1651             aParam.mSharedState.Get()->mPartitionedPrincipalToInherit);
   1652  WriteParam(aWriter, aParam.mSharedState.Get()->mPolicyContainer);
   1653  WriteParam(aWriter, aParam.mSharedState.Get()->mContentType);
   1654  WriteParam(aWriter, aParam.mSharedState.Get()->mLayoutHistoryState);
   1655  WriteParam(aWriter, aParam.mSharedState.Get()->mCacheKey);
   1656  WriteParam(aWriter, aParam.mSharedState.Get()->mIsFrameNavigation);
   1657  WriteParam(aWriter, aParam.mSharedState.Get()->mSaveLayoutState);
   1658  WriteParam(aWriter, navigationState);
   1659 }
   1660 
   1661 bool ParamTraits<mozilla::dom::SessionHistoryInfo>::Read(
   1662    IPC::MessageReader* aReader, mozilla::dom::SessionHistoryInfo* aResult) {
   1663  mozilla::Maybe<std::tuple<uint32_t, mozilla::dom::ClonedMessageData>>
   1664      stateData;
   1665  uint64_t sharedId;
   1666  if (!ReadParam(aReader, &aResult->mURI) ||
   1667      !ReadParam(aReader, &aResult->mOriginalURI) ||
   1668      !ReadParam(aReader, &aResult->mResultPrincipalURI) ||
   1669      !ReadParam(aReader, &aResult->mUnstrippedURI) ||
   1670      !ReadParam(aReader, &aResult->mReferrerInfo) ||
   1671      !ReadParam(aReader, &aResult->mTitle) ||
   1672      !ReadParam(aReader, &aResult->mName) ||
   1673      !ReadParam(aReader, &aResult->mPostData) ||
   1674      !ReadParam(aReader, &aResult->mLoadType) ||
   1675      !ReadParam(aReader, &aResult->mScrollPositionX) ||
   1676      !ReadParam(aReader, &aResult->mScrollPositionY) ||
   1677      !ReadParam(aReader, &stateData) ||
   1678      !ReadParam(aReader, &aResult->mSrcdocData) ||
   1679      !ReadParam(aReader, &aResult->mBaseURI) ||
   1680      !ReadParam(aReader, &aResult->mNavigationKey) ||
   1681      !ReadParam(aReader, &aResult->mNavigationId) ||
   1682      !ReadParam(aReader, &aResult->mLoadReplace) ||
   1683      !ReadParam(aReader, &aResult->mURIWasModified) ||
   1684      !ReadParam(aReader, &aResult->mScrollRestorationIsManual) ||
   1685      !ReadParam(aReader, &aResult->mTransient) ||
   1686      !ReadParam(aReader, &aResult->mHasUserInteraction) ||
   1687      !ReadParam(aReader, &aResult->mHasUserActivation) ||
   1688      !ReadParam(aReader, &sharedId)) {
   1689    aReader->FatalError("Error reading fields for SessionHistoryInfo");
   1690    return false;
   1691  }
   1692 
   1693  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   1694  nsCOMPtr<nsIPrincipal> principalToInherit;
   1695  nsCOMPtr<nsIPrincipal> partitionedPrincipalToInherit;
   1696  nsCOMPtr<nsIPolicyContainer> policyContainer;
   1697  nsCString contentType;
   1698  if (!ReadParam(aReader, &triggeringPrincipal) ||
   1699      !ReadParam(aReader, &principalToInherit) ||
   1700      !ReadParam(aReader, &partitionedPrincipalToInherit) ||
   1701      !ReadParam(aReader, &policyContainer) ||
   1702      !ReadParam(aReader, &contentType)) {
   1703    aReader->FatalError("Error reading fields for SessionHistoryInfo");
   1704    return false;
   1705  }
   1706 
   1707  // We should always see a cloneable input stream passed to SessionHistoryInfo.
   1708  // This is because it will be cloneable when first read in the parent process
   1709  // from the nsHttpChannel (which forces streams to be cloneable), and future
   1710  // streams in content will be wrapped in
   1711  // nsMIMEInputStream(RemoteLazyInputStream) which is also cloneable.
   1712  if (aResult->mPostData && !NS_InputStreamIsCloneable(aResult->mPostData)) {
   1713    aReader->FatalError(
   1714        "Unexpected non-cloneable postData for SessionHistoryInfo");
   1715    return false;
   1716  }
   1717 
   1718  mozilla::dom::SHEntrySharedParentState* sharedState = nullptr;
   1719  if (XRE_IsParentProcess()) {
   1720    sharedState = mozilla::dom::SHEntrySharedParentState::Lookup(sharedId);
   1721  }
   1722 
   1723  if (sharedState) {
   1724    aResult->mSharedState.Set(sharedState);
   1725 
   1726    MOZ_ASSERT(triggeringPrincipal
   1727                   ? triggeringPrincipal->Equals(
   1728                         aResult->mSharedState.Get()->mTriggeringPrincipal)
   1729                   : !aResult->mSharedState.Get()->mTriggeringPrincipal,
   1730               "We don't expect this to change!");
   1731    MOZ_ASSERT(principalToInherit
   1732                   ? principalToInherit->Equals(
   1733                         aResult->mSharedState.Get()->mPrincipalToInherit)
   1734                   : !aResult->mSharedState.Get()->mPrincipalToInherit,
   1735               "We don't expect this to change!");
   1736    MOZ_ASSERT(
   1737        partitionedPrincipalToInherit
   1738            ? partitionedPrincipalToInherit->Equals(
   1739                  aResult->mSharedState.Get()->mPartitionedPrincipalToInherit)
   1740            : !aResult->mSharedState.Get()->mPartitionedPrincipalToInherit,
   1741        "We don't expect this to change!");
   1742 
   1743    MOZ_ASSERT(policyContainer
   1744                   ? PolicyContainer::Equals(
   1745                         PolicyContainer::Cast(policyContainer),
   1746                         PolicyContainer::Cast(
   1747                             aResult->mSharedState.Get()->mPolicyContainer))
   1748                   : !aResult->mSharedState.Get()->mPolicyContainer,
   1749               "We don't expect this to change!");
   1750    MOZ_ASSERT(contentType.Equals(aResult->mSharedState.Get()->mContentType),
   1751               "We don't expect this to change!");
   1752  } else {
   1753    aResult->mSharedState.ChangeId(sharedId);
   1754    aResult->mSharedState.Get()->mTriggeringPrincipal =
   1755        triggeringPrincipal.forget();
   1756    aResult->mSharedState.Get()->mPrincipalToInherit =
   1757        principalToInherit.forget();
   1758    aResult->mSharedState.Get()->mPartitionedPrincipalToInherit =
   1759        partitionedPrincipalToInherit.forget();
   1760    aResult->mSharedState.Get()->mPolicyContainer = policyContainer.forget();
   1761    aResult->mSharedState.Get()->mContentType = contentType;
   1762  }
   1763 
   1764  mozilla::Maybe<std::tuple<uint32_t, mozilla::dom::ClonedMessageData>>
   1765      navigationState;
   1766  if (!ReadParam(aReader, &aResult->mSharedState.Get()->mLayoutHistoryState) ||
   1767      !ReadParam(aReader, &aResult->mSharedState.Get()->mCacheKey) ||
   1768      !ReadParam(aReader, &aResult->mSharedState.Get()->mIsFrameNavigation) ||
   1769      !ReadParam(aReader, &aResult->mSharedState.Get()->mSaveLayoutState) ||
   1770      !ReadParam(aReader, &navigationState)) {
   1771    aReader->FatalError("Error reading fields for SessionHistoryInfo");
   1772    return false;
   1773  }
   1774 
   1775  if (stateData.isSome()) {
   1776    uint32_t version = std::get<0>(*stateData);
   1777    aResult->mStateData = new nsStructuredCloneContainer(version);
   1778    aResult->mStateData->StealFromClonedMessageData(std::get<1>(*stateData));
   1779  }
   1780  MOZ_ASSERT_IF(stateData.isNothing(), !aResult->mStateData);
   1781 
   1782  if (navigationState.isSome()) {
   1783    uint32_t version = std::get<0>(*navigationState);
   1784    aResult->mNavigationAPIState = new nsStructuredCloneContainer(version);
   1785    aResult->mNavigationAPIState->StealFromClonedMessageData(
   1786        std::get<1>(*navigationState));
   1787  }
   1788  MOZ_ASSERT_IF(navigationState.isNothing(), !aResult->mNavigationAPIState);
   1789 
   1790  return true;
   1791 }
   1792 
   1793 void ParamTraits<mozilla::dom::LoadingSessionHistoryInfo>::Write(
   1794    IPC::MessageWriter* aWriter,
   1795    const mozilla::dom::LoadingSessionHistoryInfo& aParam) {
   1796  WriteParam(aWriter, aParam.mInfo);
   1797  WriteParam(aWriter, aParam.mContiguousEntries);
   1798  WriteParam(aWriter, aParam.mTriggeringEntry);
   1799  WriteParam(aWriter, aParam.mTriggeringNavigationType);
   1800  WriteParam(aWriter, aParam.mLoadId);
   1801  WriteParam(aWriter, aParam.mLoadIsFromSessionHistory);
   1802  WriteParam(aWriter, aParam.mOffset);
   1803  WriteParam(aWriter, aParam.mLoadingCurrentEntry);
   1804  WriteParam(aWriter, aParam.mForceMaybeResetName);
   1805 }
   1806 
   1807 bool ParamTraits<mozilla::dom::LoadingSessionHistoryInfo>::Read(
   1808    IPC::MessageReader* aReader,
   1809    mozilla::dom::LoadingSessionHistoryInfo* aResult) {
   1810  if (!ReadParam(aReader, &aResult->mInfo) ||
   1811      !ReadParam(aReader, &aResult->mContiguousEntries) ||
   1812      !ReadParam(aReader, &aResult->mTriggeringEntry) ||
   1813      !ReadParam(aReader, &aResult->mTriggeringNavigationType) ||
   1814      !ReadParam(aReader, &aResult->mLoadId) ||
   1815      !ReadParam(aReader, &aResult->mLoadIsFromSessionHistory) ||
   1816      !ReadParam(aReader, &aResult->mOffset) ||
   1817      !ReadParam(aReader, &aResult->mLoadingCurrentEntry) ||
   1818      !ReadParam(aReader, &aResult->mForceMaybeResetName)) {
   1819    aReader->FatalError("Error reading fields for LoadingSessionHistoryInfo");
   1820    return false;
   1821  }
   1822 
   1823  return true;
   1824 }
   1825 
   1826 void ParamTraits<nsILayoutHistoryState*>::Write(IPC::MessageWriter* aWriter,
   1827                                                nsILayoutHistoryState* aParam) {
   1828  if (aParam) {
   1829    WriteParam(aWriter, true);
   1830    bool scrollPositionOnly = false;
   1831    nsTArray<nsCString> keys;
   1832    nsTArray<mozilla::PresState> states;
   1833    aParam->GetContents(&scrollPositionOnly, keys, states);
   1834    WriteParam(aWriter, scrollPositionOnly);
   1835    WriteParam(aWriter, keys);
   1836    WriteParam(aWriter, states);
   1837  } else {
   1838    WriteParam(aWriter, false);
   1839  }
   1840 }
   1841 
   1842 bool ParamTraits<nsILayoutHistoryState*>::Read(
   1843    IPC::MessageReader* aReader, RefPtr<nsILayoutHistoryState>* aResult) {
   1844  bool hasLayoutHistoryState = false;
   1845  if (!ReadParam(aReader, &hasLayoutHistoryState)) {
   1846    aReader->FatalError("Error reading fields for nsILayoutHistoryState");
   1847    return false;
   1848  }
   1849 
   1850  if (hasLayoutHistoryState) {
   1851    bool scrollPositionOnly = false;
   1852    nsTArray<nsCString> keys;
   1853    nsTArray<mozilla::PresState> states;
   1854    if (!ReadParam(aReader, &scrollPositionOnly) ||
   1855        !ReadParam(aReader, &keys) || !ReadParam(aReader, &states)) {
   1856      aReader->FatalError("Error reading fields for nsILayoutHistoryState");
   1857    }
   1858 
   1859    if (keys.Length() != states.Length()) {
   1860      aReader->FatalError("Error reading fields for nsILayoutHistoryState");
   1861      return false;
   1862    }
   1863 
   1864    *aResult = NS_NewLayoutHistoryState();
   1865    (*aResult)->SetScrollPositionOnly(scrollPositionOnly);
   1866    for (uint32_t i = 0; i < keys.Length(); ++i) {
   1867      mozilla::PresState& state = states[i];
   1868      auto newState = mozilla::MakeUnique<mozilla::PresState>(state);
   1869      (*aResult)->AddState(keys[i], std::move(newState));
   1870    }
   1871  }
   1872  return true;
   1873 }
   1874 
   1875 void ParamTraits<mozilla::dom::Wireframe>::Write(
   1876    IPC::MessageWriter* aWriter, const mozilla::dom::Wireframe& aParam) {
   1877  WriteParam(aWriter, aParam.mCanvasBackground);
   1878  WriteParam(aWriter, aParam.mRects);
   1879 }
   1880 
   1881 bool ParamTraits<mozilla::dom::Wireframe>::Read(
   1882    IPC::MessageReader* aReader, mozilla::dom::Wireframe* aResult) {
   1883  return ReadParam(aReader, &aResult->mCanvasBackground) &&
   1884         ReadParam(aReader, &aResult->mRects);
   1885 }
   1886 
   1887 // Allow sending mozilla::dom::WireframeRectType enums over IPC.
   1888 template <>
   1889 struct ParamTraits<mozilla::dom::WireframeRectType>
   1890    : public mozilla::dom::WebIDLEnumSerializer<
   1891          mozilla::dom::WireframeRectType> {};
   1892 
   1893 template <>
   1894 struct ParamTraits<mozilla::dom::WireframeTaggedRect> {
   1895  static void Write(MessageWriter* aWriter,
   1896                    const mozilla::dom::WireframeTaggedRect& aParam);
   1897  static bool Read(MessageReader* aReader,
   1898                   mozilla::dom::WireframeTaggedRect* aResult);
   1899 };
   1900 
   1901 void ParamTraits<mozilla::dom::WireframeTaggedRect>::Write(
   1902    MessageWriter* aWriter, const mozilla::dom::WireframeTaggedRect& aParam) {
   1903  WriteParam(aWriter, aParam.mColor);
   1904  WriteParam(aWriter, aParam.mType);
   1905  WriteParam(aWriter, aParam.mX);
   1906  WriteParam(aWriter, aParam.mY);
   1907  WriteParam(aWriter, aParam.mWidth);
   1908  WriteParam(aWriter, aParam.mHeight);
   1909 }
   1910 
   1911 bool ParamTraits<mozilla::dom::WireframeTaggedRect>::Read(
   1912    IPC::MessageReader* aReader, mozilla::dom::WireframeTaggedRect* aResult) {
   1913  return ReadParam(aReader, &aResult->mColor) &&
   1914         ReadParam(aReader, &aResult->mType) &&
   1915         ReadParam(aReader, &aResult->mX) && ReadParam(aReader, &aResult->mY) &&
   1916         ReadParam(aReader, &aResult->mWidth) &&
   1917         ReadParam(aReader, &aResult->mHeight);
   1918 }
   1919 }  // namespace IPC