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 }