SessionHistoryEntry.h (17957B)
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 #ifndef mozilla_dom_SessionHistoryEntry_h 8 #define mozilla_dom_SessionHistoryEntry_h 9 10 #include "mozilla/dom/DocumentBinding.h" 11 #include "mozilla/Maybe.h" 12 #include "mozilla/UniquePtr.h" 13 #include "mozilla/dom/NavigationBinding.h" 14 #include "nsILayoutHistoryState.h" 15 #include "nsISHEntry.h" 16 #include "nsSHEntryShared.h" 17 #include "nsStructuredCloneContainer.h" 18 #include "nsTHashMap.h" 19 #include "nsWeakReference.h" 20 21 class nsDocShellLoadState; 22 class nsIChannel; 23 class nsIInputStream; 24 class nsIReferrerInfo; 25 class nsISHistory; 26 class nsIURI; 27 28 namespace IPC { 29 template <typename P> 30 struct ParamTraits; 31 } 32 33 namespace mozilla { 34 namespace dom { 35 36 struct LoadingSessionHistoryInfo; 37 class SessionHistoryEntry; 38 class SHEntrySharedParentState; 39 40 // SessionHistoryInfo stores session history data for a load. It can be sent 41 // over IPC and is used in both the parent and the child processes. 42 class SessionHistoryInfo { 43 public: 44 SessionHistoryInfo() = default; 45 SessionHistoryInfo(const SessionHistoryInfo& aInfo) = default; 46 SessionHistoryInfo(nsDocShellLoadState* aLoadState, nsIChannel* aChannel); 47 SessionHistoryInfo(const SessionHistoryInfo& aSharedStateFrom, nsIURI* aURI); 48 SessionHistoryInfo(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal, 49 nsIPrincipal* aPrincipalToInherit, 50 nsIPrincipal* aPartitionedPrincipalToInherit, 51 nsIPolicyContainer* aPolicyContainer, 52 const nsACString& aContentType); 53 SessionHistoryInfo(nsIChannel* aChannel, uint32_t aLoadType, 54 nsIPrincipal* aPartitionedPrincipalToInherit, 55 nsIPolicyContainer* aPolicyContainer); 56 57 void Reset(nsIURI* aURI, const nsID& aDocShellID, bool aDynamicCreation, 58 nsIPrincipal* aTriggeringPrincipal, 59 nsIPrincipal* aPrincipalToInherit, 60 nsIPrincipal* aPartitionedPrincipalToInherit, 61 nsIPolicyContainer* aPolicyContainer, 62 const nsACString& aContentType); 63 64 bool operator==(const SessionHistoryInfo& aInfo) const { 65 return false; // FIXME 66 } 67 68 nsIURI* GetURI() const { return mURI; } 69 void SetURI(nsIURI* aURI) { mURI = aURI; } 70 71 nsIURI* GetOriginalURI() const { return mOriginalURI; } 72 void SetOriginalURI(nsIURI* aOriginalURI) { mOriginalURI = aOriginalURI; } 73 74 nsIURI* GetUnstrippedURI() const { return mUnstrippedURI; } 75 void SetUnstrippedURI(nsIURI* aUnstrippedURI) { 76 mUnstrippedURI = aUnstrippedURI; 77 } 78 79 nsIURI* GetResultPrincipalURI() const { return mResultPrincipalURI; } 80 void SetResultPrincipalURI(nsIURI* aResultPrincipalURI) { 81 mResultPrincipalURI = aResultPrincipalURI; 82 } 83 84 nsCOMPtr<nsIReferrerInfo> GetReferrerInfo() { return mReferrerInfo; } 85 void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) { 86 mReferrerInfo = aReferrerInfo; 87 } 88 89 bool HasPostData() const { return mPostData; } 90 already_AddRefed<nsIInputStream> GetPostData() const; 91 void SetPostData(nsIInputStream* aPostData); 92 93 void GetScrollPosition(int32_t* aScrollPositionX, int32_t* aScrollPositionY) { 94 *aScrollPositionX = mScrollPositionX; 95 *aScrollPositionY = mScrollPositionY; 96 } 97 98 void SetScrollPosition(int32_t aScrollPositionX, int32_t aScrollPositionY) { 99 mScrollPositionX = aScrollPositionX; 100 mScrollPositionY = aScrollPositionY; 101 } 102 103 bool GetScrollRestorationIsManual() const { 104 return mScrollRestorationIsManual; 105 } 106 const nsAString& GetTitle() { return mTitle; } 107 void SetTitle(const nsAString& aTitle) { 108 mTitle = aTitle; 109 MaybeUpdateTitleFromURI(); 110 } 111 112 const nsAString& GetName() { return mName; } 113 void SetName(const nsAString& aName) { mName = aName; } 114 115 void SetScrollRestorationIsManual(bool aIsManual) { 116 mScrollRestorationIsManual = aIsManual; 117 } 118 119 nsStructuredCloneContainer* GetStateData() const { return mStateData; } 120 void SetStateData(nsStructuredCloneContainer* aStateData) { 121 mStateData = aStateData; 122 } 123 124 void SetLoadReplace(bool aLoadReplace) { mLoadReplace = aLoadReplace; } 125 126 void SetURIWasModified(bool aURIWasModified) { 127 mURIWasModified = aURIWasModified; 128 } 129 bool GetURIWasModified() const { return mURIWasModified; } 130 131 void SetHasUserInteraction(bool aHasUserInteraction) { 132 mHasUserInteraction = aHasUserInteraction; 133 } 134 bool GetHasUserInteraction() const { return mHasUserInteraction; } 135 136 uint64_t SharedId() const; 137 138 nsILayoutHistoryState* GetLayoutHistoryState(); 139 void SetLayoutHistoryState(nsILayoutHistoryState* aState); 140 141 nsIPrincipal* GetTriggeringPrincipal() const; 142 143 nsIPrincipal* GetPrincipalToInherit() const; 144 145 nsIPrincipal* GetPartitionedPrincipalToInherit() const; 146 void SetPartitionedPrincipalToInherit(nsIPrincipal* aPrincipal); 147 148 nsIPolicyContainer* GetPolicyContainer() const; 149 150 uint32_t GetCacheKey() const; 151 void SetCacheKey(uint32_t aCacheKey); 152 153 bool IsSubFrame() const; 154 155 bool SharesDocumentWith(const SessionHistoryInfo& aOther) const { 156 return SharedId() == aOther.SharedId(); 157 } 158 159 void FillLoadInfo(nsDocShellLoadState& aLoadState) const; 160 161 uint32_t LoadType() { return mLoadType; } 162 163 void SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag); 164 165 bool IsTransient() { return mTransient; } 166 void SetTransient() { mTransient = true; } 167 168 nsID& NavigationKey() { return mNavigationKey; } 169 const nsID& NavigationKey() const { return mNavigationKey; } 170 const nsID& NavigationId() const { return mNavigationId; } 171 172 nsIStructuredCloneContainer* GetNavigationAPIState() const; 173 void SetNavigationAPIState(nsIStructuredCloneContainer* aState); 174 175 already_AddRefed<nsIURI> GetURIOrInheritedForAboutBlank() const; 176 177 private: 178 friend class SessionHistoryEntry; 179 friend struct IPC::ParamTraits<SessionHistoryInfo>; 180 181 void MaybeUpdateTitleFromURI(); 182 183 nsCOMPtr<nsIURI> mURI; 184 nsCOMPtr<nsIURI> mOriginalURI; 185 nsCOMPtr<nsIURI> mResultPrincipalURI; 186 nsCOMPtr<nsIURI> mUnstrippedURI; 187 nsCOMPtr<nsIReferrerInfo> mReferrerInfo; 188 nsString mTitle; 189 nsString mName; 190 nsCOMPtr<nsIInputStream> mPostData; 191 uint32_t mLoadType = 0; 192 int32_t mScrollPositionX = 0; 193 int32_t mScrollPositionY = 0; 194 RefPtr<nsStructuredCloneContainer> mStateData; 195 Maybe<nsString> mSrcdocData; 196 nsCOMPtr<nsIURI> mBaseURI; 197 198 // Fields needed for NavigationHistoryEntry. 199 nsID mNavigationKey = nsID::GenerateUUID(); 200 nsID mNavigationId = nsID::GenerateUUID(); 201 // https://html.spec.whatwg.org/#she-navigation-api-state 202 RefPtr<nsStructuredCloneContainer> mNavigationAPIState; 203 204 bool mLoadReplace = false; 205 bool mURIWasModified = false; 206 bool mScrollRestorationIsManual = false; 207 bool mTransient = false; 208 bool mHasUserInteraction = false; 209 bool mHasUserActivation = false; 210 211 union SharedState { 212 SharedState(); 213 explicit SharedState(const SharedState& aOther); 214 explicit SharedState(const Maybe<const SharedState&>& aOther); 215 ~SharedState(); 216 217 SharedState& operator=(const SharedState& aOther); 218 219 SHEntrySharedState* Get() const; 220 221 void Set(SHEntrySharedParentState* aState) { mParent = aState; } 222 223 void ChangeId(uint64_t aId); 224 225 static SharedState Create(nsIPrincipal* aTriggeringPrincipal, 226 nsIPrincipal* aPrincipalToInherit, 227 nsIPrincipal* aPartitionedPrincipalToInherit, 228 nsIPolicyContainer* aPolicyContainer, 229 const nsACString& aContentType); 230 231 private: 232 explicit SharedState(SHEntrySharedParentState* aParent) 233 : mParent(aParent) {} 234 explicit SharedState(UniquePtr<SHEntrySharedState>&& aChild) 235 : mChild(std::move(aChild)) {} 236 237 void Init(); 238 void Init(const SharedState& aOther); 239 240 // In the parent process this holds a strong reference to the refcounted 241 // SHEntrySharedParentState. In the child processes this holds an owning 242 // pointer to a SHEntrySharedState. 243 RefPtr<SHEntrySharedParentState> mParent; 244 UniquePtr<SHEntrySharedState> mChild; 245 }; 246 247 SharedState mSharedState; 248 }; 249 250 struct LoadingSessionHistoryInfo { 251 LoadingSessionHistoryInfo() = default; 252 explicit LoadingSessionHistoryInfo(SessionHistoryEntry* aEntry); 253 // Initializes mInfo using aEntry and otherwise copies the values from aInfo. 254 LoadingSessionHistoryInfo(SessionHistoryEntry* aEntry, 255 const LoadingSessionHistoryInfo* aInfo); 256 // For about:blank only. 257 explicit LoadingSessionHistoryInfo(const SessionHistoryInfo& aInfo); 258 259 already_AddRefed<nsDocShellLoadState> CreateLoadInfo() const; 260 261 SessionHistoryInfo mInfo; 262 263 // The same origin (to mInfo) preceeding entries. 264 CopyableTArray<SessionHistoryInfo> mContiguousEntries; 265 266 // The entry that triggered the navigation to this entry. 267 Maybe<SessionHistoryInfo> mTriggeringEntry; 268 // The type of navigation which triggered this load. 269 Maybe<NavigationType> mTriggeringNavigationType; 270 271 uint64_t mLoadId = 0; 272 273 // The following three member variables are used to inform about a load from 274 // the session history. The session-history-in-child approach has just 275 // an nsISHEntry in the nsDocShellLoadState and access to the nsISHistory, 276 // but session-history-in-parent needs to pass needed information explicitly 277 // to the relevant child process. 278 bool mLoadIsFromSessionHistory = false; 279 // mOffset and mLoadingCurrentEntry are relevant only if 280 // mLoadIsFromSessionHistory is true. 281 int32_t mOffset = 0; 282 // If we're loading from the current entry we want to treat it as not a 283 // same-document navigation (see nsDocShell::IsSameDocumentNavigation). 284 bool mLoadingCurrentEntry = false; 285 // If mForceMaybeResetName.isSome() is true then the parent process has 286 // determined whether the BC's name should be cleared and stored in session 287 // history (see https://html.spec.whatwg.org/#history-traversal step 4.2). 288 // This is used when we're replacing the BC for BFCache in the parent. In 289 // other cases mForceMaybeResetName.isSome() will be false and the child 290 // process should be able to make that determination itself. 291 Maybe<bool> mForceMaybeResetName; 292 }; 293 294 // HistoryEntryCounterForBrowsingContext is used to count the number of entries 295 // which are added to the session history for a particular browsing context. 296 // If a SessionHistoryEntry is cloned because of navigation in some other 297 // browsing context, that doesn't cause the counter value to be increased. 298 // The browsing context specific counter is needed to make it easier to 299 // synchronously update history.length value in a child process when 300 // an iframe is removed from DOM. 301 class HistoryEntryCounterForBrowsingContext { 302 public: 303 HistoryEntryCounterForBrowsingContext() 304 : mCounter(new RefCountedCounter()), mHasModified(false) { 305 ++(*this); 306 } 307 308 HistoryEntryCounterForBrowsingContext( 309 const HistoryEntryCounterForBrowsingContext& aOther) 310 : mCounter(aOther.mCounter), mHasModified(false) {} 311 312 HistoryEntryCounterForBrowsingContext( 313 HistoryEntryCounterForBrowsingContext&& aOther) = delete; 314 315 ~HistoryEntryCounterForBrowsingContext() { 316 if (mHasModified) { 317 --(*mCounter); 318 } 319 } 320 321 void CopyValueFrom(const HistoryEntryCounterForBrowsingContext& aOther) { 322 if (mHasModified) { 323 --(*mCounter); 324 } 325 mCounter = aOther.mCounter; 326 mHasModified = false; 327 } 328 329 HistoryEntryCounterForBrowsingContext& operator=( 330 const HistoryEntryCounterForBrowsingContext& aOther) = delete; 331 332 HistoryEntryCounterForBrowsingContext& operator++() { 333 mHasModified = true; 334 ++(*mCounter); 335 return *this; 336 } 337 338 operator uint32_t() const { return *mCounter; } 339 340 bool Modified() { return mHasModified; } 341 342 void SetModified(bool aModified) { mHasModified = aModified; } 343 344 void Reset() { 345 if (mHasModified) { 346 --(*mCounter); 347 } 348 mCounter = new RefCountedCounter(); 349 mHasModified = false; 350 } 351 352 private: 353 class RefCountedCounter { 354 public: 355 NS_INLINE_DECL_REFCOUNTING( 356 mozilla::dom::HistoryEntryCounterForBrowsingContext::RefCountedCounter) 357 358 RefCountedCounter& operator++() { 359 ++mCounter; 360 return *this; 361 } 362 363 RefCountedCounter& operator--() { 364 --mCounter; 365 return *this; 366 } 367 368 operator uint32_t() const { return mCounter; } 369 370 private: 371 ~RefCountedCounter() = default; 372 373 uint32_t mCounter = 0; 374 }; 375 376 RefPtr<RefCountedCounter> mCounter; 377 bool mHasModified; 378 }; 379 380 // SessionHistoryEntry is used to store session history data in the parent 381 // process. It holds a SessionHistoryInfo, some state shared amongst multiple 382 // SessionHistoryEntries, a parent and children. 383 #define NS_SESSIONHISTORYENTRY_IID \ 384 {0x5b66a244, 0x8cec, 0x4caa, {0xaa, 0x0a, 0x78, 0x92, 0xfd, 0x17, 0xa6, 0x67}} 385 386 class SessionHistoryEntry : public nsISHEntry, 387 public nsSupportsWeakReference, 388 public LinkedListElement<SessionHistoryEntry> { 389 public: 390 SessionHistoryEntry(nsDocShellLoadState* aLoadState, nsIChannel* aChannel); 391 SessionHistoryEntry(); 392 explicit SessionHistoryEntry(SessionHistoryInfo* aInfo); 393 explicit SessionHistoryEntry(const SessionHistoryEntry& aEntry); 394 395 NS_DECL_ISUPPORTS 396 NS_DECL_NSISHENTRY 397 NS_INLINE_DECL_STATIC_IID(NS_SESSIONHISTORYENTRY_IID) 398 399 bool IsInSessionHistory() { 400 SessionHistoryEntry* entry = this; 401 while (nsCOMPtr<SessionHistoryEntry> parent = 402 do_QueryReferent(entry->mParent)) { 403 entry = parent; 404 } 405 return entry->SharedInfo()->mSHistory && 406 entry->SharedInfo()->mSHistory->IsAlive(); 407 } 408 409 void ReplaceWith(const SessionHistoryEntry& aSource); 410 411 const SessionHistoryInfo& Info() const { return *mInfo; } 412 413 SHEntrySharedParentState* SharedInfo() const; 414 415 void SetFrameLoader(nsFrameLoader* aFrameLoader); 416 nsFrameLoader* GetFrameLoader(); 417 418 void AddChild(SessionHistoryEntry* aChild, int32_t aOffset, 419 bool aUseRemoteSubframes); 420 void RemoveChild(SessionHistoryEntry* aChild); 421 // Finds the child with the same docshell ID as aNewChild, replaces it with 422 // aNewChild and returns true. If there is no child with the same docshell ID 423 // then it returns false. 424 bool ReplaceChild(SessionHistoryEntry* aNewChild); 425 426 void SetInfo(SessionHistoryInfo* aInfo); 427 428 bool ForInitialLoad() { return mForInitialLoad; } 429 void SetForInitialLoad(bool aForInitialLoad) { 430 mForInitialLoad = aForInitialLoad; 431 } 432 433 const nsID& DocshellID() const; 434 435 HistoryEntryCounterForBrowsingContext& BCHistoryLength() { 436 return mBCHistoryLength; 437 } 438 439 void SetBCHistoryLength(HistoryEntryCounterForBrowsingContext& aCounter) { 440 mBCHistoryLength.CopyValueFrom(aCounter); 441 } 442 443 void ClearBCHistoryLength() { mBCHistoryLength.Reset(); } 444 445 void SetIsDynamicallyAdded(bool aDynamic); 446 447 void SetWireframe(const Maybe<Wireframe>& aWireframe); 448 449 struct LoadingEntry { 450 // A pointer to the entry being loaded. Will be cleared by the 451 // SessionHistoryEntry destructor, at latest. 452 SessionHistoryEntry* mEntry; 453 // Snapshot of the entry's SessionHistoryInfo when the load started, to be 454 // used for validation purposes only. 455 UniquePtr<SessionHistoryInfo> mInfoSnapshotForValidation; 456 }; 457 458 // Get an entry based on LoadingSessionHistoryInfo's mLoadId. Parent process 459 // only. 460 static LoadingEntry* GetByLoadId(uint64_t aLoadId); 461 static void SetByLoadId(uint64_t aLoadId, SessionHistoryEntry* aEntry); 462 static void RemoveLoadId(uint64_t aLoadId); 463 464 const nsTArray<RefPtr<SessionHistoryEntry>>& Children() { return mChildren; } 465 466 already_AddRefed<nsIURI> GetURIOrInheritedForAboutBlank() const; 467 468 void SetNavigationAPIState(nsIStructuredCloneContainer* aState) { 469 mInfo->SetNavigationAPIState(aState); 470 } 471 472 private: 473 friend struct LoadingSessionHistoryInfo; 474 virtual ~SessionHistoryEntry(); 475 476 UniquePtr<SessionHistoryInfo> mInfo; 477 nsWeakPtr mParent; 478 uint32_t mID; 479 nsTArray<RefPtr<SessionHistoryEntry>> mChildren; 480 Maybe<Wireframe> mWireframe; 481 482 bool mForInitialLoad = false; 483 484 HistoryEntryCounterForBrowsingContext mBCHistoryLength; 485 486 static nsTHashMap<nsUint64HashKey, LoadingEntry>* sLoadIdToEntry; 487 }; 488 489 } // namespace dom 490 } // namespace mozilla 491 492 namespace IPC { 493 494 // Allow sending SessionHistoryInfo objects over IPC. 495 template <> 496 struct ParamTraits<mozilla::dom::SessionHistoryInfo> { 497 static void Write(IPC::MessageWriter* aWriter, 498 const mozilla::dom::SessionHistoryInfo& aParam); 499 static bool Read(IPC::MessageReader* aReader, 500 mozilla::dom::SessionHistoryInfo* aResult); 501 }; 502 503 // Allow sending LoadingSessionHistoryInfo objects over IPC. 504 template <> 505 struct ParamTraits<mozilla::dom::LoadingSessionHistoryInfo> { 506 static void Write(IPC::MessageWriter* aWriter, 507 const mozilla::dom::LoadingSessionHistoryInfo& aParam); 508 static bool Read(IPC::MessageReader* aReader, 509 mozilla::dom::LoadingSessionHistoryInfo* aResult); 510 }; 511 512 // Allow sending nsILayoutHistoryState objects over IPC. 513 template <> 514 struct ParamTraits<nsILayoutHistoryState*> { 515 static void Write(IPC::MessageWriter* aWriter, nsILayoutHistoryState* aParam); 516 static bool Read(IPC::MessageReader* aReader, 517 RefPtr<nsILayoutHistoryState>* aResult); 518 }; 519 520 // Allow sending mozilla::dom::Wireframe objects over IPC. 521 template <> 522 struct ParamTraits<mozilla::dom::Wireframe> { 523 static void Write(IPC::MessageWriter* aWriter, 524 const mozilla::dom::Wireframe& aParam); 525 static bool Read(IPC::MessageReader* aReader, 526 mozilla::dom::Wireframe* aResult); 527 }; 528 529 } // namespace IPC 530 531 inline nsISupports* ToSupports(mozilla::dom::SessionHistoryEntry* aEntry) { 532 return static_cast<nsISHEntry*>(aEntry); 533 } 534 535 #endif /* mozilla_dom_SessionHistoryEntry_h */