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