tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */