Backed out changeset ebc60855035e (bug 1829026) as requested for causing Bug 1869760...
[gecko.git] / docshell / shistory / SessionHistoryEntry.h
blob8eeb5ad2a9e9d734b138d06f10e0c28957d0f758
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 #ifndef mozilla_dom_SessionHistoryEntry_h
8 #define mozilla_dom_SessionHistoryEntry_h
10 #include "mozilla/dom/DocumentBinding.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/UniquePtr.h"
13 #include "nsILayoutHistoryState.h"
14 #include "nsISHEntry.h"
15 #include "nsSHEntryShared.h"
16 #include "nsStructuredCloneContainer.h"
17 #include "nsTHashMap.h"
18 #include "nsWeakReference.h"
20 class nsDocShellLoadState;
21 class nsIChannel;
22 class nsIInputStream;
23 class nsIReferrerInfo;
24 class nsISHistory;
25 class nsIURI;
27 namespace mozilla::ipc {
28 template <typename P>
29 struct IPDLParamTraits;
32 namespace mozilla {
33 namespace dom {
35 struct LoadingSessionHistoryInfo;
36 class SessionHistoryEntry;
37 class SHEntrySharedParentState;
39 // SessionHistoryInfo stores session history data for a load. It can be sent
40 // over IPC and is used in both the parent and the child processes.
41 class SessionHistoryInfo {
42 public:
43 SessionHistoryInfo() = default;
44 SessionHistoryInfo(const SessionHistoryInfo& aInfo) = default;
45 SessionHistoryInfo(nsDocShellLoadState* aLoadState, nsIChannel* aChannel);
46 SessionHistoryInfo(const SessionHistoryInfo& aSharedStateFrom, nsIURI* aURI);
47 SessionHistoryInfo(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
48 nsIPrincipal* aPrincipalToInherit,
49 nsIPrincipal* aPartitionedPrincipalToInherit,
50 nsIContentSecurityPolicy* aCsp,
51 const nsACString& aContentType);
52 SessionHistoryInfo(nsIChannel* aChannel, uint32_t aLoadType,
53 nsIPrincipal* aPartitionedPrincipalToInherit,
54 nsIContentSecurityPolicy* aCsp);
56 void Reset(nsIURI* aURI, const nsID& aDocShellID, bool aDynamicCreation,
57 nsIPrincipal* aTriggeringPrincipal,
58 nsIPrincipal* aPrincipalToInherit,
59 nsIPrincipal* aPartitionedPrincipalToInherit,
60 nsIContentSecurityPolicy* aCsp, const nsACString& aContentType);
62 bool operator==(const SessionHistoryInfo& aInfo) const {
63 return false; // FIXME
66 nsIURI* GetURI() const { return mURI; }
67 void SetURI(nsIURI* aURI) { mURI = aURI; }
69 nsIURI* GetOriginalURI() const { return mOriginalURI; }
70 void SetOriginalURI(nsIURI* aOriginalURI) { mOriginalURI = aOriginalURI; }
72 nsIURI* GetUnstrippedURI() const { return mUnstrippedURI; }
73 void SetUnstrippedURI(nsIURI* aUnstrippedURI) {
74 mUnstrippedURI = aUnstrippedURI;
77 nsIURI* GetResultPrincipalURI() const { return mResultPrincipalURI; }
78 void SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
79 mResultPrincipalURI = aResultPrincipalURI;
82 nsIReferrerInfo* GetReferrerInfo() { return mReferrerInfo; }
83 void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
84 mReferrerInfo = aReferrerInfo;
87 bool HasPostData() const { return mPostData; }
88 already_AddRefed<nsIInputStream> GetPostData() const;
89 void SetPostData(nsIInputStream* aPostData);
91 void GetScrollPosition(int32_t* aScrollPositionX, int32_t* aScrollPositionY) {
92 *aScrollPositionX = mScrollPositionX;
93 *aScrollPositionY = mScrollPositionY;
96 void SetScrollPosition(int32_t aScrollPositionX, int32_t aScrollPositionY) {
97 mScrollPositionX = aScrollPositionX;
98 mScrollPositionY = aScrollPositionY;
101 bool GetScrollRestorationIsManual() const {
102 return mScrollRestorationIsManual;
104 const nsAString& GetTitle() { return mTitle; }
105 void SetTitle(const nsAString& aTitle) {
106 mTitle = aTitle;
107 MaybeUpdateTitleFromURI();
110 const nsAString& GetName() { return mName; }
111 void SetName(const nsAString& aName) { mName = aName; }
113 void SetScrollRestorationIsManual(bool aIsManual) {
114 mScrollRestorationIsManual = aIsManual;
117 nsStructuredCloneContainer* GetStateData() const { return mStateData; }
118 void SetStateData(nsStructuredCloneContainer* aStateData) {
119 mStateData = aStateData;
122 void SetLoadReplace(bool aLoadReplace) { mLoadReplace = aLoadReplace; }
124 void SetURIWasModified(bool aURIWasModified) {
125 mURIWasModified = aURIWasModified;
127 bool GetURIWasModified() const { return mURIWasModified; }
129 void SetHasUserInteraction(bool aHasUserInteraction) {
130 mHasUserInteraction = aHasUserInteraction;
132 bool GetHasUserInteraction() const { return mHasUserInteraction; }
134 uint64_t SharedId() const;
136 nsILayoutHistoryState* GetLayoutHistoryState();
137 void SetLayoutHistoryState(nsILayoutHistoryState* aState);
139 nsIPrincipal* GetTriggeringPrincipal() const;
141 nsIPrincipal* GetPrincipalToInherit() const;
143 nsIPrincipal* GetPartitionedPrincipalToInherit() const;
145 nsIContentSecurityPolicy* GetCsp() const;
147 uint32_t GetCacheKey() const;
148 void SetCacheKey(uint32_t aCacheKey);
150 bool IsSubFrame() const;
152 bool SharesDocumentWith(const SessionHistoryInfo& aOther) const {
153 return SharedId() == aOther.SharedId();
156 void FillLoadInfo(nsDocShellLoadState& aLoadState) const;
158 uint32_t LoadType() { return mLoadType; }
160 void SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag);
162 bool GetPersist() const { return mPersist; }
164 private:
165 friend class SessionHistoryEntry;
166 friend struct mozilla::ipc::IPDLParamTraits<SessionHistoryInfo>;
168 void MaybeUpdateTitleFromURI();
170 nsCOMPtr<nsIURI> mURI;
171 nsCOMPtr<nsIURI> mOriginalURI;
172 nsCOMPtr<nsIURI> mResultPrincipalURI;
173 nsCOMPtr<nsIURI> mUnstrippedURI;
174 nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
175 nsString mTitle;
176 nsString mName;
177 nsCOMPtr<nsIInputStream> mPostData;
178 uint32_t mLoadType = 0;
179 int32_t mScrollPositionX = 0;
180 int32_t mScrollPositionY = 0;
181 RefPtr<nsStructuredCloneContainer> mStateData;
182 Maybe<nsString> mSrcdocData;
183 nsCOMPtr<nsIURI> mBaseURI;
185 bool mLoadReplace = false;
186 bool mURIWasModified = false;
187 bool mScrollRestorationIsManual = false;
188 bool mPersist = true;
189 bool mHasUserInteraction = false;
190 bool mHasUserActivation = false;
192 union SharedState {
193 SharedState();
194 explicit SharedState(const SharedState& aOther);
195 explicit SharedState(const Maybe<const SharedState&>& aOther);
196 ~SharedState();
198 SharedState& operator=(const SharedState& aOther);
200 SHEntrySharedState* Get() const;
202 void Set(SHEntrySharedParentState* aState) { mParent = aState; }
204 void ChangeId(uint64_t aId);
206 static SharedState Create(nsIPrincipal* aTriggeringPrincipal,
207 nsIPrincipal* aPrincipalToInherit,
208 nsIPrincipal* aPartitionedPrincipalToInherit,
209 nsIContentSecurityPolicy* aCsp,
210 const nsACString& aContentType);
212 private:
213 explicit SharedState(SHEntrySharedParentState* aParent)
214 : mParent(aParent) {}
215 explicit SharedState(UniquePtr<SHEntrySharedState>&& aChild)
216 : mChild(std::move(aChild)) {}
218 void Init();
219 void Init(const SharedState& aOther);
221 // In the parent process this holds a strong reference to the refcounted
222 // SHEntrySharedParentState. In the child processes this holds an owning
223 // pointer to a SHEntrySharedState.
224 RefPtr<SHEntrySharedParentState> mParent;
225 UniquePtr<SHEntrySharedState> mChild;
228 SharedState mSharedState;
231 struct LoadingSessionHistoryInfo {
232 LoadingSessionHistoryInfo() = default;
233 explicit LoadingSessionHistoryInfo(SessionHistoryEntry* aEntry);
234 // Initializes mInfo using aEntry and otherwise copies the values from aInfo.
235 LoadingSessionHistoryInfo(SessionHistoryEntry* aEntry,
236 const LoadingSessionHistoryInfo* aInfo);
237 // For about:blank only.
238 explicit LoadingSessionHistoryInfo(const SessionHistoryInfo& aInfo);
240 already_AddRefed<nsDocShellLoadState> CreateLoadInfo() const;
242 SessionHistoryInfo mInfo;
244 uint64_t mLoadId = 0;
246 // The following three member variables are used to inform about a load from
247 // the session history. The session-history-in-child approach has just
248 // an nsISHEntry in the nsDocShellLoadState and access to the nsISHistory,
249 // but session-history-in-parent needs to pass needed information explicitly
250 // to the relevant child process.
251 bool mLoadIsFromSessionHistory = false;
252 // mOffset and mLoadingCurrentEntry are relevant only if
253 // mLoadIsFromSessionHistory is true.
254 int32_t mOffset = 0;
255 // If we're loading from the current entry we want to treat it as not a
256 // same-document navigation (see nsDocShell::IsSameDocumentNavigation).
257 bool mLoadingCurrentEntry = false;
258 // If mForceMaybeResetName.isSome() is true then the parent process has
259 // determined whether the BC's name should be cleared and stored in session
260 // history (see https://html.spec.whatwg.org/#history-traversal step 4.2).
261 // This is used when we're replacing the BC for BFCache in the parent. In
262 // other cases mForceMaybeResetName.isSome() will be false and the child
263 // process should be able to make that determination itself.
264 Maybe<bool> mForceMaybeResetName;
267 // HistoryEntryCounterForBrowsingContext is used to count the number of entries
268 // which are added to the session history for a particular browsing context.
269 // If a SessionHistoryEntry is cloned because of navigation in some other
270 // browsing context, that doesn't cause the counter value to be increased.
271 // The browsing context specific counter is needed to make it easier to
272 // synchronously update history.length value in a child process when
273 // an iframe is removed from DOM.
274 class HistoryEntryCounterForBrowsingContext {
275 public:
276 HistoryEntryCounterForBrowsingContext()
277 : mCounter(new RefCountedCounter()), mHasModified(false) {
278 ++(*this);
281 HistoryEntryCounterForBrowsingContext(
282 const HistoryEntryCounterForBrowsingContext& aOther)
283 : mCounter(aOther.mCounter), mHasModified(false) {}
285 HistoryEntryCounterForBrowsingContext(
286 HistoryEntryCounterForBrowsingContext&& aOther) = delete;
288 ~HistoryEntryCounterForBrowsingContext() {
289 if (mHasModified) {
290 --(*mCounter);
294 void CopyValueFrom(const HistoryEntryCounterForBrowsingContext& aOther) {
295 if (mHasModified) {
296 --(*mCounter);
298 mCounter = aOther.mCounter;
299 mHasModified = false;
302 HistoryEntryCounterForBrowsingContext& operator=(
303 const HistoryEntryCounterForBrowsingContext& aOther) = delete;
305 HistoryEntryCounterForBrowsingContext& operator++() {
306 mHasModified = true;
307 ++(*mCounter);
308 return *this;
311 operator uint32_t() const { return *mCounter; }
313 bool Modified() { return mHasModified; }
315 void SetModified(bool aModified) { mHasModified = aModified; }
317 void Reset() {
318 if (mHasModified) {
319 --(*mCounter);
321 mCounter = new RefCountedCounter();
322 mHasModified = false;
325 private:
326 class RefCountedCounter {
327 public:
328 NS_INLINE_DECL_REFCOUNTING(
329 mozilla::dom::HistoryEntryCounterForBrowsingContext::RefCountedCounter)
331 RefCountedCounter& operator++() {
332 ++mCounter;
333 return *this;
336 RefCountedCounter& operator--() {
337 --mCounter;
338 return *this;
341 operator uint32_t() const { return mCounter; }
343 private:
344 ~RefCountedCounter() = default;
346 uint32_t mCounter = 0;
349 RefPtr<RefCountedCounter> mCounter;
350 bool mHasModified;
353 // SessionHistoryEntry is used to store session history data in the parent
354 // process. It holds a SessionHistoryInfo, some state shared amongst multiple
355 // SessionHistoryEntries, a parent and children.
356 #define NS_SESSIONHISTORYENTRY_IID \
358 0x5b66a244, 0x8cec, 0x4caa, { \
359 0xaa, 0x0a, 0x78, 0x92, 0xfd, 0x17, 0xa6, 0x67 \
363 class SessionHistoryEntry : public nsISHEntry, public nsSupportsWeakReference {
364 public:
365 SessionHistoryEntry(nsDocShellLoadState* aLoadState, nsIChannel* aChannel);
366 SessionHistoryEntry();
367 explicit SessionHistoryEntry(SessionHistoryInfo* aInfo);
368 explicit SessionHistoryEntry(const SessionHistoryEntry& aEntry);
370 NS_DECL_ISUPPORTS
371 NS_DECL_NSISHENTRY
372 NS_DECLARE_STATIC_IID_ACCESSOR(NS_SESSIONHISTORYENTRY_IID)
374 bool IsInSessionHistory() {
375 SessionHistoryEntry* entry = this;
376 while (nsCOMPtr<SessionHistoryEntry> parent =
377 do_QueryReferent(entry->mParent)) {
378 entry = parent;
380 return entry->SharedInfo()->mSHistory &&
381 entry->SharedInfo()->mSHistory->IsAlive();
384 void ReplaceWith(const SessionHistoryEntry& aSource);
386 const SessionHistoryInfo& Info() const { return *mInfo; }
388 SHEntrySharedParentState* SharedInfo() const;
390 void SetFrameLoader(nsFrameLoader* aFrameLoader);
391 nsFrameLoader* GetFrameLoader();
393 void AddChild(SessionHistoryEntry* aChild, int32_t aOffset,
394 bool aUseRemoteSubframes);
395 void RemoveChild(SessionHistoryEntry* aChild);
396 // Finds the child with the same docshell ID as aNewChild, replaces it with
397 // aNewChild and returns true. If there is no child with the same docshell ID
398 // then it returns false.
399 bool ReplaceChild(SessionHistoryEntry* aNewChild);
401 void SetInfo(SessionHistoryInfo* aInfo);
403 bool ForInitialLoad() { return mForInitialLoad; }
404 void SetForInitialLoad(bool aForInitialLoad) {
405 mForInitialLoad = aForInitialLoad;
408 const nsID& DocshellID() const;
410 HistoryEntryCounterForBrowsingContext& BCHistoryLength() {
411 return mBCHistoryLength;
414 void SetBCHistoryLength(HistoryEntryCounterForBrowsingContext& aCounter) {
415 mBCHistoryLength.CopyValueFrom(aCounter);
418 void ClearBCHistoryLength() { mBCHistoryLength.Reset(); }
420 void SetIsDynamicallyAdded(bool aDynamic);
422 void SetWireframe(const Maybe<Wireframe>& aWireframe);
424 struct LoadingEntry {
425 // A pointer to the entry being loaded. Will be cleared by the
426 // SessionHistoryEntry destructor, at latest.
427 SessionHistoryEntry* mEntry;
428 // Snapshot of the entry's SessionHistoryInfo when the load started, to be
429 // used for validation purposes only.
430 UniquePtr<SessionHistoryInfo> mInfoSnapshotForValidation;
433 // Get an entry based on LoadingSessionHistoryInfo's mLoadId. Parent process
434 // only.
435 static LoadingEntry* GetByLoadId(uint64_t aLoadId);
436 static void SetByLoadId(uint64_t aLoadId, SessionHistoryEntry* aEntry);
437 static void RemoveLoadId(uint64_t aLoadId);
439 const nsTArray<RefPtr<SessionHistoryEntry>>& Children() { return mChildren; }
441 private:
442 friend struct LoadingSessionHistoryInfo;
443 virtual ~SessionHistoryEntry();
445 UniquePtr<SessionHistoryInfo> mInfo;
446 nsWeakPtr mParent;
447 uint32_t mID;
448 nsTArray<RefPtr<SessionHistoryEntry>> mChildren;
449 Maybe<Wireframe> mWireframe;
451 bool mForInitialLoad = false;
453 HistoryEntryCounterForBrowsingContext mBCHistoryLength;
455 static nsTHashMap<nsUint64HashKey, LoadingEntry>* sLoadIdToEntry;
458 NS_DEFINE_STATIC_IID_ACCESSOR(SessionHistoryEntry, NS_SESSIONHISTORYENTRY_IID)
460 } // namespace dom
462 namespace ipc {
464 class IProtocol;
466 // Allow sending SessionHistoryInfo objects over IPC.
467 template <>
468 struct IPDLParamTraits<dom::SessionHistoryInfo> {
469 static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor,
470 const dom::SessionHistoryInfo& aParam);
471 static bool Read(IPC::MessageReader* aReader, IProtocol* aActor,
472 dom::SessionHistoryInfo* aResult);
475 // Allow sending LoadingSessionHistoryInfo objects over IPC.
476 template <>
477 struct IPDLParamTraits<dom::LoadingSessionHistoryInfo> {
478 static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor,
479 const dom::LoadingSessionHistoryInfo& aParam);
480 static bool Read(IPC::MessageReader* aReader, IProtocol* aActor,
481 dom::LoadingSessionHistoryInfo* aResult);
484 // Allow sending nsILayoutHistoryState objects over IPC.
485 template <>
486 struct IPDLParamTraits<nsILayoutHistoryState*> {
487 static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor,
488 nsILayoutHistoryState* aParam);
489 static bool Read(IPC::MessageReader* aReader, IProtocol* aActor,
490 RefPtr<nsILayoutHistoryState>* aResult);
493 // Allow sending dom::Wireframe objects over IPC.
494 template <>
495 struct IPDLParamTraits<mozilla::dom::Wireframe> {
496 static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor,
497 const mozilla::dom::Wireframe& aParam);
498 static bool Read(IPC::MessageReader* aReader, IProtocol* aActor,
499 mozilla::dom::Wireframe* aResult);
502 } // namespace ipc
504 } // namespace mozilla
506 inline nsISupports* ToSupports(mozilla::dom::SessionHistoryEntry* aEntry) {
507 return static_cast<nsISHEntry*>(aEntry);
510 #endif /* mozilla_dom_SessionHistoryEntry_h */