LCOV - code coverage report
Current view: top level - dom/storage - LocalStorageCache.h (source / functions) Hit Total Coverage
Test: output.info Lines: 9 12 75.0 %
Date: 2017-07-14 16:53:18 Functions: 10 16 62.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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_LocalStorageCache_h
       8             : #define mozilla_dom_LocalStorageCache_h
       9             : 
      10             : #include "nsIPrincipal.h"
      11             : #include "nsITimer.h"
      12             : 
      13             : #include "nsString.h"
      14             : #include "nsDataHashtable.h"
      15             : #include "nsHashKeys.h"
      16             : #include "mozilla/Monitor.h"
      17             : #include "mozilla/Telemetry.h"
      18             : #include "mozilla/Atomics.h"
      19             : 
      20             : namespace mozilla {
      21             : namespace dom {
      22             : 
      23             : class LocalStorage;
      24             : class LocalStorageManager;
      25             : class StorageUsage;
      26             : class StorageDBBridge;
      27             : 
      28             : // Interface class on which only the database or IPC may call.
      29             : // Used to populate the cache with DB data.
      30           3 : class LocalStorageCacheBridge
      31             : {
      32             : public:
      33             :   NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
      34             :   NS_IMETHOD_(void) Release(void);
      35             : 
      36             :   // The origin of the cache, result is concatenation of OriginNoSuffix() and
      37             :   // OriginSuffix(), see below.
      38             :   virtual const nsCString Origin() const = 0;
      39             : 
      40             :   // The origin attributes suffix alone, this is usually passed as an
      41             :   // |aOriginSuffix| argument to various methods
      42             :   virtual const nsCString& OriginSuffix() const = 0;
      43             : 
      44             :   // The origin in the database usage format (reversed) and without the suffix
      45             :   virtual const nsCString& OriginNoSuffix() const = 0;
      46             : 
      47             :   // Whether the cache is already fully loaded
      48             :   virtual bool Loaded() = 0;
      49             : 
      50             :   // How many items has so far been loaded into the cache, used
      51             :   // for optimization purposes
      52             :   virtual uint32_t LoadedCount() = 0;
      53             : 
      54             :   // Called by the database to load a key and its value to the cache
      55             :   virtual bool LoadItem(const nsAString& aKey, const nsString& aValue) = 0;
      56             : 
      57             :   // Called by the database after all keys and values has been loaded
      58             :   // to this cache
      59             :   virtual void LoadDone(nsresult aRv) = 0;
      60             : 
      61             :   // Use to synchronously wait until the cache gets fully loaded with data,
      62             :   // this method exits after LoadDone has been called
      63             :   virtual void LoadWait() = 0;
      64             : 
      65             : protected:
      66           2 :   virtual ~LocalStorageCacheBridge() {}
      67             : 
      68             :   ThreadSafeAutoRefCnt mRefCnt;
      69             :   NS_DECL_OWNINGTHREAD
      70             : };
      71             : 
      72             : // Implementation of scope cache that is responsible for preloading data
      73             : // for persistent storage (localStorage) and hold data for non-private,
      74             : // private and session-only cookie modes.  It is also responsible for
      75             : // persisting data changes using the database, works as a write-back cache.
      76             : class LocalStorageCache : public LocalStorageCacheBridge
      77             : {
      78             : public:
      79             :   NS_IMETHOD_(void) Release(void);
      80             : 
      81             :   enum MutationSource {
      82             :     // The mutation is a result of an explicit JS mutation in this process.
      83             :     // The mutation should be sent to the sDatabase. Quota will be checked and
      84             :     // QuotaExceededError may be returned without the mutation being applied.
      85             :     ContentMutation,
      86             :     // The mutation initially was triggered in a different process and is being
      87             :     // propagated to this cache via LocalStorage::ApplyEvent.  The mutation should
      88             :     // not be sent to the sDatabase because the originating process is already
      89             :     // doing that.  (In addition to the redundant writes being wasteful, there
      90             :     // is the potential for other processes to see inconsistent state from the
      91             :     // database while preloading.)  Quota will be updated but not checked
      92             :     // because it's assumed it was checked in another process and data-coherency
      93             :     // is more important than slightly exceeding quota.
      94             :     E10sPropagated
      95             :   };
      96             : 
      97             :   // Note: We pass aOriginNoSuffix through the ctor here, because
      98             :   // LocalStorageCacheHashKey's ctor is creating this class and
      99             :   // accepts reversed-origin-no-suffix as an argument - the hashing key.
     100             :   explicit LocalStorageCache(const nsACString* aOriginNoSuffix);
     101             : 
     102             : protected:
     103             :   virtual ~LocalStorageCache();
     104             : 
     105             : public:
     106             :   void Init(LocalStorageManager* aManager, bool aPersistent,
     107             :             nsIPrincipal* aPrincipal, const nsACString& aQuotaOriginScope);
     108             : 
     109             :   // Get size of per-origin data.
     110             :   int64_t GetOriginQuotaUsage(const LocalStorage* aStorage) const;
     111             : 
     112             :   // Starts async preload of this cache if it persistent and not loaded.
     113             :   void Preload();
     114             : 
     115             :   // The set of methods that are invoked by DOM storage web API.
     116             :   // We are passing the LocalStorage object just to let the cache
     117             :   // read properties like mPrivate and mSessionOnly.
     118             :   // Get* methods return error when load from the database has failed.
     119             :   nsresult GetLength(const LocalStorage* aStorage, uint32_t* aRetval);
     120             :   nsresult GetKey(const LocalStorage* aStorage, uint32_t index, nsAString& aRetval);
     121             :   nsresult GetItem(const LocalStorage* aStorage, const nsAString& aKey,
     122             :                    nsAString& aRetval);
     123             :   nsresult SetItem(const LocalStorage* aStorage, const nsAString& aKey,
     124             :                    const nsString& aValue, nsString& aOld,
     125             :                    const MutationSource aSource=ContentMutation);
     126             :   nsresult RemoveItem(const LocalStorage* aStorage, const nsAString& aKey,
     127             :                       nsString& aOld,
     128             :                       const MutationSource aSource=ContentMutation);
     129             :   nsresult Clear(const LocalStorage* aStorage,
     130             :                  const MutationSource aSource=ContentMutation);
     131             : 
     132             :   void GetKeys(const LocalStorage* aStorage, nsTArray<nsString>& aKeys);
     133             : 
     134             :   // Starts the database engine thread or the IPC bridge
     135             :   static StorageDBBridge* StartDatabase();
     136             :   static StorageDBBridge* GetDatabase();
     137             : 
     138             :   // Stops the thread and flushes all uncommited data
     139             :   static nsresult StopDatabase();
     140             : 
     141             :   // LocalStorageCacheBridge
     142             : 
     143             :   virtual const nsCString Origin() const;
     144           2 :   virtual const nsCString& OriginNoSuffix() const { return mOriginNoSuffix; }
     145           2 :   virtual const nsCString& OriginSuffix() const { return mOriginSuffix; }
     146           0 :   virtual bool Loaded() { return mLoaded; }
     147             :   virtual uint32_t LoadedCount();
     148             :   virtual bool LoadItem(const nsAString& aKey, const nsString& aValue);
     149             :   virtual void LoadDone(nsresult aRv);
     150             :   virtual void LoadWait();
     151             : 
     152             :   // Cache keeps 3 sets of data: regular, private and session-only.
     153             :   // This class keeps keys and values for a set and also caches
     154             :   // size of the data for quick per-origin quota checking.
     155           0 :   class Data
     156             :   {
     157             :   public:
     158           3 :     Data() : mOriginQuotaUsage(0) {}
     159             :     int64_t mOriginQuotaUsage;
     160             :     nsDataHashtable<nsStringHashKey, nsString> mKeys;
     161             :   };
     162             : 
     163             : public:
     164             :   // Number of data sets we keep: default, private, session
     165             :   static const uint32_t kDataSetCount = 3;
     166             : 
     167             : private:
     168             :   // API to clear the cache data, this is invoked by chrome operations
     169             :   // like cookie deletion.
     170             :   friend class LocalStorageManager;
     171             : 
     172             :   static const uint32_t kUnloadDefault = 1 << 0;
     173             :   static const uint32_t kUnloadPrivate = 1 << 1;
     174             :   static const uint32_t kUnloadSession = 1 << 2;
     175             :   static const uint32_t kUnloadComplete =
     176             :     kUnloadDefault | kUnloadPrivate | kUnloadSession;
     177             : 
     178             : #ifdef DOM_STORAGE_TESTS
     179             :   static const uint32_t kTestReload    = 1 << 15;
     180             : #endif
     181             : 
     182             :   void UnloadItems(uint32_t aUnloadFlags);
     183             : 
     184             : private:
     185             :   // Synchronously blocks until the cache is fully loaded from the database
     186             :   void WaitForPreload(mozilla::Telemetry::HistogramID aTelemetryID);
     187             : 
     188             :   // Helper to get one of the 3 data sets (regular, private, session)
     189             :   Data& DataSet(const LocalStorage* aStorage);
     190             : 
     191             :   // Whether the storage change is about to persist
     192             :   bool Persist(const LocalStorage* aStorage) const;
     193             : 
     194             :   // Changes the quota usage on the given data set if it fits the quota.
     195             :   // If not, then false is returned and no change to the set must be done.
     196             :   // A special case is if aSource==E10sPropagated, then we will return true even
     197             :   // if the change would put us over quota.  This is done to ensure coherency of
     198             :   // caches between processes in the face of races.  It does allow an attacker
     199             :   // to potentially use N multiples of the quota storage limit if they can
     200             :   // arrange for their origin to execute code in N processes.  However, this is
     201             :   // not considered a particularly concerning threat model because it's already
     202             :   // very possible for a rogue page to attempt to intentionally fill up the
     203             :   // user's storage through the use of multiple domains.
     204             :   bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta,
     205             :                          const MutationSource aSource=ContentMutation);
     206             :   bool ProcessUsageDelta(const LocalStorage* aStorage, const int64_t aDelta,
     207             :                          const MutationSource aSource=ContentMutation);
     208             : 
     209             : private:
     210             :   // When a cache is reponsible for its life time (in case of localStorage data
     211             :   // cache) we need to refer our manager since removal of the cache from the
     212             :   // hash table is handled in the destructor by call to the manager.  Cache
     213             :   // could potentially overlive the manager, hence the hard ref.
     214             :   RefPtr<LocalStorageManager> mManager;
     215             : 
     216             :   // Reference to the usage counter object we check on for eTLD+1 quota limit.
     217             :   // Obtained from the manager during initialization (Init method).
     218             :   RefPtr<StorageUsage> mUsage;
     219             : 
     220             :   // The origin this cache belongs to in the "DB format", i.e. reversed
     221             :   nsCString mOriginNoSuffix;
     222             : 
     223             :   // The origin attributes suffix
     224             :   nsCString mOriginSuffix;
     225             : 
     226             :   // The eTLD+1 scope used to count quota usage.  It is in the reversed format
     227             :   // and contains the origin attributes suffix.
     228             :   nsCString mQuotaOriginScope;
     229             : 
     230             :   // Non-private Browsing, Private Browsing and Session Only sets.
     231             :   Data mData[kDataSetCount];
     232             : 
     233             :   // This monitor is used to wait for full load of data.
     234             :   mozilla::Monitor mMonitor;
     235             : 
     236             :   // Flag that is initially false.  When the cache is about to work with
     237             :   // the database (i.e. it is persistent) this flags is set to true after
     238             :   // all keys and coresponding values are loaded from the database.
     239             :   // This flag never goes from true back to false.  Since this flag is
     240             :   // critical for mData hashtable synchronization, it's made atomic.
     241             :   Atomic<bool, ReleaseAcquire> mLoaded;
     242             : 
     243             :   // Result of load from the database.  Valid after mLoaded flag has been set.
     244             :   nsresult mLoadResult;
     245             : 
     246             :   // Init() method has been called
     247             :   bool mInitialized : 1;
     248             : 
     249             :   // This cache is about to be bound with the database (i.e. it has
     250             :   // to load from the DB first and has to persist when modifying the
     251             :   // default data set.)
     252             :   bool mPersistent : 1;
     253             : 
     254             :   // - False when the session-only data set was never used.
     255             :   // - True after access to session-only data has been made for the first time.
     256             :   // We also fill session-only data set with the default one at that moment.
     257             :   // Drops back to false when session-only data are cleared from chrome.
     258             :   bool mSessionOnlyDataSetActive : 1;
     259             : 
     260             :   // Whether we have already captured state of the cache preload on our first
     261             :   // access.
     262             :   bool mPreloadTelemetryRecorded : 1;
     263             : 
     264             :   // StorageDBThread on the parent or single process,
     265             :   // StorageDBChild on the child process.
     266             :   static StorageDBBridge* sDatabase;
     267             : 
     268             :   // False until we shut the database down.
     269             :   static bool sDatabaseDown;
     270             : };
     271             : 
     272             : // StorageUsage
     273             : // Infrastructure to manage and check eTLD+1 quota
     274           2 : class StorageUsageBridge
     275             : {
     276             : public:
     277           8 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageUsageBridge)
     278             : 
     279             :   virtual const nsCString& OriginScope() = 0;
     280             :   virtual void LoadUsage(const int64_t aUsage) = 0;
     281             : 
     282             : protected:
     283             :   // Protected destructor, to discourage deletion outside of Release():
     284           1 :   virtual ~StorageUsageBridge() {}
     285             : };
     286             : 
     287           0 : class StorageUsage : public StorageUsageBridge
     288             : {
     289             : public:
     290             :   explicit StorageUsage(const nsACString& aOriginScope);
     291             : 
     292             :   bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta,
     293             :                                   const LocalStorageCache::MutationSource aSource);
     294             : 
     295             : private:
     296           1 :   virtual const nsCString& OriginScope() { return mOriginScope; }
     297             :   virtual void LoadUsage(const int64_t aUsage);
     298             : 
     299             :   nsCString mOriginScope;
     300             :   int64_t mUsage[LocalStorageCache::kDataSetCount];
     301             : };
     302             : 
     303             : } // namespace dom
     304             : } // namespace mozilla
     305             : 
     306             : #endif // mozilla_dom_LocalStorageCache_h

Generated by: LCOV version 1.13