tor-browser

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

nsSHEntry.cpp (31106B)


      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 "nsSHEntry.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "nsDocShell.h"
     12 #include "nsDocShellEditorData.h"
     13 #include "nsDocShellLoadState.h"
     14 #include "nsDocShellLoadTypes.h"
     15 #include "nsIContentSecurityPolicy.h"
     16 #include "nsIDocShellTreeItem.h"
     17 #include "nsIDocumentViewer.h"
     18 #include "nsIInputStream.h"
     19 #include "nsILayoutHistoryState.h"
     20 #include "nsIMutableArray.h"
     21 #include "nsIStructuredCloneContainer.h"
     22 #include "nsIURI.h"
     23 #include "nsSHEntryShared.h"
     24 #include "nsSHistory.h"
     25 
     26 #include "mozilla/Logging.h"
     27 #include "mozilla/dom/nsCSPUtils.h"
     28 #include "nsIReferrerInfo.h"
     29 
     30 extern mozilla::LazyLogModule gPageCacheLog;
     31 
     32 static uint32_t gEntryID = 0;
     33 
     34 nsSHEntry::nsSHEntry()
     35    : mShared(new nsSHEntryShared()),
     36      mLoadType(0),
     37      mID(++gEntryID),  // SessionStore has special handling for 0 values.
     38      mScrollPositionX(0),
     39      mScrollPositionY(0),
     40      mLoadReplace(false),
     41      mURIWasModified(false),
     42      mIsSrcdocEntry(false),
     43      mScrollRestorationIsManual(false),
     44      mLoadedInThisProcess(false),
     45      mTransient(false),
     46      mHasUserInteraction(false),
     47      mHasUserActivation(false) {}
     48 
     49 nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
     50    : mShared(aOther.mShared),
     51      mURI(aOther.mURI),
     52      mOriginalURI(aOther.mOriginalURI),
     53      mResultPrincipalURI(aOther.mResultPrincipalURI),
     54      mUnstrippedURI(aOther.mUnstrippedURI),
     55      mReferrerInfo(aOther.mReferrerInfo),
     56      mTitle(aOther.mTitle),
     57      mPostData(aOther.mPostData),
     58      mLoadType(0),  // XXX why not copy?
     59      mID(aOther.mID),
     60      mScrollPositionX(0),  // XXX why not copy?
     61      mScrollPositionY(0),  // XXX why not copy?
     62      mParent(aOther.mParent),
     63      mStateData(aOther.mStateData),
     64      mSrcdocData(aOther.mSrcdocData),
     65      mBaseURI(aOther.mBaseURI),
     66      mLoadReplace(aOther.mLoadReplace),
     67      mURIWasModified(aOther.mURIWasModified),
     68      mIsSrcdocEntry(aOther.mIsSrcdocEntry),
     69      mScrollRestorationIsManual(false),
     70      mLoadedInThisProcess(aOther.mLoadedInThisProcess),
     71      mTransient(aOther.mTransient),
     72      mHasUserInteraction(false),
     73      mHasUserActivation(aOther.mHasUserActivation) {}
     74 
     75 nsSHEntry::~nsSHEntry() {
     76  // Null out the mParent pointers on all our kids.
     77  for (nsISHEntry* entry : mChildren) {
     78    if (entry) {
     79      entry->SetParent(nullptr);
     80    }
     81  }
     82 }
     83 
     84 NS_IMPL_ISUPPORTS(nsSHEntry, nsISHEntry, nsISupportsWeakReference)
     85 
     86 NS_IMETHODIMP
     87 nsSHEntry::SetScrollPosition(int32_t aX, int32_t aY) {
     88  mScrollPositionX = aX;
     89  mScrollPositionY = aY;
     90  return NS_OK;
     91 }
     92 
     93 NS_IMETHODIMP
     94 nsSHEntry::GetScrollPosition(int32_t* aX, int32_t* aY) {
     95  *aX = mScrollPositionX;
     96  *aY = mScrollPositionY;
     97  return NS_OK;
     98 }
     99 
    100 NS_IMETHODIMP
    101 nsSHEntry::GetURIWasModified(bool* aOut) {
    102  *aOut = mURIWasModified;
    103  return NS_OK;
    104 }
    105 
    106 NS_IMETHODIMP
    107 nsSHEntry::SetURIWasModified(bool aIn) {
    108  mURIWasModified = aIn;
    109  return NS_OK;
    110 }
    111 
    112 NS_IMETHODIMP
    113 nsSHEntry::GetURI(nsIURI** aURI) {
    114  *aURI = mURI;
    115  NS_IF_ADDREF(*aURI);
    116  return NS_OK;
    117 }
    118 
    119 NS_IMETHODIMP
    120 nsSHEntry::SetURI(nsIURI* aURI) {
    121  mURI = aURI;
    122  return NS_OK;
    123 }
    124 
    125 NS_IMETHODIMP
    126 nsSHEntry::GetOriginalURI(nsIURI** aOriginalURI) {
    127  *aOriginalURI = mOriginalURI;
    128  NS_IF_ADDREF(*aOriginalURI);
    129  return NS_OK;
    130 }
    131 
    132 NS_IMETHODIMP
    133 nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI) {
    134  mOriginalURI = aOriginalURI;
    135  return NS_OK;
    136 }
    137 
    138 NS_IMETHODIMP
    139 nsSHEntry::GetResultPrincipalURI(nsIURI** aResultPrincipalURI) {
    140  *aResultPrincipalURI = mResultPrincipalURI;
    141  NS_IF_ADDREF(*aResultPrincipalURI);
    142  return NS_OK;
    143 }
    144 
    145 NS_IMETHODIMP
    146 nsSHEntry::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
    147  mResultPrincipalURI = aResultPrincipalURI;
    148  return NS_OK;
    149 }
    150 
    151 NS_IMETHODIMP
    152 nsSHEntry::GetUnstrippedURI(nsIURI** aUnstrippedURI) {
    153  *aUnstrippedURI = mUnstrippedURI;
    154  NS_IF_ADDREF(*aUnstrippedURI);
    155  return NS_OK;
    156 }
    157 
    158 NS_IMETHODIMP
    159 nsSHEntry::SetUnstrippedURI(nsIURI* aUnstrippedURI) {
    160  mUnstrippedURI = aUnstrippedURI;
    161  return NS_OK;
    162 }
    163 
    164 NS_IMETHODIMP
    165 nsSHEntry::GetLoadReplace(bool* aLoadReplace) {
    166  *aLoadReplace = mLoadReplace;
    167  return NS_OK;
    168 }
    169 
    170 NS_IMETHODIMP
    171 nsSHEntry::SetLoadReplace(bool aLoadReplace) {
    172  mLoadReplace = aLoadReplace;
    173  return NS_OK;
    174 }
    175 
    176 NS_IMETHODIMP
    177 nsSHEntry::GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) {
    178  *aReferrerInfo = mReferrerInfo;
    179  NS_IF_ADDREF(*aReferrerInfo);
    180  return NS_OK;
    181 }
    182 
    183 NS_IMETHODIMP
    184 nsSHEntry::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
    185  mReferrerInfo = aReferrerInfo;
    186  return NS_OK;
    187 }
    188 
    189 NS_IMETHODIMP
    190 nsSHEntry::SetSticky(bool aSticky) {
    191  mShared->mSticky = aSticky;
    192  return NS_OK;
    193 }
    194 
    195 NS_IMETHODIMP
    196 nsSHEntry::GetSticky(bool* aSticky) {
    197  *aSticky = mShared->mSticky;
    198  return NS_OK;
    199 }
    200 
    201 NS_IMETHODIMP
    202 nsSHEntry::GetTitle(nsAString& aTitle) {
    203  // Check for empty title...
    204  if (mTitle.IsEmpty() && mURI) {
    205    // Default title is the URL.
    206    nsAutoCString spec;
    207    if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
    208      AppendUTF8toUTF16(spec, mTitle);
    209    }
    210  }
    211 
    212  aTitle = mTitle;
    213  return NS_OK;
    214 }
    215 
    216 NS_IMETHODIMP
    217 nsSHEntry::SetTitle(const nsAString& aTitle) {
    218  mTitle = aTitle;
    219  return NS_OK;
    220 }
    221 
    222 NS_IMETHODIMP
    223 nsSHEntry::GetName(nsAString& aName) {
    224  aName = mName;
    225  return NS_OK;
    226 }
    227 
    228 NS_IMETHODIMP
    229 nsSHEntry::SetName(const nsAString& aName) {
    230  mName = aName;
    231  return NS_OK;
    232 }
    233 
    234 NS_IMETHODIMP
    235 nsSHEntry::GetPostData(nsIInputStream** aResult) {
    236  *aResult = mPostData;
    237  NS_IF_ADDREF(*aResult);
    238  return NS_OK;
    239 }
    240 
    241 NS_IMETHODIMP
    242 nsSHEntry::SetPostData(nsIInputStream* aPostData) {
    243  mPostData = aPostData;
    244  return NS_OK;
    245 }
    246 
    247 NS_IMETHODIMP
    248 nsSHEntry::GetHasPostData(bool* aResult) {
    249  *aResult = !!mPostData;
    250  return NS_OK;
    251 }
    252 
    253 NS_IMETHODIMP
    254 nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult) {
    255  *aResult = mShared->mLayoutHistoryState;
    256  NS_IF_ADDREF(*aResult);
    257  return NS_OK;
    258 }
    259 
    260 NS_IMETHODIMP
    261 nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState) {
    262  mShared->mLayoutHistoryState = aState;
    263  if (mShared->mLayoutHistoryState) {
    264    mShared->mLayoutHistoryState->SetScrollPositionOnly(
    265        !mShared->mSaveLayoutState);
    266  }
    267 
    268  return NS_OK;
    269 }
    270 
    271 NS_IMETHODIMP
    272 nsSHEntry::InitLayoutHistoryState(nsILayoutHistoryState** aState) {
    273  if (!mShared->mLayoutHistoryState) {
    274    nsCOMPtr<nsILayoutHistoryState> historyState;
    275    historyState = NS_NewLayoutHistoryState();
    276    SetLayoutHistoryState(historyState);
    277  }
    278 
    279  nsCOMPtr<nsILayoutHistoryState> state = GetLayoutHistoryState();
    280  state.forget(aState);
    281  return NS_OK;
    282 }
    283 
    284 NS_IMETHODIMP
    285 nsSHEntry::GetLoadType(uint32_t* aResult) {
    286  *aResult = mLoadType;
    287  return NS_OK;
    288 }
    289 
    290 NS_IMETHODIMP
    291 nsSHEntry::SetLoadType(uint32_t aLoadType) {
    292  mLoadType = aLoadType;
    293  return NS_OK;
    294 }
    295 
    296 NS_IMETHODIMP
    297 nsSHEntry::GetID(uint32_t* aResult) {
    298  *aResult = mID;
    299  return NS_OK;
    300 }
    301 
    302 NS_IMETHODIMP
    303 nsSHEntry::SetID(uint32_t aID) {
    304  mID = aID;
    305  return NS_OK;
    306 }
    307 
    308 NS_IMETHODIMP
    309 nsSHEntry::GetIsSubFrame(bool* aFlag) {
    310  *aFlag = mShared->mIsFrameNavigation;
    311  return NS_OK;
    312 }
    313 
    314 NS_IMETHODIMP
    315 nsSHEntry::SetIsSubFrame(bool aFlag) {
    316  mShared->mIsFrameNavigation = aFlag;
    317  return NS_OK;
    318 }
    319 
    320 NS_IMETHODIMP
    321 nsSHEntry::GetHasUserInteraction(bool* aFlag) {
    322  // The back button and menulist deal with root/top-level
    323  // session history entries, thus we annotate only the root entry.
    324  if (!mParent) {
    325    *aFlag = mHasUserInteraction;
    326  } else {
    327    nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
    328    root->GetHasUserInteraction(aFlag);
    329  }
    330  return NS_OK;
    331 }
    332 
    333 NS_IMETHODIMP
    334 nsSHEntry::SetHasUserInteraction(bool aFlag) {
    335  // The back button and menulist deal with root/top-level
    336  // session history entries, thus we annotate only the root entry.
    337  if (!mParent) {
    338    mHasUserInteraction = aFlag;
    339  } else {
    340    nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
    341    root->SetHasUserInteraction(aFlag);
    342  }
    343  return NS_OK;
    344 }
    345 
    346 NS_IMETHODIMP
    347 nsSHEntry::GetHasUserActivation(bool* aFlag) {
    348  *aFlag = mHasUserActivation;
    349  return NS_OK;
    350 }
    351 
    352 NS_IMETHODIMP
    353 nsSHEntry::SetHasUserActivation(bool aFlag) {
    354  mHasUserActivation = aFlag;
    355  return NS_OK;
    356 }
    357 
    358 NS_IMETHODIMP
    359 nsSHEntry::GetCacheKey(uint32_t* aResult) {
    360  *aResult = mShared->mCacheKey;
    361  return NS_OK;
    362 }
    363 
    364 NS_IMETHODIMP
    365 nsSHEntry::SetCacheKey(uint32_t aCacheKey) {
    366  mShared->mCacheKey = aCacheKey;
    367  return NS_OK;
    368 }
    369 
    370 NS_IMETHODIMP
    371 nsSHEntry::GetContentType(nsACString& aContentType) {
    372  aContentType = mShared->mContentType;
    373  return NS_OK;
    374 }
    375 
    376 NS_IMETHODIMP
    377 nsSHEntry::SetContentType(const nsACString& aContentType) {
    378  mShared->mContentType = aContentType;
    379  return NS_OK;
    380 }
    381 
    382 NS_IMETHODIMP
    383 nsSHEntry::Create(
    384    nsIURI* aURI, const nsAString& aTitle, nsIInputStream* aInputStream,
    385    uint32_t aCacheKey, const nsACString& aContentType,
    386    nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
    387    nsIPrincipal* aPartitionedPrincipalToInherit,
    388    nsIPolicyContainer* aPolicyContainer, const nsID& aDocShellID,
    389    bool aDynamicCreation, nsIURI* aOriginalURI, nsIURI* aResultPrincipalURI,
    390    nsIURI* aUnstrippedURI, bool aLoadReplace, nsIReferrerInfo* aReferrerInfo,
    391    const nsAString& aSrcdocData, bool aSrcdocEntry, nsIURI* aBaseURI,
    392    bool aSaveLayoutState, bool aExpired, bool aUserActivation) {
    393  MOZ_ASSERT(
    394      aTriggeringPrincipal,
    395      "need a valid triggeringPrincipal to create a session history entry");
    396 
    397  mURI = aURI;
    398  mTitle = aTitle;
    399  mPostData = aInputStream;
    400 
    401  // Set the LoadType by default to loadHistory during creation
    402  mLoadType = LOAD_HISTORY;
    403 
    404  mShared->mCacheKey = aCacheKey;
    405  mShared->mContentType = aContentType;
    406  mShared->mTriggeringPrincipal = aTriggeringPrincipal;
    407  mShared->mPrincipalToInherit = aPrincipalToInherit;
    408  mShared->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
    409  mShared->mPolicyContainer = aPolicyContainer;
    410  mShared->mDocShellID = aDocShellID;
    411  mShared->mDynamicallyCreated = aDynamicCreation;
    412 
    413  // By default all entries are set false for subframe flag.
    414  // nsDocShell::CloneAndReplace() which creates entries for
    415  // all subframe navigations, sets the flag to true.
    416  mShared->mIsFrameNavigation = false;
    417 
    418  mHasUserInteraction = false;
    419 
    420  mShared->mExpired = aExpired;
    421 
    422  mIsSrcdocEntry = aSrcdocEntry;
    423  mSrcdocData = aSrcdocData;
    424 
    425  mBaseURI = aBaseURI;
    426 
    427  mLoadedInThisProcess = true;
    428 
    429  mOriginalURI = aOriginalURI;
    430  mResultPrincipalURI = aResultPrincipalURI;
    431  mUnstrippedURI = aUnstrippedURI;
    432  mLoadReplace = aLoadReplace;
    433  mReferrerInfo = aReferrerInfo;
    434 
    435  mHasUserActivation = aUserActivation;
    436 
    437  mShared->mLayoutHistoryState = nullptr;
    438 
    439  mShared->mSaveLayoutState = aSaveLayoutState;
    440 
    441  return NS_OK;
    442 }
    443 
    444 NS_IMETHODIMP
    445 nsSHEntry::GetParent(nsISHEntry** aResult) {
    446  nsCOMPtr<nsISHEntry> parent = do_QueryReferent(mParent);
    447  parent.forget(aResult);
    448  return NS_OK;
    449 }
    450 
    451 NS_IMETHODIMP
    452 nsSHEntry::SetParent(nsISHEntry* aParent) {
    453  mParent = do_GetWeakReference(aParent);
    454  return NS_OK;
    455 }
    456 
    457 NS_IMETHODIMP_(void)
    458 nsSHEntry::SetViewerBounds(const nsIntRect& aBounds) {
    459  mShared->mViewerBounds = aBounds;
    460 }
    461 
    462 NS_IMETHODIMP_(void)
    463 nsSHEntry::GetViewerBounds(nsIntRect& aBounds) {
    464  aBounds = mShared->mViewerBounds;
    465 }
    466 
    467 NS_IMETHODIMP
    468 nsSHEntry::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal) {
    469  NS_IF_ADDREF(*aTriggeringPrincipal = mShared->mTriggeringPrincipal);
    470  return NS_OK;
    471 }
    472 
    473 NS_IMETHODIMP
    474 nsSHEntry::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal) {
    475  mShared->mTriggeringPrincipal = aTriggeringPrincipal;
    476  return NS_OK;
    477 }
    478 
    479 NS_IMETHODIMP
    480 nsSHEntry::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
    481  NS_IF_ADDREF(*aPrincipalToInherit = mShared->mPrincipalToInherit);
    482  return NS_OK;
    483 }
    484 
    485 NS_IMETHODIMP
    486 nsSHEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
    487  mShared->mPrincipalToInherit = aPrincipalToInherit;
    488  return NS_OK;
    489 }
    490 
    491 NS_IMETHODIMP
    492 nsSHEntry::GetPartitionedPrincipalToInherit(
    493    nsIPrincipal** aPartitionedPrincipalToInherit) {
    494  NS_IF_ADDREF(*aPartitionedPrincipalToInherit =
    495                   mShared->mPartitionedPrincipalToInherit);
    496  return NS_OK;
    497 }
    498 
    499 NS_IMETHODIMP
    500 nsSHEntry::SetPartitionedPrincipalToInherit(
    501    nsIPrincipal* aPartitionedPrincipalToInherit) {
    502  mShared->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
    503  return NS_OK;
    504 }
    505 
    506 NS_IMETHODIMP
    507 nsSHEntry::GetPolicyContainer(nsIPolicyContainer** aPolicyContainer) {
    508  NS_IF_ADDREF(*aPolicyContainer = mShared->mPolicyContainer);
    509  return NS_OK;
    510 }
    511 
    512 NS_IMETHODIMP
    513 nsSHEntry::SetPolicyContainer(nsIPolicyContainer* aPolicyContainer) {
    514  if (CSP_ShouldURIInheritCSP(mURI)) {
    515    mShared->mPolicyContainer = aPolicyContainer;
    516  }
    517  return NS_OK;
    518 }
    519 
    520 NS_IMETHODIMP
    521 nsSHEntry::AdoptBFCacheEntry(nsISHEntry* aEntry) {
    522  nsSHEntryShared* shared = static_cast<nsSHEntry*>(aEntry)->mShared;
    523  NS_ENSURE_STATE(shared);
    524 
    525  mShared = shared;
    526  return NS_OK;
    527 }
    528 
    529 NS_IMETHODIMP
    530 nsSHEntry::SharesDocumentWith(nsISHEntry* aEntry, bool* aOut) {
    531  NS_ENSURE_ARG_POINTER(aOut);
    532 
    533  *aOut = mShared == static_cast<nsSHEntry*>(aEntry)->mShared;
    534  return NS_OK;
    535 }
    536 
    537 NS_IMETHODIMP
    538 nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry) {
    539  *aIsSrcdocEntry = mIsSrcdocEntry;
    540  return NS_OK;
    541 }
    542 
    543 NS_IMETHODIMP
    544 nsSHEntry::GetSrcdocData(nsAString& aSrcdocData) {
    545  aSrcdocData = mSrcdocData;
    546  return NS_OK;
    547 }
    548 
    549 NS_IMETHODIMP
    550 nsSHEntry::SetSrcdocData(const nsAString& aSrcdocData) {
    551  mSrcdocData = aSrcdocData;
    552  mIsSrcdocEntry = true;
    553  return NS_OK;
    554 }
    555 
    556 NS_IMETHODIMP
    557 nsSHEntry::GetBaseURI(nsIURI** aBaseURI) {
    558  *aBaseURI = mBaseURI;
    559  NS_IF_ADDREF(*aBaseURI);
    560  return NS_OK;
    561 }
    562 
    563 NS_IMETHODIMP
    564 nsSHEntry::SetBaseURI(nsIURI* aBaseURI) {
    565  mBaseURI = aBaseURI;
    566  return NS_OK;
    567 }
    568 
    569 NS_IMETHODIMP
    570 nsSHEntry::GetScrollRestorationIsManual(bool* aIsManual) {
    571  *aIsManual = mScrollRestorationIsManual;
    572  return NS_OK;
    573 }
    574 
    575 NS_IMETHODIMP
    576 nsSHEntry::SetScrollRestorationIsManual(bool aIsManual) {
    577  mScrollRestorationIsManual = aIsManual;
    578  return NS_OK;
    579 }
    580 
    581 NS_IMETHODIMP
    582 nsSHEntry::GetLoadedInThisProcess(bool* aLoadedInThisProcess) {
    583  *aLoadedInThisProcess = mLoadedInThisProcess;
    584  return NS_OK;
    585 }
    586 
    587 NS_IMETHODIMP
    588 nsSHEntry::GetChildCount(int32_t* aCount) {
    589  *aCount = mChildren.Count();
    590  return NS_OK;
    591 }
    592 
    593 NS_IMETHODIMP
    594 nsSHEntry::AddChild(nsISHEntry* aChild, int32_t aOffset,
    595                    bool aUseRemoteSubframes) {
    596  if (aChild) {
    597    NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
    598  }
    599 
    600  if (aOffset < 0) {
    601    mChildren.AppendObject(aChild);
    602    return NS_OK;
    603  }
    604 
    605  //
    606  // Bug 52670: Ensure children are added in order.
    607  //
    608  //  Later frames in the child list may load faster and get appended
    609  //  before earlier frames, causing session history to be scrambled.
    610  //  By growing the list here, they are added to the right position.
    611  //
    612  //  Assert that aOffset will not be so high as to grow us a lot.
    613  //
    614  NS_ASSERTION(aOffset < (mChildren.Count() + 1023), "Large frames array!\n");
    615 
    616  bool newChildIsDyn = aChild ? aChild->IsDynamicallyAdded() : false;
    617 
    618  // If the new child is dynamically added, try to add it to aOffset, but if
    619  // there are non-dynamically added children, the child must be after those.
    620  if (newChildIsDyn) {
    621    int32_t lastNonDyn = aOffset - 1;
    622    for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
    623      nsISHEntry* entry = mChildren[i];
    624      if (entry) {
    625        if (entry->IsDynamicallyAdded()) {
    626          break;
    627        } else {
    628          lastNonDyn = i;
    629        }
    630      }
    631    }
    632    // InsertObjectAt allows only appending one object.
    633    // If aOffset is larger than Count(), we must first manually
    634    // set the capacity.
    635    if (aOffset > mChildren.Count()) {
    636      mChildren.SetCount(aOffset);
    637    }
    638    if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
    639      NS_WARNING("Adding a child failed!");
    640      aChild->SetParent(nullptr);
    641      return NS_ERROR_FAILURE;
    642    }
    643  } else {
    644    // If the new child isn't dynamically added, it should be set to aOffset.
    645    // If there are dynamically added children before that, those must be
    646    // moved to be after aOffset.
    647    if (mChildren.Count() > 0) {
    648      int32_t start = std::min(mChildren.Count() - 1, aOffset);
    649      int32_t dynEntryIndex = -1;
    650      nsISHEntry* dynEntry = nullptr;
    651      for (int32_t i = start; i >= 0; --i) {
    652        nsISHEntry* entry = mChildren[i];
    653        if (entry) {
    654          if (entry->IsDynamicallyAdded()) {
    655            dynEntryIndex = i;
    656            dynEntry = entry;
    657          } else {
    658            break;
    659          }
    660        }
    661      }
    662 
    663      if (dynEntry) {
    664        nsCOMArray<nsISHEntry> tmp;
    665        tmp.SetCount(aOffset - dynEntryIndex + 1);
    666        mChildren.InsertObjectsAt(tmp, dynEntryIndex);
    667        NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
    668      }
    669    }
    670 
    671    // Make sure there isn't anything at aOffset.
    672    if (aOffset < mChildren.Count()) {
    673      nsISHEntry* oldChild = mChildren[aOffset];
    674      if (oldChild && oldChild != aChild) {
    675        // Under Fission, this can happen when a network-created iframe starts
    676        // out in-process, moves out-of-process, and then switches back. At that
    677        // point, we'll create a new network-created DocShell at the same index
    678        // where we already have an entry for the original network-created
    679        // DocShell.
    680        //
    681        // This should ideally stop being an issue once the Fission-aware
    682        // session history rewrite is complete.
    683        NS_ASSERTION(
    684            aUseRemoteSubframes,
    685            "Adding a child where we already have a child? This may misbehave");
    686        oldChild->SetParent(nullptr);
    687      }
    688    }
    689 
    690    mChildren.ReplaceObjectAt(aChild, aOffset);
    691  }
    692 
    693  return NS_OK;
    694 }
    695 
    696 NS_IMETHODIMP
    697 nsSHEntry::RemoveChild(nsISHEntry* aChild) {
    698  NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
    699  bool childRemoved = false;
    700  if (aChild->IsDynamicallyAdded()) {
    701    childRemoved = mChildren.RemoveObject(aChild);
    702  } else {
    703    int32_t index = mChildren.IndexOfObject(aChild);
    704    if (index >= 0) {
    705      // Other alive non-dynamic child docshells still keep mChildOffset,
    706      // so we don't want to change the indices here.
    707      mChildren.ReplaceObjectAt(nullptr, index);
    708      childRemoved = true;
    709    }
    710  }
    711  if (childRemoved) {
    712    aChild->SetParent(nullptr);
    713 
    714    // reduce the child count, i.e. remove empty children at the end
    715    for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
    716      if (!mChildren.RemoveObjectAt(i)) {
    717        break;
    718      }
    719    }
    720  }
    721  return NS_OK;
    722 }
    723 
    724 NS_IMETHODIMP
    725 nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry** aResult) {
    726  if (aIndex >= 0 && aIndex < mChildren.Count()) {
    727    *aResult = mChildren[aIndex];
    728    // yes, mChildren can have holes in it.  AddChild's offset parameter makes
    729    // that possible.
    730    NS_IF_ADDREF(*aResult);
    731  } else {
    732    *aResult = nullptr;
    733  }
    734  return NS_OK;
    735 }
    736 
    737 NS_IMETHODIMP_(void)
    738 nsSHEntry::GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t aChildOffset,
    739                                                       nsISHEntry** aChild) {
    740  *aChild = nullptr;
    741 
    742  bool dynamicallyAddedChild = false;
    743  HasDynamicallyAddedChild(&dynamicallyAddedChild);
    744  if (dynamicallyAddedChild) {
    745    return;
    746  }
    747 
    748  // If the user did a shift-reload on this frameset page,
    749  // we don't want to load the subframes from history.
    750  if (IsForceReloadType(mLoadType) || mLoadType == LOAD_REFRESH) {
    751    return;
    752  }
    753 
    754  /* Before looking for the subframe's url, check
    755   * the expiration status of the parent. If the parent
    756   * has expired from cache, then subframes will not be
    757   * loaded from history in certain situations.
    758   * If the user pressed reload and the parent frame has expired
    759   *  from cache, we do not want to load the child frame from history.
    760   */
    761  if (mShared->mExpired && (mLoadType == LOAD_RELOAD_NORMAL)) {
    762    // The parent has expired. Return null.
    763    *aChild = nullptr;
    764    return;
    765  }
    766  // Get the child subframe from session history.
    767  GetChildAt(aChildOffset, aChild);
    768  if (*aChild) {
    769    // Set the parent's Load Type on the child
    770    (*aChild)->SetLoadType(mLoadType);
    771  }
    772 }
    773 
    774 NS_IMETHODIMP
    775 nsSHEntry::ReplaceChild(nsISHEntry* aNewEntry) {
    776  NS_ENSURE_STATE(aNewEntry);
    777 
    778  nsID docshellID;
    779  aNewEntry->GetDocshellID(docshellID);
    780 
    781  for (int32_t i = 0; i < mChildren.Count(); ++i) {
    782    if (mChildren[i]) {
    783      nsID childDocshellID;
    784      nsresult rv = mChildren[i]->GetDocshellID(childDocshellID);
    785      NS_ENSURE_SUCCESS(rv, rv);
    786      if (docshellID == childDocshellID) {
    787        mChildren[i]->SetParent(nullptr);
    788        mChildren.ReplaceObjectAt(aNewEntry, i);
    789        return aNewEntry->SetParent(this);
    790      }
    791    }
    792  }
    793  return NS_ERROR_FAILURE;
    794 }
    795 
    796 NS_IMETHODIMP_(void) nsSHEntry::ClearEntry() {
    797  int32_t childCount = GetChildCount();
    798  // Remove all children of this entry
    799  for (int32_t i = childCount - 1; i >= 0; i--) {
    800    nsCOMPtr<nsISHEntry> child;
    801    GetChildAt(i, getter_AddRefs(child));
    802    RemoveChild(child);
    803  }
    804  AbandonBFCacheEntry();
    805 }
    806 
    807 NS_IMETHODIMP
    808 nsSHEntry::GetStateData(nsIStructuredCloneContainer** aContainer) {
    809  NS_IF_ADDREF(*aContainer = mStateData);
    810  return NS_OK;
    811 }
    812 
    813 NS_IMETHODIMP
    814 nsSHEntry::SetStateData(nsIStructuredCloneContainer* aContainer) {
    815  mStateData = aContainer;
    816  return NS_OK;
    817 }
    818 
    819 NS_IMETHODIMP_(bool)
    820 nsSHEntry::IsDynamicallyAdded() { return mShared->mDynamicallyCreated; }
    821 
    822 NS_IMETHODIMP
    823 nsSHEntry::HasDynamicallyAddedChild(bool* aAdded) {
    824  *aAdded = false;
    825  for (int32_t i = 0; i < mChildren.Count(); ++i) {
    826    nsISHEntry* entry = mChildren[i];
    827    if (entry) {
    828      *aAdded = entry->IsDynamicallyAdded();
    829      if (*aAdded) {
    830        break;
    831      }
    832    }
    833  }
    834  return NS_OK;
    835 }
    836 
    837 NS_IMETHODIMP
    838 nsSHEntry::GetDocshellID(nsID& aID) {
    839  aID = mShared->mDocShellID;
    840  return NS_OK;
    841 }
    842 
    843 NS_IMETHODIMP
    844 nsSHEntry::SetDocshellID(const nsID& aID) {
    845  mShared->mDocShellID = aID;
    846  return NS_OK;
    847 }
    848 
    849 NS_IMETHODIMP
    850 nsSHEntry::GetNavigationKey(nsID& aNavigationKey) {
    851  aNavigationKey.Clear();
    852  return NS_OK;
    853 }
    854 
    855 NS_IMETHODIMP
    856 nsSHEntry::SetNavigationKey(const nsID& aNavigationKey) { return NS_OK; }
    857 
    858 NS_IMETHODIMP
    859 nsSHEntry::GetNavigationId(nsID& aNavigationId) {
    860  aNavigationId.Clear();
    861  return NS_OK;
    862 }
    863 
    864 NS_IMETHODIMP
    865 nsSHEntry::SetNavigationId(const nsID& aNavigationId) { return NS_OK; }
    866 
    867 NS_IMETHODIMP
    868 nsSHEntry::GetLastTouched(uint32_t* aLastTouched) {
    869  *aLastTouched = mShared->mLastTouched;
    870  return NS_OK;
    871 }
    872 
    873 NS_IMETHODIMP
    874 nsSHEntry::SetLastTouched(uint32_t aLastTouched) {
    875  mShared->mLastTouched = aLastTouched;
    876  return NS_OK;
    877 }
    878 
    879 NS_IMETHODIMP
    880 nsSHEntry::GetShistory(nsISHistory** aSHistory) {
    881  nsCOMPtr<nsISHistory> shistory(do_QueryReferent(mShared->mSHistory));
    882  shistory.forget(aSHistory);
    883  return NS_OK;
    884 }
    885 
    886 NS_IMETHODIMP
    887 nsSHEntry::SetShistory(nsISHistory* aSHistory) {
    888  nsWeakPtr shistory = do_GetWeakReference(aSHistory);
    889  // mSHistory can not be changed once it's set
    890  MOZ_ASSERT(!mShared->mSHistory || (mShared->mSHistory == shistory));
    891  mShared->mSHistory = shistory;
    892  return NS_OK;
    893 }
    894 
    895 NS_IMETHODIMP
    896 nsSHEntry::SetLoadTypeAsHistory() {
    897  // Set the LoadType by default to loadHistory during creation
    898  mLoadType = LOAD_HISTORY;
    899  return NS_OK;
    900 }
    901 
    902 NS_IMETHODIMP
    903 nsSHEntry::IsTransient(bool* aIsTransient) {
    904  *aIsTransient = mTransient;
    905  return NS_OK;
    906 }
    907 
    908 NS_IMETHODIMP
    909 nsSHEntry::SetTransient() {
    910  mTransient = true;
    911  return NS_OK;
    912 }
    913 
    914 NS_IMETHODIMP
    915 nsSHEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
    916  nsCOMPtr<nsIURI> uri = GetURI();
    917  RefPtr<nsDocShellLoadState> loadState(new nsDocShellLoadState(uri));
    918 
    919  nsCOMPtr<nsIURI> originalURI = GetOriginalURI();
    920  loadState->SetOriginalURI(originalURI);
    921 
    922  mozilla::Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
    923  nsCOMPtr<nsIURI> resultPrincipalURI = GetResultPrincipalURI();
    924  emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
    925  loadState->SetMaybeResultPrincipalURI(emplacedResultPrincipalURI);
    926 
    927  nsCOMPtr<nsIURI> unstrippedURI = GetUnstrippedURI();
    928  loadState->SetUnstrippedURI(unstrippedURI);
    929 
    930  loadState->SetLoadReplace(GetLoadReplace());
    931  nsCOMPtr<nsIInputStream> postData = GetPostData();
    932  loadState->SetPostDataStream(postData);
    933 
    934  nsAutoCString contentType;
    935  GetContentType(contentType);
    936  loadState->SetTypeHint(contentType);
    937 
    938  nsCOMPtr<nsIPrincipal> triggeringPrincipal = GetTriggeringPrincipal();
    939  loadState->SetTriggeringPrincipal(triggeringPrincipal);
    940  nsCOMPtr<nsIPrincipal> principalToInherit = GetPrincipalToInherit();
    941  loadState->SetPrincipalToInherit(principalToInherit);
    942  nsCOMPtr<nsIPrincipal> partitionedPrincipalToInherit =
    943      GetPartitionedPrincipalToInherit();
    944  loadState->SetPartitionedPrincipalToInherit(partitionedPrincipalToInherit);
    945  nsCOMPtr<nsIPolicyContainer> policyContainer = GetPolicyContainer();
    946  loadState->SetPolicyContainer(policyContainer);
    947  nsCOMPtr<nsIReferrerInfo> referrerInfo = GetReferrerInfo();
    948  loadState->SetReferrerInfo(referrerInfo);
    949 
    950  // Do not inherit principal from document (security-critical!);
    951  uint32_t flags = nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_NONE;
    952 
    953  // Passing nullptr as aSourceDocShell gives the same behaviour as before
    954  // aSourceDocShell was introduced. According to spec we should be passing
    955  // the source browsing context that was used when the history entry was
    956  // first created. bug 947716 has been created to address this issue.
    957  nsAutoString srcdoc;
    958  nsCOMPtr<nsIURI> baseURI;
    959  if (GetIsSrcdocEntry()) {
    960    GetSrcdocData(srcdoc);
    961    baseURI = GetBaseURI();
    962    flags |= nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
    963  } else {
    964    srcdoc = VoidString();
    965  }
    966  loadState->SetSrcdocData(srcdoc);
    967  loadState->SetBaseURI(baseURI);
    968  loadState->SetInternalLoadFlags(flags);
    969 
    970  loadState->SetFirstParty(true);
    971 
    972  const bool hasUserActivation = GetHasUserActivation();
    973  loadState->SetHasValidUserGestureActivation(hasUserActivation);
    974  loadState->SetTextDirectiveUserActivation(hasUserActivation);
    975 
    976  loadState->SetSHEntry(this);
    977 
    978  // When we create a load state from the history entry we already know if
    979  // https-first was able to upgrade the request from http to https. There is no
    980  // point in re-retrying to upgrade.
    981  loadState->SetIsExemptFromHTTPSFirstMode(true);
    982 
    983  loadState.forget(aLoadState);
    984  return NS_OK;
    985 }
    986 
    987 NS_IMETHODIMP_(void)
    988 nsSHEntry::SyncTreesForSubframeNavigation(
    989    nsISHEntry* aEntry, mozilla::dom::BrowsingContext* aTopBC,
    990    mozilla::dom::BrowsingContext* aIgnoreBC) {
    991  // XXX Keep this in sync with
    992  // SessionHistoryEntry::SyncTreesForSubframeNavigation
    993  //
    994  // We need to sync up the browsing context and session history trees for
    995  // subframe navigation.  If the load was in a subframe, we forward up to
    996  // the top browsing context, which will then recursively sync up all browsing
    997  // contexts to their corresponding entries in the new session history tree. If
    998  // we don't do this, then we can cache a content viewer on the wrong cloned
    999  // entry, and subsequently restore it at the wrong time.
   1000  nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
   1001  if (newRootEntry) {
   1002    // newRootEntry is now the new root entry.
   1003    // Find the old root entry as well.
   1004 
   1005    // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
   1006    // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
   1007    nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(this);
   1008 
   1009    if (oldRootEntry) {
   1010      nsSHistory::SwapEntriesData data = {aIgnoreBC, newRootEntry, nullptr};
   1011      nsSHistory::SetChildHistoryEntry(oldRootEntry, aTopBC, 0, &data);
   1012    }
   1013  }
   1014 }
   1015 
   1016 void nsSHEntry::EvictDocumentViewer() {
   1017  nsCOMPtr<nsIDocumentViewer> viewer = GetDocumentViewer();
   1018  if (viewer) {
   1019    mShared->NotifyListenersDocumentViewerEvicted();
   1020    // Drop the presentation state before destroying the viewer, so that
   1021    // document teardown is able to correctly persist the state.
   1022    SetDocumentViewer(nullptr);
   1023    SyncPresentationState();
   1024    viewer->Destroy();
   1025  }
   1026 }
   1027 
   1028 NS_IMETHODIMP
   1029 nsSHEntry::SetDocumentViewer(nsIDocumentViewer* aViewer) {
   1030  return GetState()->SetDocumentViewer(aViewer);
   1031 }
   1032 
   1033 NS_IMETHODIMP
   1034 nsSHEntry::GetDocumentViewer(nsIDocumentViewer** aResult) {
   1035  *aResult = GetState()->mDocumentViewer;
   1036  NS_IF_ADDREF(*aResult);
   1037  return NS_OK;
   1038 }
   1039 
   1040 NS_IMETHODIMP
   1041 nsSHEntry::GetIsInBFCache(bool* aResult) {
   1042  *aResult = !!GetState()->mDocumentViewer;
   1043  return NS_OK;
   1044 }
   1045 
   1046 NS_IMETHODIMP
   1047 nsSHEntry::Clone(nsISHEntry** aResult) {
   1048  nsCOMPtr<nsISHEntry> entry = new nsSHEntry(*this);
   1049  entry.forget(aResult);
   1050  return NS_OK;
   1051 }
   1052 
   1053 NS_IMETHODIMP
   1054 nsSHEntry::GetSaveLayoutStateFlag(bool* aFlag) {
   1055  *aFlag = mShared->mSaveLayoutState;
   1056  return NS_OK;
   1057 }
   1058 
   1059 NS_IMETHODIMP
   1060 nsSHEntry::SetSaveLayoutStateFlag(bool aFlag) {
   1061  mShared->mSaveLayoutState = aFlag;
   1062  if (mShared->mLayoutHistoryState) {
   1063    mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
   1064  }
   1065 
   1066  return NS_OK;
   1067 }
   1068 
   1069 NS_IMETHODIMP
   1070 nsSHEntry::SetWindowState(nsISupports* aState) {
   1071  GetState()->mWindowState = aState;
   1072  return NS_OK;
   1073 }
   1074 
   1075 NS_IMETHODIMP
   1076 nsSHEntry::GetWindowState(nsISupports** aState) {
   1077  NS_IF_ADDREF(*aState = GetState()->mWindowState);
   1078  return NS_OK;
   1079 }
   1080 
   1081 NS_IMETHODIMP
   1082 nsSHEntry::GetRefreshURIList(nsIMutableArray** aList) {
   1083  NS_IF_ADDREF(*aList = GetState()->mRefreshURIList);
   1084  return NS_OK;
   1085 }
   1086 
   1087 NS_IMETHODIMP
   1088 nsSHEntry::SetRefreshURIList(nsIMutableArray* aList) {
   1089  GetState()->mRefreshURIList = aList;
   1090  return NS_OK;
   1091 }
   1092 
   1093 NS_IMETHODIMP_(void)
   1094 nsSHEntry::AddChildShell(nsIDocShellTreeItem* aShell) {
   1095  MOZ_ASSERT(aShell, "Null child shell added to history entry");
   1096  GetState()->mChildShells.AppendObject(aShell);
   1097 }
   1098 
   1099 NS_IMETHODIMP
   1100 nsSHEntry::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem** aShell) {
   1101  NS_IF_ADDREF(*aShell = GetState()->mChildShells.SafeObjectAt(aIndex));
   1102  return NS_OK;
   1103 }
   1104 
   1105 NS_IMETHODIMP_(void)
   1106 nsSHEntry::ClearChildShells() { GetState()->mChildShells.Clear(); }
   1107 
   1108 NS_IMETHODIMP_(void)
   1109 nsSHEntry::SyncPresentationState() { GetState()->SyncPresentationState(); }
   1110 
   1111 nsDocShellEditorData* nsSHEntry::ForgetEditorData() {
   1112  // XXX jlebar Check how this is used.
   1113  return GetState()->mEditorData.release();
   1114 }
   1115 
   1116 void nsSHEntry::SetEditorData(nsDocShellEditorData* aData) {
   1117  NS_ASSERTION(!(aData && GetState()->mEditorData),
   1118               "We're going to overwrite an owning ref!");
   1119  if (GetState()->mEditorData != aData) {
   1120    GetState()->mEditorData = mozilla::WrapUnique(aData);
   1121  }
   1122 }
   1123 
   1124 bool nsSHEntry::HasDetachedEditor() {
   1125  return GetState()->mEditorData != nullptr;
   1126 }
   1127 
   1128 bool nsSHEntry::HasBFCacheEntry(
   1129    mozilla::dom::SHEntrySharedParentState* aEntry) {
   1130  return GetState() == aEntry;
   1131 }
   1132 
   1133 NS_IMETHODIMP
   1134 nsSHEntry::AbandonBFCacheEntry() {
   1135  mShared = GetState()->Duplicate();
   1136  return NS_OK;
   1137 }
   1138 
   1139 NS_IMETHODIMP
   1140 nsSHEntry::GetBfcacheID(uint64_t* aBFCacheID) {
   1141  *aBFCacheID = mShared->GetId();
   1142  return NS_OK;
   1143 }
   1144 
   1145 NS_IMETHODIMP
   1146 nsSHEntry::GetWireframe(JSContext* aCx, JS::MutableHandle<JS::Value> aOut) {
   1147  aOut.set(JS::NullValue());
   1148  return NS_OK;
   1149 }
   1150 
   1151 NS_IMETHODIMP
   1152 nsSHEntry::SetWireframe(JSContext* aCx, JS::Handle<JS::Value> aArg) {
   1153  return NS_ERROR_NOT_IMPLEMENTED;
   1154 }