DOMStorageCache.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef nsDOMStorageCache_h___
  6. #define nsDOMStorageCache_h___
  7. #include "nsIPrincipal.h"
  8. #include "nsITimer.h"
  9. #include "nsString.h"
  10. #include "nsDataHashtable.h"
  11. #include "nsHashKeys.h"
  12. #include "mozilla/Monitor.h"
  13. #include "mozilla/Atomics.h"
  14. namespace mozilla {
  15. namespace dom {
  16. class DOMStorage;
  17. class DOMStorageUsage;
  18. class DOMStorageManager;
  19. class DOMStorageDBBridge;
  20. // Interface class on which only the database or IPC may call.
  21. // Used to populate the cache with DB data.
  22. class DOMStorageCacheBridge
  23. {
  24. public:
  25. NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
  26. NS_IMETHOD_(void) Release(void);
  27. // The origin of the cache, result is concatenation of OriginNoSuffix() and OriginSuffix(),
  28. // see below.
  29. virtual const nsCString Origin() const = 0;
  30. // The origin attributes suffix alone, this is usually passed as an |aOriginSuffix|
  31. // argument to various methods
  32. virtual const nsCString& OriginSuffix() const = 0;
  33. // The origin in the database usage format (reversed) and without the suffix
  34. virtual const nsCString& OriginNoSuffix() const = 0;
  35. // Whether the cache is already fully loaded
  36. virtual bool Loaded() = 0;
  37. // How many items has so far been loaded into the cache, used
  38. // for optimization purposes
  39. virtual uint32_t LoadedCount() = 0;
  40. // Called by the database to load a key and its value to the cache
  41. virtual bool LoadItem(const nsAString& aKey, const nsString& aValue) = 0;
  42. // Called by the database after all keys and values has been loaded
  43. // to this cache
  44. virtual void LoadDone(nsresult aRv) = 0;
  45. // Use to synchronously wait until the cache gets fully loaded with data,
  46. // this method exits after LoadDone has been called
  47. virtual void LoadWait() = 0;
  48. protected:
  49. virtual ~DOMStorageCacheBridge() {}
  50. ThreadSafeAutoRefCnt mRefCnt;
  51. NS_DECL_OWNINGTHREAD
  52. };
  53. // Implementation of scope cache that is responsible for preloading data
  54. // for persistent storage (localStorage) and hold data for non-private,
  55. // private and session-only cookie modes. It is also responsible for
  56. // persisting data changes using the database, works as a write-back cache.
  57. class DOMStorageCache : public DOMStorageCacheBridge
  58. {
  59. public:
  60. NS_IMETHOD_(void) Release(void);
  61. // Note: We pass aOriginNoSuffix through the ctor here, because
  62. // DOMStorageCacheHashKey's ctor is creating this class and
  63. // accepts reversed-origin-no-suffix as an argument - the hashing key.
  64. explicit DOMStorageCache(const nsACString* aOriginNoSuffix);
  65. protected:
  66. virtual ~DOMStorageCache();
  67. public:
  68. void Init(DOMStorageManager* aManager, bool aPersistent, nsIPrincipal* aPrincipal,
  69. const nsACString& aQuotaOriginScope);
  70. // Copies all data from the other storage.
  71. void CloneFrom(const DOMStorageCache* aThat);
  72. // Starts async preload of this cache if it persistent and not loaded.
  73. void Preload();
  74. // Keeps the cache alive (i.e. present in the manager's hash table) for a time.
  75. void KeepAlive();
  76. // The set of methods that are invoked by DOM storage web API.
  77. // We are passing the DOMStorage object just to let the cache
  78. // read properties like mPrivate, mPrincipal and mSessionOnly.
  79. // Get* methods return error when load from the database has failed.
  80. nsresult GetLength(const DOMStorage* aStorage, uint32_t* aRetval);
  81. nsresult GetKey(const DOMStorage* aStorage, uint32_t index, nsAString& aRetval);
  82. nsresult GetItem(const DOMStorage* aStorage, const nsAString& aKey, nsAString& aRetval);
  83. nsresult SetItem(const DOMStorage* aStorage, const nsAString& aKey, const nsString& aValue, nsString& aOld);
  84. nsresult RemoveItem(const DOMStorage* aStorage, const nsAString& aKey, nsString& aOld);
  85. nsresult Clear(const DOMStorage* aStorage);
  86. void GetKeys(const DOMStorage* aStorage, nsTArray<nsString>& aKeys);
  87. // Whether the principal equals principal the cache was created for
  88. bool CheckPrincipal(nsIPrincipal* aPrincipal) const;
  89. nsIPrincipal* Principal() const { return mPrincipal; }
  90. // Starts the database engine thread or the IPC bridge
  91. static DOMStorageDBBridge* StartDatabase();
  92. static DOMStorageDBBridge* GetDatabase();
  93. // Stops the thread and flushes all uncommited data
  94. static nsresult StopDatabase();
  95. // DOMStorageCacheBridge
  96. virtual const nsCString Origin() const;
  97. virtual const nsCString& OriginNoSuffix() const { return mOriginNoSuffix; }
  98. virtual const nsCString& OriginSuffix() const { return mOriginSuffix; }
  99. virtual bool Loaded() { return mLoaded; }
  100. virtual uint32_t LoadedCount();
  101. virtual bool LoadItem(const nsAString& aKey, const nsString& aValue);
  102. virtual void LoadDone(nsresult aRv);
  103. virtual void LoadWait();
  104. // Cache keeps 3 sets of data: regular, private and session-only.
  105. // This class keeps keys and values for a set and also caches
  106. // size of the data for quick per-origin quota checking.
  107. class Data
  108. {
  109. public:
  110. Data() : mOriginQuotaUsage(0) {}
  111. int64_t mOriginQuotaUsage;
  112. nsDataHashtable<nsStringHashKey, nsString> mKeys;
  113. };
  114. public:
  115. // Number of data sets we keep: default, private, session
  116. static const uint32_t kDataSetCount = 3;
  117. private:
  118. // API to clear the cache data, this is invoked by chrome operations
  119. // like cookie deletion.
  120. friend class DOMStorageManager;
  121. static const uint32_t kUnloadDefault = 1 << 0;
  122. static const uint32_t kUnloadPrivate = 1 << 1;
  123. static const uint32_t kUnloadSession = 1 << 2;
  124. static const uint32_t kUnloadComplete =
  125. kUnloadDefault | kUnloadPrivate | kUnloadSession;
  126. #ifdef DOM_STORAGE_TESTS
  127. static const uint32_t kTestReload = 1 << 15;
  128. #endif
  129. void UnloadItems(uint32_t aUnloadFlags);
  130. private:
  131. // Synchronously blocks until the cache is fully loaded from the database
  132. void WaitForPreload();
  133. // Helper to get one of the 3 data sets (regular, private, session)
  134. Data& DataSet(const DOMStorage* aStorage);
  135. // Whether the storage change is about to persist
  136. bool Persist(const DOMStorage* aStorage) const;
  137. // Changes the quota usage on the given data set if it fits the quota.
  138. // If not, then false is returned and no change to the set must be done.
  139. bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta);
  140. bool ProcessUsageDelta(const DOMStorage* aStorage, const int64_t aDelta);
  141. private:
  142. // When a cache is reponsible for its life time (in case of localStorage data
  143. // cache) we need to refer our manager since removal of the cache from the hash
  144. // table is handled in the destructor by call to the manager.
  145. // Cache could potentially overlive the manager, hence the hard ref.
  146. RefPtr<DOMStorageManager> mManager;
  147. // Reference to the usage counter object we check on for eTLD+1 quota limit.
  148. // Obtained from the manager during initialization (Init method).
  149. RefPtr<DOMStorageUsage> mUsage;
  150. // Timer that holds this cache alive for a while after it has been preloaded.
  151. nsCOMPtr<nsITimer> mKeepAliveTimer;
  152. // Principal the cache has been initially created for, this is used only
  153. // for sessionStorage access checks since sessionStorage objects are strictly
  154. // scoped by a principal. localStorage objects on the other hand are scoped by
  155. // origin only.
  156. nsCOMPtr<nsIPrincipal> mPrincipal;
  157. // The origin this cache belongs to in the "DB format", i.e. reversed
  158. nsCString mOriginNoSuffix;
  159. // The origin attributes suffix
  160. nsCString mOriginSuffix;
  161. // The eTLD+1 scope used to count quota usage. It is in the reversed format
  162. // and contains the origin attributes suffix.
  163. nsCString mQuotaOriginScope;
  164. // Non-private Browsing, Private Browsing and Session Only sets.
  165. Data mData[kDataSetCount];
  166. // This monitor is used to wait for full load of data.
  167. mozilla::Monitor mMonitor;
  168. // Flag that is initially false. When the cache is about to work with
  169. // the database (i.e. it is persistent) this flags is set to true after
  170. // all keys and coresponding values are loaded from the database.
  171. // This flag never goes from true back to false. Since this flag is
  172. // critical for mData hashtable synchronization, it's made atomic.
  173. Atomic<bool, ReleaseAcquire> mLoaded;
  174. // Result of load from the database. Valid after mLoaded flag has been set.
  175. nsresult mLoadResult;
  176. // Init() method has been called
  177. bool mInitialized : 1;
  178. // This cache is about to be bound with the database (i.e. it has
  179. // to load from the DB first and has to persist when modifying the
  180. // default data set.)
  181. bool mPersistent : 1;
  182. // - False when the session-only data set was never used.
  183. // - True after access to session-only data has been made for the first time.
  184. // We also fill session-only data set with the default one at that moment.
  185. // Drops back to false when session-only data are cleared from chrome.
  186. bool mSessionOnlyDataSetActive : 1;
  187. // DOMStorageDBThread on the parent or single process,
  188. // DOMStorageDBChild on the child process.
  189. static DOMStorageDBBridge* sDatabase;
  190. // False until we shut the database down.
  191. static bool sDatabaseDown;
  192. };
  193. // DOMStorageUsage
  194. // Infrastructure to manage and check eTLD+1 quota
  195. class DOMStorageUsageBridge
  196. {
  197. public:
  198. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DOMStorageUsageBridge)
  199. virtual const nsCString& OriginScope() = 0;
  200. virtual void LoadUsage(const int64_t aUsage) = 0;
  201. protected:
  202. // Protected destructor, to discourage deletion outside of Release():
  203. virtual ~DOMStorageUsageBridge() {}
  204. };
  205. class DOMStorageUsage : public DOMStorageUsageBridge
  206. {
  207. public:
  208. explicit DOMStorageUsage(const nsACString& aOriginScope);
  209. bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta);
  210. private:
  211. virtual const nsCString& OriginScope() { return mOriginScope; }
  212. virtual void LoadUsage(const int64_t aUsage);
  213. nsCString mOriginScope;
  214. int64_t mUsage[DOMStorageCache::kDataSetCount];
  215. };
  216. } // namespace dom
  217. } // namespace mozilla
  218. #endif