1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/src/storage/DOMStorageCache.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,273 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef nsDOMStorageCache_h___ 1.10 +#define nsDOMStorageCache_h___ 1.11 + 1.12 +#include "nsIURI.h" 1.13 +#include "nsIPrincipal.h" 1.14 +#include "nsITimer.h" 1.15 + 1.16 +#include "nsString.h" 1.17 +#include "nsDataHashtable.h" 1.18 +#include "nsHashKeys.h" 1.19 +#include "mozilla/Monitor.h" 1.20 +#include "mozilla/Telemetry.h" 1.21 +#include "nsAutoPtr.h" 1.22 + 1.23 +namespace mozilla { 1.24 +namespace dom { 1.25 + 1.26 +class DOMStorage; 1.27 +class DOMStorageUsage; 1.28 +class DOMStorageManager; 1.29 +class DOMStorageDBBridge; 1.30 + 1.31 +// Interface class on which only the database or IPC may call. 1.32 +// Used to populate the cache with DB data. 1.33 +class DOMStorageCacheBridge 1.34 +{ 1.35 +public: 1.36 + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); 1.37 + NS_IMETHOD_(void) Release(void); 1.38 + 1.39 + virtual ~DOMStorageCacheBridge() {} 1.40 + 1.41 + // The scope (origin) in the database usage format (reversed) 1.42 + virtual const nsCString& Scope() const = 0; 1.43 + 1.44 + // Whether the cache is already fully loaded 1.45 + virtual bool Loaded() = 0; 1.46 + 1.47 + // How many items has so far been loaded into the cache, used 1.48 + // for optimization purposes 1.49 + virtual uint32_t LoadedCount() = 0; 1.50 + 1.51 + // Called by the database to load a key and its value to the cache 1.52 + virtual bool LoadItem(const nsAString& aKey, const nsString& aValue) = 0; 1.53 + 1.54 + // Called by the database after all keys and values has been loaded 1.55 + // to this cache 1.56 + virtual void LoadDone(nsresult aRv) = 0; 1.57 + 1.58 + // Use to synchronously wait until the cache gets fully loaded with data, 1.59 + // this method exits after LoadDone has been called 1.60 + virtual void LoadWait() = 0; 1.61 + 1.62 +protected: 1.63 + ThreadSafeAutoRefCnt mRefCnt; 1.64 + NS_DECL_OWNINGTHREAD 1.65 +}; 1.66 + 1.67 +// Implementation of scope cache that is responsible for preloading data 1.68 +// for persistent storage (localStorage) and hold data for non-private, 1.69 +// private and session-only cookie modes. It is also responsible for 1.70 +// persisting data changes using the database, works as a write-back cache. 1.71 +class DOMStorageCache : public DOMStorageCacheBridge 1.72 +{ 1.73 +public: 1.74 + NS_IMETHOD_(void) Release(void); 1.75 + 1.76 + DOMStorageCache(const nsACString* aScope); 1.77 + virtual ~DOMStorageCache(); 1.78 + 1.79 + void Init(DOMStorageManager* aManager, bool aPersistent, 1.80 + nsIURI* aFirstPartyIsolationURI, nsIPrincipal* aPrincipal, 1.81 + const nsACString& aQuotaScope); 1.82 + 1.83 + // Copies all data from the other storage. 1.84 + void CloneFrom(const DOMStorageCache* aThat); 1.85 + 1.86 + // Starts async preload of this cache if it persistent and not loaded. 1.87 + void Preload(); 1.88 + 1.89 + // Keeps the cache alive (i.e. present in the manager's hash table) for a time. 1.90 + void KeepAlive(); 1.91 + 1.92 + // The set of methods that are invoked by DOM storage web API. 1.93 + // We are passing the DOMStorage object just to let the cache 1.94 + // read properties like mPrivate and mSessionOnly. 1.95 + // Get* methods return error when load from the database has failed. 1.96 + nsresult GetLength(const DOMStorage* aStorage, uint32_t* aRetval); 1.97 + nsresult GetKey(const DOMStorage* aStorage, uint32_t index, nsAString& aRetval); 1.98 + nsresult GetItem(const DOMStorage* aStorage, const nsAString& aKey, nsAString& aRetval); 1.99 + nsresult SetItem(const DOMStorage* aStorage, const nsAString& aKey, const nsString& aValue, nsString& aOld); 1.100 + nsresult RemoveItem(const DOMStorage* aStorage, const nsAString& aKey, nsString& aOld); 1.101 + nsresult Clear(const DOMStorage* aStorage); 1.102 + 1.103 + nsTArray<nsString>* GetKeys(const DOMStorage* aStorage); 1.104 + 1.105 + nsIURI* FirstPartyIsolationURI() const { return mFirstPartyIsolationURI; } 1.106 + 1.107 + // Whether the principal equals principal the cache was created for 1.108 + bool CheckPrincipal(nsIPrincipal* aPrincipal) const; 1.109 + nsIPrincipal* Principal() const { return mPrincipal; } 1.110 + 1.111 + // Starts the database engine thread or the IPC bridge 1.112 + static DOMStorageDBBridge* StartDatabase(); 1.113 + static DOMStorageDBBridge* GetDatabase(); 1.114 + 1.115 + // Stops the thread and flushes all uncommited data 1.116 + static nsresult StopDatabase(); 1.117 + 1.118 + // DOMStorageCacheBridge 1.119 + 1.120 + virtual const nsCString& Scope() const { return mScope; } 1.121 + virtual bool Loaded() { return mLoaded; } 1.122 + virtual uint32_t LoadedCount(); 1.123 + virtual bool LoadItem(const nsAString& aKey, const nsString& aValue); 1.124 + virtual void LoadDone(nsresult aRv); 1.125 + virtual void LoadWait(); 1.126 + 1.127 + // Cache keeps 3 sets of data: regular, private and session-only. 1.128 + // This class keeps keys and values for a set and also caches 1.129 + // size of the data for quick per-origin quota checking. 1.130 + class Data 1.131 + { 1.132 + public: 1.133 + Data() : mOriginQuotaUsage(0) {} 1.134 + int64_t mOriginQuotaUsage; 1.135 + nsDataHashtable<nsStringHashKey, nsString> mKeys; 1.136 + }; 1.137 + 1.138 +public: 1.139 + // Number of data sets we keep: default, private, session 1.140 + static const uint32_t kDataSetCount = 3; 1.141 + 1.142 +private: 1.143 + // API to clear the cache data, this is invoked by chrome operations 1.144 + // like cookie deletion. 1.145 + friend class DOMStorageManager; 1.146 + 1.147 + static const uint32_t kUnloadDefault = 1 << 0; 1.148 + static const uint32_t kUnloadPrivate = 1 << 1; 1.149 + static const uint32_t kUnloadSession = 1 << 2; 1.150 + static const uint32_t kUnloadComplete = 1.151 + kUnloadDefault | kUnloadPrivate | kUnloadSession; 1.152 + 1.153 +#ifdef DOM_STORAGE_TESTS 1.154 + static const uint32_t kTestReload = 1 << 15; 1.155 +#endif 1.156 + 1.157 + void UnloadItems(uint32_t aUnloadFlags); 1.158 + 1.159 +private: 1.160 + // Synchronously blocks until the cache is fully loaded from the database 1.161 + void WaitForPreload(mozilla::Telemetry::ID aTelemetryID); 1.162 + 1.163 + // Helper to get one of the 3 data sets (regular, private, session) 1.164 + Data& DataSet(const DOMStorage* aStorage); 1.165 + 1.166 + // Whether the storage change is about to persist 1.167 + bool Persist(const DOMStorage* aStorage) const; 1.168 + 1.169 + // Changes the quota usage on the given data set if it fits the quota. 1.170 + // If not, then false is returned and no change to the set must be done. 1.171 + bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta); 1.172 + bool ProcessUsageDelta(const DOMStorage* aStorage, const int64_t aDelta); 1.173 + 1.174 +private: 1.175 + // When a cache is reponsible for its life time (in case of localStorage data 1.176 + // cache) we need to refer our manager since removal of the cache from the hash 1.177 + // table is handled in the destructor by call to the manager. 1.178 + // Cache could potentially overlive the manager, hence the hard ref. 1.179 + nsRefPtr<DOMStorageManager> mManager; 1.180 + 1.181 + // Reference to the usage counter object we check on for eTLD+1 quota limit. 1.182 + // Obtained from the manager during initialization (Init method). 1.183 + nsRefPtr<DOMStorageUsage> mUsage; 1.184 + 1.185 + // Timer that holds this cache alive for a while after it has been preloaded. 1.186 + nsCOMPtr<nsITimer> mKeepAliveTimer; 1.187 + 1.188 + // The first party URI associated with this cache. 1.189 + nsCOMPtr<nsIURI> mFirstPartyIsolationURI; 1.190 + 1.191 + // Principal the cache has been initially created for, this is used only 1.192 + // for sessionStorage access checks since sessionStorage objects are strictly 1.193 + // scoped by a principal. localStorage objects on the other hand are scoped by 1.194 + // origin only. 1.195 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.196 + 1.197 + // The scope this cache belongs to in the "DB format", i.e. reversed 1.198 + nsCString mScope; 1.199 + 1.200 + // The eTLD+1 scope used to count quota usage. 1.201 + nsCString mQuotaScope; 1.202 + 1.203 + // Non-private Browsing, Private Browsing and Session Only sets. 1.204 + Data mData[kDataSetCount]; 1.205 + 1.206 + // This monitor is used to wait for full load of data. 1.207 + mozilla::Monitor mMonitor; 1.208 + 1.209 + // Flag that is initially false. When the cache is about to work with 1.210 + // the database (i.e. it is persistent) this flags is set to true after 1.211 + // all keys and coresponding values are loaded from the database. 1.212 + // This flag never goes from true back to false. 1.213 + bool mLoaded; 1.214 + 1.215 + // Result of load from the database. Valid after mLoaded flag has been set. 1.216 + nsresult mLoadResult; 1.217 + 1.218 + // Init() method has been called 1.219 + bool mInitialized : 1; 1.220 + 1.221 + // This cache is about to be bound with the database (i.e. it has 1.222 + // to load from the DB first and has to persist when modifying the 1.223 + // default data set.) 1.224 + bool mPersistent : 1; 1.225 + 1.226 + // - False when the session-only data set was never used. 1.227 + // - True after access to session-only data has been made for the first time. 1.228 + // We also fill session-only data set with the default one at that moment. 1.229 + // Drops back to false when session-only data are cleared from chrome. 1.230 + bool mSessionOnlyDataSetActive : 1; 1.231 + 1.232 + // Whether we have already captured state of the cache preload on our first access. 1.233 + bool mPreloadTelemetryRecorded : 1; 1.234 + 1.235 + // DOMStorageDBThread on the parent or single process, 1.236 + // DOMStorageDBChild on the child process. 1.237 + static DOMStorageDBBridge* sDatabase; 1.238 + 1.239 + // False until we shut the database down. 1.240 + static bool sDatabaseDown; 1.241 +}; 1.242 + 1.243 +// DOMStorageUsage 1.244 +// Infrastructure to manage and check eTLD+1 quota 1.245 +class DOMStorageUsageBridge 1.246 +{ 1.247 +public: 1.248 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DOMStorageUsageBridge) 1.249 + 1.250 + virtual const nsCString& Scope() = 0; 1.251 + virtual void LoadUsage(const int64_t aUsage) = 0; 1.252 + 1.253 +protected: 1.254 + // Protected destructor, to discourage deletion outside of Release(): 1.255 + virtual ~DOMStorageUsageBridge() {} 1.256 +}; 1.257 + 1.258 +class DOMStorageUsage : public DOMStorageUsageBridge 1.259 +{ 1.260 +public: 1.261 + DOMStorageUsage(const nsACString& aScope); 1.262 + 1.263 + bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta); 1.264 + 1.265 +private: 1.266 + virtual const nsCString& Scope() { return mScope; } 1.267 + virtual void LoadUsage(const int64_t aUsage); 1.268 + 1.269 + nsCString mScope; 1.270 + int64_t mUsage[DOMStorageCache::kDataSetCount]; 1.271 +}; 1.272 + 1.273 +} // ::dom 1.274 +} // ::mozilla 1.275 + 1.276 +#endif