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
;
23 class nsIReferrerInfo
;
27 namespace mozilla::ipc
{
29 struct IPDLParamTraits
;
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
{
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
) {
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
; }
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
;
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;
194 explicit SharedState(const SharedState
& aOther
);
195 explicit SharedState(const Maybe
<const SharedState
&>& aOther
);
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
);
213 explicit SharedState(SHEntrySharedParentState
* aParent
)
214 : mParent(aParent
) {}
215 explicit SharedState(UniquePtr
<SHEntrySharedState
>&& aChild
)
216 : mChild(std::move(aChild
)) {}
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.
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
{
276 HistoryEntryCounterForBrowsingContext()
277 : mCounter(new RefCountedCounter()), mHasModified(false) {
281 HistoryEntryCounterForBrowsingContext(
282 const HistoryEntryCounterForBrowsingContext
& aOther
)
283 : mCounter(aOther
.mCounter
), mHasModified(false) {}
285 HistoryEntryCounterForBrowsingContext(
286 HistoryEntryCounterForBrowsingContext
&& aOther
) = delete;
288 ~HistoryEntryCounterForBrowsingContext() {
294 void CopyValueFrom(const HistoryEntryCounterForBrowsingContext
& aOther
) {
298 mCounter
= aOther
.mCounter
;
299 mHasModified
= false;
302 HistoryEntryCounterForBrowsingContext
& operator=(
303 const HistoryEntryCounterForBrowsingContext
& aOther
) = delete;
305 HistoryEntryCounterForBrowsingContext
& operator++() {
311 operator uint32_t() const { return *mCounter
; }
313 bool Modified() { return mHasModified
; }
315 void SetModified(bool aModified
) { mHasModified
= aModified
; }
321 mCounter
= new RefCountedCounter();
322 mHasModified
= false;
326 class RefCountedCounter
{
328 NS_INLINE_DECL_REFCOUNTING(
329 mozilla::dom::HistoryEntryCounterForBrowsingContext::RefCountedCounter
)
331 RefCountedCounter
& operator++() {
336 RefCountedCounter
& operator--() {
341 operator uint32_t() const { return mCounter
; }
344 ~RefCountedCounter() = default;
346 uint32_t mCounter
= 0;
349 RefPtr
<RefCountedCounter
> mCounter
;
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
{
365 SessionHistoryEntry(nsDocShellLoadState
* aLoadState
, nsIChannel
* aChannel
);
366 SessionHistoryEntry();
367 explicit SessionHistoryEntry(SessionHistoryInfo
* aInfo
);
368 explicit SessionHistoryEntry(const SessionHistoryEntry
& aEntry
);
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
)) {
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
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
; }
442 friend struct LoadingSessionHistoryInfo
;
443 virtual ~SessionHistoryEntry();
445 UniquePtr
<SessionHistoryInfo
> mInfo
;
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
)
466 // Allow sending SessionHistoryInfo objects over IPC.
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.
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.
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.
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
);
504 } // namespace mozilla
506 inline nsISupports
* ToSupports(mozilla::dom::SessionHistoryEntry
* aEntry
) {
507 return static_cast<nsISHEntry
*>(aEntry
);
510 #endif /* mozilla_dom_SessionHistoryEntry_h */