tor-browser

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

SessionStorageManager.h (11853B)


      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_SessionStorageManager_h
      8 #define mozilla_dom_SessionStorageManager_h
      9 
     10 #include "StorageObserver.h"
     11 #include "mozilla/dom/FlippedOnce.h"
     12 #include "mozilla/ipc/PBackgroundChild.h"
     13 #include "mozilla/ipc/PBackgroundParent.h"
     14 #include "nsClassHashtable.h"
     15 #include "nsCycleCollectionParticipant.h"
     16 #include "nsHashKeys.h"
     17 #include "nsIDOMStorageManager.h"
     18 
     19 class nsIPrincipal;
     20 class nsITimer;
     21 
     22 namespace mozilla {
     23 class OriginAttributesPattern;
     24 
     25 namespace dom {
     26 
     27 class SSCacheCopy;
     28 
     29 bool RecvShutdownBackgroundSessionStorageManagers();
     30 void RecvPropagateBackgroundSessionStorageManager(uint64_t aCurrentTopContextId,
     31                                                  uint64_t aTargetTopContextId);
     32 bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId);
     33 
     34 bool RecvGetSessionStorageData(
     35    uint64_t aTopContextId, uint32_t aSizeLimit, bool aCancelSessionStoreTimer,
     36    ::mozilla::ipc::PBackgroundParent::GetSessionStorageManagerDataResolver&&
     37        aResolver);
     38 
     39 bool RecvLoadSessionStorageData(
     40    uint64_t aTopContextId,
     41    nsTArray<mozilla::dom::SSCacheCopy>&& aCacheCopyList);
     42 
     43 bool RecvClearStoragesForOrigin(const nsACString& aOriginAttrs,
     44                                const nsACString& aOriginKey);
     45 
     46 // DomainMatchingMode is used to allow ClearStorages to mimic one of
     47 // the LSNG behaviours - exact domain match.
     48 // When ClearStorages is invoked with EXACT_MATCH, it clears only the
     49 // data for a given domain, and would not affect any subdomains.
     50 // Currently EXACT_MATCH is only passed when browser:purge-sessionStorage event
     51 // is triggered. By default, ClearStorages is called with PREFIX_MATCH, which
     52 // clears data for a given domain and all the subdomains. This ensures that the
     53 // behaviour of other events that call ClearStorages remain unchanged.
     54 enum class DomainMatchingMode { PREFIX_MATCH, EXACT_MATCH };
     55 
     56 class BrowsingContext;
     57 class ContentParent;
     58 class SSSetItemInfo;
     59 class SSWriteInfo;
     60 class SessionStorageCache;
     61 class SessionStorageCacheChild;
     62 class SessionStorageManagerChild;
     63 class SessionStorageManagerParent;
     64 class SessionStorageObserver;
     65 struct OriginRecord;
     66 
     67 // sessionStorage is a data store that's unique to each tab (i.e. top-level
     68 // browsing context) and origin. Before the advent of Fission all the data
     69 // for a given tab could be stored in a single content process; now each
     70 // site-specific process stores only its portion of the data. As content
     71 // processes terminate, their sessionStorage data needs to be saved in the
     72 // parent process, in case the same origin appears again in the tab (e.g.
     73 // by navigating an iframe element). Therefore SessionStorageManager
     74 // objects exist in both the parent and content processes.
     75 //
     76 // Whenever a write operation for SessionStorage executes, the content process
     77 // sends the changes to the parent process at the next stable state. Whenever a
     78 // content process navigates to an origin for the first time in a given tab, the
     79 // parent process sends it the saved data. SessionStorageCache has a flag
     80 // (mLoadedOrCloned) to ensure that it's only be loaded or cloned once.
     81 //
     82 // Note: the current implementation is expected to be replaced by a new
     83 // implementation using LSNG.
     84 class SessionStorageManagerBase {
     85 public:
     86  SessionStorageManagerBase() = default;
     87 
     88 protected:
     89  ~SessionStorageManagerBase() = default;
     90 
     91  struct OriginRecord {
     92    OriginRecord() = default;
     93    OriginRecord(OriginRecord&&) = default;
     94    OriginRecord& operator=(OriginRecord&&) = default;
     95    ~OriginRecord();
     96 
     97    RefPtr<SessionStorageCache> mCache;
     98 
     99    // A flag to ensure that cache is only loaded once.
    100    FlippedOnce<false> mLoaded;
    101  };
    102 
    103  void ClearStoragesInternal(
    104      const OriginAttributesPattern& aPattern, const nsACString& aOriginScope,
    105      DomainMatchingMode aMode = DomainMatchingMode::PREFIX_MATCH);
    106 
    107  void ClearStoragesForOriginInternal(const nsACString& aOriginAttrs,
    108                                      const nsACString& aOriginKey);
    109 
    110  OriginRecord* GetOriginRecord(const nsACString& aOriginAttrs,
    111                                const nsACString& aOriginKey,
    112                                bool aMakeIfNeeded,
    113                                SessionStorageCache* aCloneFrom);
    114 
    115  using OriginKeyHashTable = nsClassHashtable<nsCStringHashKey, OriginRecord>;
    116  nsClassHashtable<nsCStringHashKey, OriginKeyHashTable> mOATable;
    117 };
    118 
    119 class SessionStorageManager final : public SessionStorageManagerBase,
    120                                    public nsIDOMSessionStorageManager,
    121                                    public StorageObserverSink {
    122 public:
    123  explicit SessionStorageManager(RefPtr<BrowsingContext> aBrowsingContext);
    124 
    125  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    126  NS_DECL_NSIDOMSTORAGEMANAGER
    127  NS_DECL_NSIDOMSESSIONSTORAGEMANAGER
    128 
    129  NS_DECL_CYCLE_COLLECTION_CLASS(SessionStorageManager)
    130 
    131  bool CanLoadData();
    132 
    133  void SetActor(SessionStorageManagerChild* aActor);
    134 
    135  bool ActorExists() const;
    136 
    137  void ClearActor();
    138 
    139  nsresult EnsureManager();
    140 
    141  nsresult LoadData(nsIPrincipal& aPrincipal, SessionStorageCache& aCache);
    142 
    143  void CheckpointData(nsIPrincipal& aPrincipal, SessionStorageCache& aCache);
    144 
    145  nsresult ClearStoragesForOrigin(const nsACString& aOriginAttrs,
    146                                  const nsACString& aOriginKey);
    147 
    148 private:
    149  ~SessionStorageManager();
    150 
    151  // StorageObserverSink, handler to various chrome clearing notification
    152  nsresult Observe(const char* aTopic,
    153                   const nsAString& aOriginAttributesPattern,
    154                   const nsACString& aOriginScope) override;
    155 
    156  nsresult GetSessionStorageCacheHelper(nsIPrincipal* aPrincipal,
    157                                        bool aMakeIfNeeded,
    158                                        SessionStorageCache* aCloneFrom,
    159                                        RefPtr<SessionStorageCache>* aRetVal);
    160 
    161  nsresult GetSessionStorageCacheHelper(const nsACString& aOriginAttrs,
    162                                        const nsACString& aOriginKey,
    163                                        bool aMakeIfNeeded,
    164                                        SessionStorageCache* aCloneFrom,
    165                                        RefPtr<SessionStorageCache>* aRetVal);
    166 
    167  void ClearStorages(
    168      const OriginAttributesPattern& aPattern, const nsACString& aOriginScope,
    169      DomainMatchingMode aMode = DomainMatchingMode::PREFIX_MATCH);
    170 
    171  SessionStorageCacheChild* EnsureCache(nsIPrincipal& aPrincipal,
    172                                        const nsACString& aOriginKey,
    173                                        SessionStorageCache& aCache);
    174 
    175  void CheckpointDataInternal(nsIPrincipal& aPrincipal,
    176                              const nsACString& aOriginKey,
    177                              SessionStorageCache& aCache);
    178 
    179  RefPtr<SessionStorageObserver> mObserver;
    180 
    181  RefPtr<BrowsingContext> mBrowsingContext;
    182 
    183  SessionStorageManagerChild* mActor;
    184 };
    185 
    186 /**
    187 * A specialized SessionStorageManager class that lives on the parent process
    188 * background thread. It is a shadow copy of SessionStorageManager and it's used
    189 * to preserve SessionStorageCaches for the other SessionStorageManagers.
    190 */
    191 class BackgroundSessionStorageManager final : public SessionStorageManagerBase {
    192 public:
    193  // Parent process getter function.
    194  static BackgroundSessionStorageManager* GetOrCreate(uint64_t aTopContextId);
    195 
    196  NS_INLINE_DECL_REFCOUNTING(BackgroundSessionStorageManager);
    197 
    198  // Only called by CanonicalBrowsingContext::ReplaceBy on the parent process.
    199  static void PropagateManager(uint64_t aCurrentTopContextId,
    200                               uint64_t aTargetTopContextId);
    201 
    202  // Only called by CanonicalBrowsingContext::CanonicalDiscard on parent
    203  // process.
    204  static void RemoveManager(uint64_t aTopContextId);
    205 
    206  static void LoadData(
    207      uint64_t aTopContextId,
    208      const nsTArray<mozilla::dom::SSCacheCopy>& aCacheCopyList);
    209 
    210  using DataPromise =
    211      ::mozilla::ipc::PBackgroundChild::GetSessionStorageManagerDataPromise;
    212  static RefPtr<DataPromise> GetData(BrowsingContext* aContext,
    213                                     uint32_t aSizeLimit,
    214                                     bool aClearSessionStoreTimer = false);
    215 
    216  void GetData(uint32_t aSizeLimit, nsTArray<SSCacheCopy>& aCacheCopyList);
    217 
    218  void CopyDataToContentProcess(const nsACString& aOriginAttrs,
    219                                const nsACString& aOriginKey,
    220                                nsTArray<SSSetItemInfo>& aData);
    221 
    222  void UpdateData(const nsACString& aOriginAttrs, const nsACString& aOriginKey,
    223                  const nsTArray<SSWriteInfo>& aWriteInfos);
    224 
    225  void UpdateData(const nsACString& aOriginAttrs, const nsACString& aOriginKey,
    226                  const nsTArray<SSSetItemInfo>& aData);
    227 
    228  void ClearStorages(
    229      const OriginAttributesPattern& aPattern, const nsACString& aOriginScope,
    230      DomainMatchingMode aMode = DomainMatchingMode::PREFIX_MATCH);
    231 
    232  void ClearStoragesForOrigin(const nsACString& aOriginAttrs,
    233                              const nsACString& aOriginKey);
    234 
    235  void SetCurrentBrowsingContextId(uint64_t aBrowsingContextId);
    236 
    237  void MaybeDispatchSessionStoreUpdate();
    238 
    239  void CancelSessionStoreUpdate();
    240 
    241  void AddParticipatingActor(SessionStorageManagerParent* aActor);
    242 
    243  void RemoveParticipatingActor(SessionStorageManagerParent* aActor);
    244 
    245 private:
    246  // Only be called by GetOrCreate() on the parent process.
    247  explicit BackgroundSessionStorageManager(uint64_t aBrowsingContextId);
    248 
    249  ~BackgroundSessionStorageManager();
    250 
    251  // Sets a timer for notifying main thread that the cache has been
    252  // updated. May do nothing if we're coalescing notifications.
    253  void MaybeScheduleSessionStoreUpdate();
    254 
    255  void DispatchSessionStoreUpdate();
    256 
    257  // The most current browsing context using this manager
    258  uint64_t mCurrentBrowsingContextId;
    259 
    260  // Callback for notifying main thread of calls to `UpdateData`.
    261  //
    262  // A timer that is held whenever this manager has dirty state that
    263  // has not yet been reflected to the main thread. The timer is used
    264  // to delay notifying the main thread to ask for changes, thereby
    265  // coalescing/throttling changes. (Note that SessionStorage, like
    266  // LocalStorage, treats attempts to set a value to its current value
    267  // as a no-op.)
    268  //
    269 
    270  // The timer is initialized with a fixed delay as soon as the state
    271  // becomes dirty; additional mutations to our state will not reset
    272  // the timer because then we might never flush to the main
    273  // thread. The timer is cleared only when a new set of data is sent
    274  // to the main thread and therefore this manager no longer has any
    275  // dirty state. This means that there is a period of time after the
    276  // nsITimer fires where this value is non-null but there is no
    277  // scheduled timer while we wait for the main thread to request the
    278  // new state. Callers of GetData can also optionally cancel the
    279  // current timer to reduce the amounts of notifications.
    280  //
    281  // When this manager is moved to a new top-level browsing context id
    282  // via a PropagateBackgroundSessionStorageManager message, the
    283  // behavior of the timer doesn't change because the main thread knows
    284  // about the renaming and is initiating it (and any in-flight
    285  // GetSessionStorageManagerData requests will be unaffected because
    286  // they use async-returns so the response is inherently matched up via
    287  // the issued promise).
    288  nsCOMPtr<nsITimer> mSessionStoreCallbackTimer;
    289 
    290  nsTArray<RefPtr<SessionStorageManagerParent>> mParticipatingActors;
    291 };
    292 
    293 }  // namespace dom
    294 }  // namespace mozilla
    295 
    296 #endif  // mozilla_dom_SessionStorageManager_h