Bug 1891710: part 2) Enable <Element-outerHTML.html> WPT for Trusted Types. r=smaug
[gecko.git] / docshell / shistory / nsSHEntry.cpp
blob8fc4f74844590d3701649e6dce11c4256f7d56b6
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/. */
7 #include "nsSHEntry.h"
9 #include <algorithm>
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"
26 #include "mozilla/Logging.h"
27 #include "nsIReferrerInfo.h"
29 extern mozilla::LazyLogModule gPageCacheLog;
31 static uint32_t gEntryID = 0;
33 nsSHEntry::nsSHEntry()
34 : mShared(new nsSHEntryShared()),
35 mLoadType(0),
36 mID(++gEntryID), // SessionStore has special handling for 0 values.
37 mScrollPositionX(0),
38 mScrollPositionY(0),
39 mLoadReplace(false),
40 mURIWasModified(false),
41 mIsSrcdocEntry(false),
42 mScrollRestorationIsManual(false),
43 mLoadedInThisProcess(false),
44 mPersist(true),
45 mHasUserInteraction(false),
46 mHasUserActivation(false) {}
48 nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
49 : mShared(aOther.mShared),
50 mURI(aOther.mURI),
51 mOriginalURI(aOther.mOriginalURI),
52 mResultPrincipalURI(aOther.mResultPrincipalURI),
53 mUnstrippedURI(aOther.mUnstrippedURI),
54 mReferrerInfo(aOther.mReferrerInfo),
55 mTitle(aOther.mTitle),
56 mPostData(aOther.mPostData),
57 mLoadType(0), // XXX why not copy?
58 mID(aOther.mID),
59 mScrollPositionX(0), // XXX why not copy?
60 mScrollPositionY(0), // XXX why not copy?
61 mParent(aOther.mParent),
62 mStateData(aOther.mStateData),
63 mSrcdocData(aOther.mSrcdocData),
64 mBaseURI(aOther.mBaseURI),
65 mLoadReplace(aOther.mLoadReplace),
66 mURIWasModified(aOther.mURIWasModified),
67 mIsSrcdocEntry(aOther.mIsSrcdocEntry),
68 mScrollRestorationIsManual(false),
69 mLoadedInThisProcess(aOther.mLoadedInThisProcess),
70 mPersist(aOther.mPersist),
71 mHasUserInteraction(false),
72 mHasUserActivation(aOther.mHasUserActivation) {}
74 nsSHEntry::~nsSHEntry() {
75 // Null out the mParent pointers on all our kids.
76 for (nsISHEntry* entry : mChildren) {
77 if (entry) {
78 entry->SetParent(nullptr);
83 NS_IMPL_ISUPPORTS(nsSHEntry, nsISHEntry, nsISupportsWeakReference)
85 NS_IMETHODIMP
86 nsSHEntry::SetScrollPosition(int32_t aX, int32_t aY) {
87 mScrollPositionX = aX;
88 mScrollPositionY = aY;
89 return NS_OK;
92 NS_IMETHODIMP
93 nsSHEntry::GetScrollPosition(int32_t* aX, int32_t* aY) {
94 *aX = mScrollPositionX;
95 *aY = mScrollPositionY;
96 return NS_OK;
99 NS_IMETHODIMP
100 nsSHEntry::GetURIWasModified(bool* aOut) {
101 *aOut = mURIWasModified;
102 return NS_OK;
105 NS_IMETHODIMP
106 nsSHEntry::SetURIWasModified(bool aIn) {
107 mURIWasModified = aIn;
108 return NS_OK;
111 NS_IMETHODIMP
112 nsSHEntry::GetURI(nsIURI** aURI) {
113 *aURI = mURI;
114 NS_IF_ADDREF(*aURI);
115 return NS_OK;
118 NS_IMETHODIMP
119 nsSHEntry::SetURI(nsIURI* aURI) {
120 mURI = aURI;
121 return NS_OK;
124 NS_IMETHODIMP
125 nsSHEntry::GetOriginalURI(nsIURI** aOriginalURI) {
126 *aOriginalURI = mOriginalURI;
127 NS_IF_ADDREF(*aOriginalURI);
128 return NS_OK;
131 NS_IMETHODIMP
132 nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI) {
133 mOriginalURI = aOriginalURI;
134 return NS_OK;
137 NS_IMETHODIMP
138 nsSHEntry::GetResultPrincipalURI(nsIURI** aResultPrincipalURI) {
139 *aResultPrincipalURI = mResultPrincipalURI;
140 NS_IF_ADDREF(*aResultPrincipalURI);
141 return NS_OK;
144 NS_IMETHODIMP
145 nsSHEntry::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
146 mResultPrincipalURI = aResultPrincipalURI;
147 return NS_OK;
150 NS_IMETHODIMP
151 nsSHEntry::GetUnstrippedURI(nsIURI** aUnstrippedURI) {
152 *aUnstrippedURI = mUnstrippedURI;
153 NS_IF_ADDREF(*aUnstrippedURI);
154 return NS_OK;
157 NS_IMETHODIMP
158 nsSHEntry::SetUnstrippedURI(nsIURI* aUnstrippedURI) {
159 mUnstrippedURI = aUnstrippedURI;
160 return NS_OK;
163 NS_IMETHODIMP
164 nsSHEntry::GetLoadReplace(bool* aLoadReplace) {
165 *aLoadReplace = mLoadReplace;
166 return NS_OK;
169 NS_IMETHODIMP
170 nsSHEntry::SetLoadReplace(bool aLoadReplace) {
171 mLoadReplace = aLoadReplace;
172 return NS_OK;
175 NS_IMETHODIMP
176 nsSHEntry::GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) {
177 *aReferrerInfo = mReferrerInfo;
178 NS_IF_ADDREF(*aReferrerInfo);
179 return NS_OK;
182 NS_IMETHODIMP
183 nsSHEntry::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
184 mReferrerInfo = aReferrerInfo;
185 return NS_OK;
188 NS_IMETHODIMP
189 nsSHEntry::SetSticky(bool aSticky) {
190 mShared->mSticky = aSticky;
191 return NS_OK;
194 NS_IMETHODIMP
195 nsSHEntry::GetSticky(bool* aSticky) {
196 *aSticky = mShared->mSticky;
197 return NS_OK;
200 NS_IMETHODIMP
201 nsSHEntry::GetTitle(nsAString& aTitle) {
202 // Check for empty title...
203 if (mTitle.IsEmpty() && mURI) {
204 // Default title is the URL.
205 nsAutoCString spec;
206 if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
207 AppendUTF8toUTF16(spec, mTitle);
211 aTitle = mTitle;
212 return NS_OK;
215 NS_IMETHODIMP
216 nsSHEntry::SetTitle(const nsAString& aTitle) {
217 mTitle = aTitle;
218 return NS_OK;
221 NS_IMETHODIMP
222 nsSHEntry::GetName(nsAString& aName) {
223 aName = mName;
224 return NS_OK;
227 NS_IMETHODIMP
228 nsSHEntry::SetName(const nsAString& aName) {
229 mName = aName;
230 return NS_OK;
233 NS_IMETHODIMP
234 nsSHEntry::GetPostData(nsIInputStream** aResult) {
235 *aResult = mPostData;
236 NS_IF_ADDREF(*aResult);
237 return NS_OK;
240 NS_IMETHODIMP
241 nsSHEntry::SetPostData(nsIInputStream* aPostData) {
242 mPostData = aPostData;
243 return NS_OK;
246 NS_IMETHODIMP
247 nsSHEntry::GetHasPostData(bool* aResult) {
248 *aResult = !!mPostData;
249 return NS_OK;
252 NS_IMETHODIMP
253 nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult) {
254 *aResult = mShared->mLayoutHistoryState;
255 NS_IF_ADDREF(*aResult);
256 return NS_OK;
259 NS_IMETHODIMP
260 nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState) {
261 mShared->mLayoutHistoryState = aState;
262 if (mShared->mLayoutHistoryState) {
263 mShared->mLayoutHistoryState->SetScrollPositionOnly(
264 !mShared->mSaveLayoutState);
267 return NS_OK;
270 NS_IMETHODIMP
271 nsSHEntry::InitLayoutHistoryState(nsILayoutHistoryState** aState) {
272 if (!mShared->mLayoutHistoryState) {
273 nsCOMPtr<nsILayoutHistoryState> historyState;
274 historyState = NS_NewLayoutHistoryState();
275 SetLayoutHistoryState(historyState);
278 nsCOMPtr<nsILayoutHistoryState> state = GetLayoutHistoryState();
279 state.forget(aState);
280 return NS_OK;
283 NS_IMETHODIMP
284 nsSHEntry::GetLoadType(uint32_t* aResult) {
285 *aResult = mLoadType;
286 return NS_OK;
289 NS_IMETHODIMP
290 nsSHEntry::SetLoadType(uint32_t aLoadType) {
291 mLoadType = aLoadType;
292 return NS_OK;
295 NS_IMETHODIMP
296 nsSHEntry::GetID(uint32_t* aResult) {
297 *aResult = mID;
298 return NS_OK;
301 NS_IMETHODIMP
302 nsSHEntry::SetID(uint32_t aID) {
303 mID = aID;
304 return NS_OK;
307 NS_IMETHODIMP
308 nsSHEntry::GetIsSubFrame(bool* aFlag) {
309 *aFlag = mShared->mIsFrameNavigation;
310 return NS_OK;
313 NS_IMETHODIMP
314 nsSHEntry::SetIsSubFrame(bool aFlag) {
315 mShared->mIsFrameNavigation = aFlag;
316 return NS_OK;
319 NS_IMETHODIMP
320 nsSHEntry::GetHasUserInteraction(bool* aFlag) {
321 // The back button and menulist deal with root/top-level
322 // session history entries, thus we annotate only the root entry.
323 if (!mParent) {
324 *aFlag = mHasUserInteraction;
325 } else {
326 nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
327 root->GetHasUserInteraction(aFlag);
329 return NS_OK;
332 NS_IMETHODIMP
333 nsSHEntry::SetHasUserInteraction(bool aFlag) {
334 // The back button and menulist deal with root/top-level
335 // session history entries, thus we annotate only the root entry.
336 if (!mParent) {
337 mHasUserInteraction = aFlag;
338 } else {
339 nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
340 root->SetHasUserInteraction(aFlag);
342 return NS_OK;
345 NS_IMETHODIMP
346 nsSHEntry::GetHasUserActivation(bool* aFlag) {
347 *aFlag = mHasUserActivation;
348 return NS_OK;
351 NS_IMETHODIMP
352 nsSHEntry::SetHasUserActivation(bool aFlag) {
353 mHasUserActivation = aFlag;
354 return NS_OK;
357 NS_IMETHODIMP
358 nsSHEntry::GetCacheKey(uint32_t* aResult) {
359 *aResult = mShared->mCacheKey;
360 return NS_OK;
363 NS_IMETHODIMP
364 nsSHEntry::SetCacheKey(uint32_t aCacheKey) {
365 mShared->mCacheKey = aCacheKey;
366 return NS_OK;
369 NS_IMETHODIMP
370 nsSHEntry::GetContentType(nsACString& aContentType) {
371 aContentType = mShared->mContentType;
372 return NS_OK;
375 NS_IMETHODIMP
376 nsSHEntry::SetContentType(const nsACString& aContentType) {
377 mShared->mContentType = aContentType;
378 return NS_OK;
381 NS_IMETHODIMP
382 nsSHEntry::Create(
383 nsIURI* aURI, const nsAString& aTitle, nsIInputStream* aInputStream,
384 uint32_t aCacheKey, const nsACString& aContentType,
385 nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
386 nsIPrincipal* aPartitionedPrincipalToInherit,
387 nsIContentSecurityPolicy* aCsp, const nsID& aDocShellID,
388 bool aDynamicCreation, nsIURI* aOriginalURI, nsIURI* aResultPrincipalURI,
389 nsIURI* aUnstrippedURI, bool aLoadReplace, nsIReferrerInfo* aReferrerInfo,
390 const nsAString& aSrcdocData, bool aSrcdocEntry, nsIURI* aBaseURI,
391 bool aSaveLayoutState, bool aExpired, bool aUserActivation) {
392 MOZ_ASSERT(
393 aTriggeringPrincipal,
394 "need a valid triggeringPrincipal to create a session history entry");
396 mURI = aURI;
397 mTitle = aTitle;
398 mPostData = aInputStream;
400 // Set the LoadType by default to loadHistory during creation
401 mLoadType = LOAD_HISTORY;
403 mShared->mCacheKey = aCacheKey;
404 mShared->mContentType = aContentType;
405 mShared->mTriggeringPrincipal = aTriggeringPrincipal;
406 mShared->mPrincipalToInherit = aPrincipalToInherit;
407 mShared->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
408 mShared->mCsp = aCsp;
409 mShared->mDocShellID = aDocShellID;
410 mShared->mDynamicallyCreated = aDynamicCreation;
412 // By default all entries are set false for subframe flag.
413 // nsDocShell::CloneAndReplace() which creates entries for
414 // all subframe navigations, sets the flag to true.
415 mShared->mIsFrameNavigation = false;
417 mHasUserInteraction = false;
419 mShared->mExpired = aExpired;
421 mIsSrcdocEntry = aSrcdocEntry;
422 mSrcdocData = aSrcdocData;
424 mBaseURI = aBaseURI;
426 mLoadedInThisProcess = true;
428 mOriginalURI = aOriginalURI;
429 mResultPrincipalURI = aResultPrincipalURI;
430 mUnstrippedURI = aUnstrippedURI;
431 mLoadReplace = aLoadReplace;
432 mReferrerInfo = aReferrerInfo;
434 mHasUserActivation = aUserActivation;
436 mShared->mLayoutHistoryState = nullptr;
438 mShared->mSaveLayoutState = aSaveLayoutState;
440 return NS_OK;
443 NS_IMETHODIMP
444 nsSHEntry::GetParent(nsISHEntry** aResult) {
445 nsCOMPtr<nsISHEntry> parent = do_QueryReferent(mParent);
446 parent.forget(aResult);
447 return NS_OK;
450 NS_IMETHODIMP
451 nsSHEntry::SetParent(nsISHEntry* aParent) {
452 mParent = do_GetWeakReference(aParent);
453 return NS_OK;
456 NS_IMETHODIMP_(void)
457 nsSHEntry::SetViewerBounds(const nsIntRect& aBounds) {
458 mShared->mViewerBounds = aBounds;
461 NS_IMETHODIMP_(void)
462 nsSHEntry::GetViewerBounds(nsIntRect& aBounds) {
463 aBounds = mShared->mViewerBounds;
466 NS_IMETHODIMP
467 nsSHEntry::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal) {
468 NS_IF_ADDREF(*aTriggeringPrincipal = mShared->mTriggeringPrincipal);
469 return NS_OK;
472 NS_IMETHODIMP
473 nsSHEntry::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal) {
474 mShared->mTriggeringPrincipal = aTriggeringPrincipal;
475 return NS_OK;
478 NS_IMETHODIMP
479 nsSHEntry::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
480 NS_IF_ADDREF(*aPrincipalToInherit = mShared->mPrincipalToInherit);
481 return NS_OK;
484 NS_IMETHODIMP
485 nsSHEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
486 mShared->mPrincipalToInherit = aPrincipalToInherit;
487 return NS_OK;
490 NS_IMETHODIMP
491 nsSHEntry::GetPartitionedPrincipalToInherit(
492 nsIPrincipal** aPartitionedPrincipalToInherit) {
493 NS_IF_ADDREF(*aPartitionedPrincipalToInherit =
494 mShared->mPartitionedPrincipalToInherit);
495 return NS_OK;
498 NS_IMETHODIMP
499 nsSHEntry::SetPartitionedPrincipalToInherit(
500 nsIPrincipal* aPartitionedPrincipalToInherit) {
501 mShared->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
502 return NS_OK;
505 NS_IMETHODIMP
506 nsSHEntry::GetCsp(nsIContentSecurityPolicy** aCsp) {
507 NS_IF_ADDREF(*aCsp = mShared->mCsp);
508 return NS_OK;
511 NS_IMETHODIMP
512 nsSHEntry::SetCsp(nsIContentSecurityPolicy* aCsp) {
513 mShared->mCsp = aCsp;
514 return NS_OK;
517 NS_IMETHODIMP
518 nsSHEntry::AdoptBFCacheEntry(nsISHEntry* aEntry) {
519 nsSHEntryShared* shared = static_cast<nsSHEntry*>(aEntry)->mShared;
520 NS_ENSURE_STATE(shared);
522 mShared = shared;
523 return NS_OK;
526 NS_IMETHODIMP
527 nsSHEntry::SharesDocumentWith(nsISHEntry* aEntry, bool* aOut) {
528 NS_ENSURE_ARG_POINTER(aOut);
530 *aOut = mShared == static_cast<nsSHEntry*>(aEntry)->mShared;
531 return NS_OK;
534 NS_IMETHODIMP
535 nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry) {
536 *aIsSrcdocEntry = mIsSrcdocEntry;
537 return NS_OK;
540 NS_IMETHODIMP
541 nsSHEntry::GetSrcdocData(nsAString& aSrcdocData) {
542 aSrcdocData = mSrcdocData;
543 return NS_OK;
546 NS_IMETHODIMP
547 nsSHEntry::SetSrcdocData(const nsAString& aSrcdocData) {
548 mSrcdocData = aSrcdocData;
549 mIsSrcdocEntry = true;
550 return NS_OK;
553 NS_IMETHODIMP
554 nsSHEntry::GetBaseURI(nsIURI** aBaseURI) {
555 *aBaseURI = mBaseURI;
556 NS_IF_ADDREF(*aBaseURI);
557 return NS_OK;
560 NS_IMETHODIMP
561 nsSHEntry::SetBaseURI(nsIURI* aBaseURI) {
562 mBaseURI = aBaseURI;
563 return NS_OK;
566 NS_IMETHODIMP
567 nsSHEntry::GetScrollRestorationIsManual(bool* aIsManual) {
568 *aIsManual = mScrollRestorationIsManual;
569 return NS_OK;
572 NS_IMETHODIMP
573 nsSHEntry::SetScrollRestorationIsManual(bool aIsManual) {
574 mScrollRestorationIsManual = aIsManual;
575 return NS_OK;
578 NS_IMETHODIMP
579 nsSHEntry::GetLoadedInThisProcess(bool* aLoadedInThisProcess) {
580 *aLoadedInThisProcess = mLoadedInThisProcess;
581 return NS_OK;
584 NS_IMETHODIMP
585 nsSHEntry::GetChildCount(int32_t* aCount) {
586 *aCount = mChildren.Count();
587 return NS_OK;
590 NS_IMETHODIMP
591 nsSHEntry::AddChild(nsISHEntry* aChild, int32_t aOffset,
592 bool aUseRemoteSubframes) {
593 if (aChild) {
594 NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
597 if (aOffset < 0) {
598 mChildren.AppendObject(aChild);
599 return NS_OK;
603 // Bug 52670: Ensure children are added in order.
605 // Later frames in the child list may load faster and get appended
606 // before earlier frames, causing session history to be scrambled.
607 // By growing the list here, they are added to the right position.
609 // Assert that aOffset will not be so high as to grow us a lot.
611 NS_ASSERTION(aOffset < (mChildren.Count() + 1023), "Large frames array!\n");
613 bool newChildIsDyn = aChild ? aChild->IsDynamicallyAdded() : false;
615 // If the new child is dynamically added, try to add it to aOffset, but if
616 // there are non-dynamically added children, the child must be after those.
617 if (newChildIsDyn) {
618 int32_t lastNonDyn = aOffset - 1;
619 for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
620 nsISHEntry* entry = mChildren[i];
621 if (entry) {
622 if (entry->IsDynamicallyAdded()) {
623 break;
624 } else {
625 lastNonDyn = i;
629 // InsertObjectAt allows only appending one object.
630 // If aOffset is larger than Count(), we must first manually
631 // set the capacity.
632 if (aOffset > mChildren.Count()) {
633 mChildren.SetCount(aOffset);
635 if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
636 NS_WARNING("Adding a child failed!");
637 aChild->SetParent(nullptr);
638 return NS_ERROR_FAILURE;
640 } else {
641 // If the new child isn't dynamically added, it should be set to aOffset.
642 // If there are dynamically added children before that, those must be
643 // moved to be after aOffset.
644 if (mChildren.Count() > 0) {
645 int32_t start = std::min(mChildren.Count() - 1, aOffset);
646 int32_t dynEntryIndex = -1;
647 nsISHEntry* dynEntry = nullptr;
648 for (int32_t i = start; i >= 0; --i) {
649 nsISHEntry* entry = mChildren[i];
650 if (entry) {
651 if (entry->IsDynamicallyAdded()) {
652 dynEntryIndex = i;
653 dynEntry = entry;
654 } else {
655 break;
660 if (dynEntry) {
661 nsCOMArray<nsISHEntry> tmp;
662 tmp.SetCount(aOffset - dynEntryIndex + 1);
663 mChildren.InsertObjectsAt(tmp, dynEntryIndex);
664 NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
668 // Make sure there isn't anything at aOffset.
669 if (aOffset < mChildren.Count()) {
670 nsISHEntry* oldChild = mChildren[aOffset];
671 if (oldChild && oldChild != aChild) {
672 // Under Fission, this can happen when a network-created iframe starts
673 // out in-process, moves out-of-process, and then switches back. At that
674 // point, we'll create a new network-created DocShell at the same index
675 // where we already have an entry for the original network-created
676 // DocShell.
678 // This should ideally stop being an issue once the Fission-aware
679 // session history rewrite is complete.
680 NS_ASSERTION(
681 aUseRemoteSubframes,
682 "Adding a child where we already have a child? This may misbehave");
683 oldChild->SetParent(nullptr);
687 mChildren.ReplaceObjectAt(aChild, aOffset);
690 return NS_OK;
693 NS_IMETHODIMP
694 nsSHEntry::RemoveChild(nsISHEntry* aChild) {
695 NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
696 bool childRemoved = false;
697 if (aChild->IsDynamicallyAdded()) {
698 childRemoved = mChildren.RemoveObject(aChild);
699 } else {
700 int32_t index = mChildren.IndexOfObject(aChild);
701 if (index >= 0) {
702 // Other alive non-dynamic child docshells still keep mChildOffset,
703 // so we don't want to change the indices here.
704 mChildren.ReplaceObjectAt(nullptr, index);
705 childRemoved = true;
708 if (childRemoved) {
709 aChild->SetParent(nullptr);
711 // reduce the child count, i.e. remove empty children at the end
712 for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
713 if (!mChildren.RemoveObjectAt(i)) {
714 break;
718 return NS_OK;
721 NS_IMETHODIMP
722 nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry** aResult) {
723 if (aIndex >= 0 && aIndex < mChildren.Count()) {
724 *aResult = mChildren[aIndex];
725 // yes, mChildren can have holes in it. AddChild's offset parameter makes
726 // that possible.
727 NS_IF_ADDREF(*aResult);
728 } else {
729 *aResult = nullptr;
731 return NS_OK;
734 NS_IMETHODIMP_(void)
735 nsSHEntry::GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t aChildOffset,
736 nsISHEntry** aChild) {
737 *aChild = nullptr;
739 bool dynamicallyAddedChild = false;
740 HasDynamicallyAddedChild(&dynamicallyAddedChild);
741 if (dynamicallyAddedChild) {
742 return;
745 // If the user did a shift-reload on this frameset page,
746 // we don't want to load the subframes from history.
747 if (IsForceReloadType(mLoadType) || mLoadType == LOAD_REFRESH) {
748 return;
751 /* Before looking for the subframe's url, check
752 * the expiration status of the parent. If the parent
753 * has expired from cache, then subframes will not be
754 * loaded from history in certain situations.
755 * If the user pressed reload and the parent frame has expired
756 * from cache, we do not want to load the child frame from history.
758 if (mShared->mExpired && (mLoadType == LOAD_RELOAD_NORMAL)) {
759 // The parent has expired. Return null.
760 *aChild = nullptr;
761 return;
763 // Get the child subframe from session history.
764 GetChildAt(aChildOffset, aChild);
765 if (*aChild) {
766 // Set the parent's Load Type on the child
767 (*aChild)->SetLoadType(mLoadType);
771 NS_IMETHODIMP
772 nsSHEntry::ReplaceChild(nsISHEntry* aNewEntry) {
773 NS_ENSURE_STATE(aNewEntry);
775 nsID docshellID;
776 aNewEntry->GetDocshellID(docshellID);
778 for (int32_t i = 0; i < mChildren.Count(); ++i) {
779 if (mChildren[i]) {
780 nsID childDocshellID;
781 nsresult rv = mChildren[i]->GetDocshellID(childDocshellID);
782 NS_ENSURE_SUCCESS(rv, rv);
783 if (docshellID == childDocshellID) {
784 mChildren[i]->SetParent(nullptr);
785 mChildren.ReplaceObjectAt(aNewEntry, i);
786 return aNewEntry->SetParent(this);
790 return NS_ERROR_FAILURE;
793 NS_IMETHODIMP_(void) nsSHEntry::ClearEntry() {
794 int32_t childCount = GetChildCount();
795 // Remove all children of this entry
796 for (int32_t i = childCount - 1; i >= 0; i--) {
797 nsCOMPtr<nsISHEntry> child;
798 GetChildAt(i, getter_AddRefs(child));
799 RemoveChild(child);
801 AbandonBFCacheEntry();
804 NS_IMETHODIMP
805 nsSHEntry::GetStateData(nsIStructuredCloneContainer** aContainer) {
806 NS_IF_ADDREF(*aContainer = mStateData);
807 return NS_OK;
810 NS_IMETHODIMP
811 nsSHEntry::SetStateData(nsIStructuredCloneContainer* aContainer) {
812 mStateData = aContainer;
813 return NS_OK;
816 NS_IMETHODIMP_(bool)
817 nsSHEntry::IsDynamicallyAdded() { return mShared->mDynamicallyCreated; }
819 NS_IMETHODIMP
820 nsSHEntry::HasDynamicallyAddedChild(bool* aAdded) {
821 *aAdded = false;
822 for (int32_t i = 0; i < mChildren.Count(); ++i) {
823 nsISHEntry* entry = mChildren[i];
824 if (entry) {
825 *aAdded = entry->IsDynamicallyAdded();
826 if (*aAdded) {
827 break;
831 return NS_OK;
834 NS_IMETHODIMP
835 nsSHEntry::GetDocshellID(nsID& aID) {
836 aID = mShared->mDocShellID;
837 return NS_OK;
840 NS_IMETHODIMP
841 nsSHEntry::SetDocshellID(const nsID& aID) {
842 mShared->mDocShellID = aID;
843 return NS_OK;
846 NS_IMETHODIMP
847 nsSHEntry::GetLastTouched(uint32_t* aLastTouched) {
848 *aLastTouched = mShared->mLastTouched;
849 return NS_OK;
852 NS_IMETHODIMP
853 nsSHEntry::SetLastTouched(uint32_t aLastTouched) {
854 mShared->mLastTouched = aLastTouched;
855 return NS_OK;
858 NS_IMETHODIMP
859 nsSHEntry::GetShistory(nsISHistory** aSHistory) {
860 nsCOMPtr<nsISHistory> shistory(do_QueryReferent(mShared->mSHistory));
861 shistory.forget(aSHistory);
862 return NS_OK;
865 NS_IMETHODIMP
866 nsSHEntry::SetShistory(nsISHistory* aSHistory) {
867 nsWeakPtr shistory = do_GetWeakReference(aSHistory);
868 // mSHistory can not be changed once it's set
869 MOZ_ASSERT(!mShared->mSHistory || (mShared->mSHistory == shistory));
870 mShared->mSHistory = shistory;
871 return NS_OK;
874 NS_IMETHODIMP
875 nsSHEntry::SetLoadTypeAsHistory() {
876 // Set the LoadType by default to loadHistory during creation
877 mLoadType = LOAD_HISTORY;
878 return NS_OK;
881 NS_IMETHODIMP
882 nsSHEntry::GetPersist(bool* aPersist) {
883 *aPersist = mPersist;
884 return NS_OK;
887 NS_IMETHODIMP
888 nsSHEntry::SetPersist(bool aPersist) {
889 mPersist = aPersist;
890 return NS_OK;
893 NS_IMETHODIMP
894 nsSHEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
895 nsCOMPtr<nsIURI> uri = GetURI();
896 RefPtr<nsDocShellLoadState> loadState(new nsDocShellLoadState(uri));
898 nsCOMPtr<nsIURI> originalURI = GetOriginalURI();
899 loadState->SetOriginalURI(originalURI);
901 mozilla::Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
902 nsCOMPtr<nsIURI> resultPrincipalURI = GetResultPrincipalURI();
903 emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
904 loadState->SetMaybeResultPrincipalURI(emplacedResultPrincipalURI);
906 nsCOMPtr<nsIURI> unstrippedURI = GetUnstrippedURI();
907 loadState->SetUnstrippedURI(unstrippedURI);
909 loadState->SetLoadReplace(GetLoadReplace());
910 nsCOMPtr<nsIInputStream> postData = GetPostData();
911 loadState->SetPostDataStream(postData);
913 nsAutoCString contentType;
914 GetContentType(contentType);
915 loadState->SetTypeHint(contentType);
917 nsCOMPtr<nsIPrincipal> triggeringPrincipal = GetTriggeringPrincipal();
918 loadState->SetTriggeringPrincipal(triggeringPrincipal);
919 nsCOMPtr<nsIPrincipal> principalToInherit = GetPrincipalToInherit();
920 loadState->SetPrincipalToInherit(principalToInherit);
921 nsCOMPtr<nsIPrincipal> partitionedPrincipalToInherit =
922 GetPartitionedPrincipalToInherit();
923 loadState->SetPartitionedPrincipalToInherit(partitionedPrincipalToInherit);
924 nsCOMPtr<nsIContentSecurityPolicy> csp = GetCsp();
925 loadState->SetCsp(csp);
926 nsCOMPtr<nsIReferrerInfo> referrerInfo = GetReferrerInfo();
927 loadState->SetReferrerInfo(referrerInfo);
929 // Do not inherit principal from document (security-critical!);
930 uint32_t flags = nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_NONE;
932 // Passing nullptr as aSourceDocShell gives the same behaviour as before
933 // aSourceDocShell was introduced. According to spec we should be passing
934 // the source browsing context that was used when the history entry was
935 // first created. bug 947716 has been created to address this issue.
936 nsAutoString srcdoc;
937 nsCOMPtr<nsIURI> baseURI;
938 if (GetIsSrcdocEntry()) {
939 GetSrcdocData(srcdoc);
940 baseURI = GetBaseURI();
941 flags |= nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
942 } else {
943 srcdoc = VoidString();
945 loadState->SetSrcdocData(srcdoc);
946 loadState->SetBaseURI(baseURI);
947 loadState->SetInternalLoadFlags(flags);
949 loadState->SetFirstParty(true);
951 loadState->SetHasValidUserGestureActivation(GetHasUserActivation());
953 loadState->SetSHEntry(this);
955 // When we create a load state from the history entry we already know if
956 // https-first was able to upgrade the request from http to https. There is no
957 // point in re-retrying to upgrade.
958 loadState->SetIsExemptFromHTTPSFirstMode(true);
960 loadState.forget(aLoadState);
961 return NS_OK;
964 NS_IMETHODIMP_(void)
965 nsSHEntry::SyncTreesForSubframeNavigation(
966 nsISHEntry* aEntry, mozilla::dom::BrowsingContext* aTopBC,
967 mozilla::dom::BrowsingContext* aIgnoreBC) {
968 // XXX Keep this in sync with
969 // SessionHistoryEntry::SyncTreesForSubframeNavigation
971 // We need to sync up the browsing context and session history trees for
972 // subframe navigation. If the load was in a subframe, we forward up to
973 // the top browsing context, which will then recursively sync up all browsing
974 // contexts to their corresponding entries in the new session history tree. If
975 // we don't do this, then we can cache a content viewer on the wrong cloned
976 // entry, and subsequently restore it at the wrong time.
977 nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
978 if (newRootEntry) {
979 // newRootEntry is now the new root entry.
980 // Find the old root entry as well.
982 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
983 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
984 nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(this);
986 if (oldRootEntry) {
987 nsSHistory::SwapEntriesData data = {aIgnoreBC, newRootEntry, nullptr};
988 nsSHistory::SetChildHistoryEntry(oldRootEntry, aTopBC, 0, &data);
993 void nsSHEntry::EvictDocumentViewer() {
994 nsCOMPtr<nsIDocumentViewer> viewer = GetDocumentViewer();
995 if (viewer) {
996 mShared->NotifyListenersDocumentViewerEvicted();
997 // Drop the presentation state before destroying the viewer, so that
998 // document teardown is able to correctly persist the state.
999 SetDocumentViewer(nullptr);
1000 SyncPresentationState();
1001 viewer->Destroy();
1005 NS_IMETHODIMP
1006 nsSHEntry::SetDocumentViewer(nsIDocumentViewer* aViewer) {
1007 return GetState()->SetDocumentViewer(aViewer);
1010 NS_IMETHODIMP
1011 nsSHEntry::GetDocumentViewer(nsIDocumentViewer** aResult) {
1012 *aResult = GetState()->mDocumentViewer;
1013 NS_IF_ADDREF(*aResult);
1014 return NS_OK;
1017 NS_IMETHODIMP
1018 nsSHEntry::GetIsInBFCache(bool* aResult) {
1019 *aResult = !!GetState()->mDocumentViewer;
1020 return NS_OK;
1023 NS_IMETHODIMP
1024 nsSHEntry::Clone(nsISHEntry** aResult) {
1025 nsCOMPtr<nsISHEntry> entry = new nsSHEntry(*this);
1026 entry.forget(aResult);
1027 return NS_OK;
1030 NS_IMETHODIMP
1031 nsSHEntry::GetSaveLayoutStateFlag(bool* aFlag) {
1032 *aFlag = mShared->mSaveLayoutState;
1033 return NS_OK;
1036 NS_IMETHODIMP
1037 nsSHEntry::SetSaveLayoutStateFlag(bool aFlag) {
1038 mShared->mSaveLayoutState = aFlag;
1039 if (mShared->mLayoutHistoryState) {
1040 mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
1043 return NS_OK;
1046 NS_IMETHODIMP
1047 nsSHEntry::SetWindowState(nsISupports* aState) {
1048 GetState()->mWindowState = aState;
1049 return NS_OK;
1052 NS_IMETHODIMP
1053 nsSHEntry::GetWindowState(nsISupports** aState) {
1054 NS_IF_ADDREF(*aState = GetState()->mWindowState);
1055 return NS_OK;
1058 NS_IMETHODIMP
1059 nsSHEntry::GetRefreshURIList(nsIMutableArray** aList) {
1060 NS_IF_ADDREF(*aList = GetState()->mRefreshURIList);
1061 return NS_OK;
1064 NS_IMETHODIMP
1065 nsSHEntry::SetRefreshURIList(nsIMutableArray* aList) {
1066 GetState()->mRefreshURIList = aList;
1067 return NS_OK;
1070 NS_IMETHODIMP_(void)
1071 nsSHEntry::AddChildShell(nsIDocShellTreeItem* aShell) {
1072 MOZ_ASSERT(aShell, "Null child shell added to history entry");
1073 GetState()->mChildShells.AppendObject(aShell);
1076 NS_IMETHODIMP
1077 nsSHEntry::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem** aShell) {
1078 NS_IF_ADDREF(*aShell = GetState()->mChildShells.SafeObjectAt(aIndex));
1079 return NS_OK;
1082 NS_IMETHODIMP_(void)
1083 nsSHEntry::ClearChildShells() { GetState()->mChildShells.Clear(); }
1085 NS_IMETHODIMP_(void)
1086 nsSHEntry::SyncPresentationState() { GetState()->SyncPresentationState(); }
1088 nsDocShellEditorData* nsSHEntry::ForgetEditorData() {
1089 // XXX jlebar Check how this is used.
1090 return GetState()->mEditorData.release();
1093 void nsSHEntry::SetEditorData(nsDocShellEditorData* aData) {
1094 NS_ASSERTION(!(aData && GetState()->mEditorData),
1095 "We're going to overwrite an owning ref!");
1096 if (GetState()->mEditorData != aData) {
1097 GetState()->mEditorData = mozilla::WrapUnique(aData);
1101 bool nsSHEntry::HasDetachedEditor() {
1102 return GetState()->mEditorData != nullptr;
1105 bool nsSHEntry::HasBFCacheEntry(
1106 mozilla::dom::SHEntrySharedParentState* aEntry) {
1107 return GetState() == aEntry;
1110 NS_IMETHODIMP
1111 nsSHEntry::AbandonBFCacheEntry() {
1112 mShared = GetState()->Duplicate();
1113 return NS_OK;
1116 NS_IMETHODIMP
1117 nsSHEntry::GetBfcacheID(uint64_t* aBFCacheID) {
1118 *aBFCacheID = mShared->GetId();
1119 return NS_OK;
1122 NS_IMETHODIMP
1123 nsSHEntry::GetWireframe(JSContext* aCx, JS::MutableHandle<JS::Value> aOut) {
1124 aOut.set(JS::NullValue());
1125 return NS_OK;
1128 NS_IMETHODIMP
1129 nsSHEntry::SetWireframe(JSContext* aCx, JS::Handle<JS::Value> aArg) {
1130 return NS_ERROR_NOT_IMPLEMENTED;