tor-browser

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

Manager.h (10508B)


      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_cache_Manager_h
      8 #define mozilla_dom_cache_Manager_h
      9 
     10 #include "CacheCommon.h"
     11 #include "mozilla/dom/SafeRefPtr.h"
     12 #include "mozilla/dom/cache/Types.h"
     13 #include "mozilla/dom/quota/Client.h"
     14 #include "mozilla/dom/quota/StringifyUtils.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsISupportsImpl.h"
     17 #include "nsString.h"
     18 #include "nsTArray.h"
     19 
     20 class nsIInputStream;
     21 class nsIThread;
     22 
     23 namespace mozilla {
     24 
     25 class ErrorResult;
     26 
     27 namespace dom {
     28 
     29 namespace quota {
     30 
     31 class ClientDirectoryLock;
     32 
     33 }  // namespace quota
     34 
     35 namespace cache {
     36 
     37 class CacheOpArgs;
     38 class CacheOpResult;
     39 class CacheRequestResponse;
     40 class Context;
     41 class ManagerId;
     42 struct SavedRequest;
     43 struct SavedResponse;
     44 class StreamList;
     45 
     46 // The Manager is class is responsible for performing all of the underlying
     47 // work for a Cache or CacheStorage operation.  The DOM objects and IPC actors
     48 // are basically just plumbing to get the request to the right Manager object
     49 // running in the parent process.
     50 //
     51 // There should be exactly one Manager object for each origin or app using the
     52 // Cache API.  This uniqueness is defined by the ManagerId equality operator.
     53 // The uniqueness is enforced by the Manager GetOrCreate() factory method.
     54 //
     55 // The life cycle of Manager objects is somewhat complex.  While code may
     56 // hold a strong reference to the Manager, it will invalidate itself once it
     57 // believes it has become completely idle.  This is currently determined when
     58 // all of the following conditions occur:
     59 //
     60 //  1) There are no more Manager::Listener objects registered with the Manager
     61 //     by performing a Cache or Storage operation.
     62 //  2) There are no more CacheId references noted via Manager::AddRefCacheId().
     63 //  3) There are no more BodyId references noted via Manager::AddRefBodyId().
     64 //
     65 // In order to keep your Manager alive you should perform an operation to set
     66 // a Listener, call AddRefCacheId(), or call AddRefBodyId().
     67 //
     68 // Even once a Manager becomes invalid, however, it may still continue to
     69 // exist.  This is allowed so that any in-progress Actions can gracefully
     70 // complete.
     71 //
     72 // As an invariant, all Manager objects must cease all IO before shutdown.  This
     73 // is enforced by the Manager::Factory.  If content still holds references to
     74 // Cache DOM objects during shutdown, then all operations will begin rejecting.
     75 class Manager final : public SafeRefCounted<Manager>, public Stringifyable {
     76  using Client = quota::Client;
     77  using ClientDirectoryLock = quota::ClientDirectoryLock;
     78 
     79 public:
     80  // Callback interface implemented by clients of Manager, such as CacheParent
     81  // and CacheStorageParent.  In general, if you call a Manager method you
     82  // should expect to receive exactly one On*() callback.  For example, if
     83  // you call Manager::CacheMatch(), then you should expect to receive
     84  // OnCacheMatch() back in response.
     85  //
     86  // Listener objects are set on a per-operation basis.  So you pass the
     87  // Listener to a call like Manager::CacheMatch().  Once set in this way,
     88  // the Manager will continue to reference the Listener until RemoveListener()
     89  // is called.  This is done to allow the same listener to be used for
     90  // multiple operations simultaneously without having to maintain an exact
     91  // count of operations-in-flight.
     92  //
     93  // Note, the Manager only holds weak references to Listener objects.
     94  // Listeners must call Manager::RemoveListener() before they are destroyed
     95  // to clear these weak references.
     96  //
     97  // All public methods should be invoked on the same thread used to create
     98  // the Manager.
     99  class Listener {
    100   public:
    101    // convenience routines
    102    void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult);
    103 
    104    void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
    105                      CacheId aOpenedCacheId);
    106 
    107    void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
    108                      const SavedResponse& aSavedResponse,
    109                      StreamList& aStreamList);
    110 
    111    void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
    112                      const nsTArray<SavedResponse>& aSavedResponseList,
    113                      StreamList& aStreamList);
    114 
    115    void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
    116                      const nsTArray<SavedRequest>& aSavedRequestList,
    117                      StreamList& aStreamList);
    118 
    119    struct StreamInfo {
    120      const nsTArray<SavedResponse>& mSavedResponseList;
    121      const nsTArray<SavedRequest>& mSavedRequestList;
    122      StreamList& mStreamList;
    123    };
    124 
    125    // interface to be implemented
    126    virtual void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
    127                              CacheId aOpenedCacheId,
    128                              const Maybe<StreamInfo>& aStreamInfo) {}
    129 
    130   protected:
    131    ~Listener() = default;
    132  };
    133 
    134  enum State { Open, Closing };
    135 
    136  static Result<SafeRefPtr<Manager>, nsresult> AcquireCreateIfNonExistent(
    137      const SafeRefPtr<ManagerId>& aManagerId);
    138 
    139  static void InitiateShutdown();
    140 
    141  static bool IsShutdownAllComplete();
    142 
    143  static nsCString GetShutdownStatus();
    144 
    145  // Cancel actions for given DirectoryLock ids.
    146  static void Abort(const Client::DirectoryLockIdTable& aDirectoryLockIds);
    147 
    148  // Cancel all actions.
    149  static void AbortAll();
    150 
    151  // Must be called by Listener objects before they are destroyed.
    152  void RemoveListener(Listener* aListener);
    153 
    154  // Must be called by Context objects before they are destroyed.
    155  void RemoveContext(Context& aContext);
    156 
    157  // Marks the Manager "invalid".  Once the Context completes no new operations
    158  // will be permitted with this Manager.  New actors will get a new Manager.
    159  void NoteClosing();
    160 
    161  State GetState() const;
    162 
    163  // If an actor represents a long term reference to a cache or body stream,
    164  // then they must call AddRefCacheId() or AddRefBodyId().  This will
    165  // cause the Manager to keep the backing data store alive for the given
    166  // object.  The actor must then call ReleaseCacheId() or ReleaseBodyId()
    167  // exactly once for every AddRef*() call it made.  Any delayed deletion
    168  // will then be performed.
    169  void AddRefCacheId(CacheId aCacheId);
    170  void ReleaseCacheId(CacheId aCacheId);
    171  void AddRefBodyId(const nsID& aBodyId);
    172  void ReleaseBodyId(const nsID& aBodyId);
    173 
    174  const ManagerId& GetManagerId() const;
    175 
    176  Maybe<ClientDirectoryLock&> MaybeDirectoryLockRef() const;
    177 
    178  // Methods to allow a StreamList to register themselves with the Manager.
    179  // StreamList objects must call RemoveStreamList() before they are destroyed.
    180  void AddStreamList(StreamList& aStreamList);
    181  void RemoveStreamList(StreamList& aStreamList);
    182 
    183  void ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
    184                      const CacheOpArgs& aOpArgs);
    185  void ExecutePutAll(
    186      Listener* aListener, CacheId aCacheId,
    187      const nsTArray<CacheRequestResponse>& aPutList,
    188      const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
    189      const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
    190 
    191  void ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
    192                        const CacheOpArgs& aOpArgs);
    193 
    194  void ExecuteOpenStream(Listener* aListener, InputStreamResolver&& aResolver,
    195                         const nsID& aBodyId);
    196 
    197  void NoteStreamOpenComplete(const nsID& aBodyId, ErrorResult&& aRv,
    198                              nsCOMPtr<nsIInputStream>&& aBodyStream);
    199 
    200 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    201  void RecordMayNotDeleteCSCP(
    202      mozilla::ipc::ActorId aCacheStreamControlParentId);
    203  void RecordHaveDeletedCSCP(mozilla::ipc::ActorId aCacheStreamControlParentId);
    204 #endif
    205 
    206 private:
    207  class Factory;
    208  class BaseAction;
    209  class DeleteOrphanedCacheAction;
    210 
    211  class CacheMatchAction;
    212  class CacheMatchAllAction;
    213  class CachePutAllAction;
    214  class CacheDeleteAction;
    215  class CacheKeysAction;
    216 
    217  class StorageMatchAction;
    218  class StorageHasAction;
    219  class StorageOpenAction;
    220  class StorageDeleteAction;
    221  class StorageKeysAction;
    222 
    223  class OpenStreamAction;
    224 
    225  using ListenerId = uint64_t;
    226 
    227  void Init(Maybe<Manager&> aOldManager);
    228  void Shutdown();
    229 
    230  void Abort();
    231 
    232  ListenerId SaveListener(Listener* aListener);
    233  Listener* GetListener(ListenerId aListenerId) const;
    234 
    235  bool SetCacheIdOrphanedIfRefed(CacheId aCacheId);
    236  bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId);
    237  void NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList);
    238 
    239  void MaybeAllowContextToClose();
    240 
    241  SafeRefPtr<ManagerId> mManagerId;
    242  nsCOMPtr<nsIThread> mIOThread;
    243 
    244  // Weak reference cleared by RemoveContext() in Context destructor.
    245  Context* MOZ_NON_OWNING_REF mContext;
    246 
    247  // Weak references cleared by RemoveListener() in Listener destructors.
    248  struct ListenerEntry {
    249    ListenerEntry() : mId(UINT64_MAX), mListener(nullptr) {}
    250 
    251    ListenerEntry(ListenerId aId, Listener* aListener)
    252        : mId(aId), mListener(aListener) {}
    253 
    254    ListenerId mId;
    255    Listener* mListener;
    256  };
    257 
    258  class ListenerEntryIdComparator {
    259   public:
    260    bool Equals(const ListenerEntry& aA, const ListenerId& aB) const {
    261      return aA.mId == aB;
    262    }
    263  };
    264 
    265  class ListenerEntryListenerComparator {
    266   public:
    267    bool Equals(const ListenerEntry& aA, const Listener* aB) const {
    268      return aA.mListener == aB;
    269    }
    270  };
    271 
    272  using ListenerList = nsTArray<ListenerEntry>;
    273  ListenerList mListeners;
    274  static ListenerId sNextListenerId;
    275 
    276  // Weak references cleared by RemoveStreamList() in StreamList destructors.
    277  nsTArray<NotNull<StreamList*>> mStreamLists;
    278 
    279  bool mShuttingDown;
    280  State mState;
    281 
    282  struct CacheIdRefCounter {
    283    CacheId mCacheId;
    284    MozRefCountType mCount;
    285    bool mOrphaned;
    286  };
    287  nsTArray<CacheIdRefCounter> mCacheIdRefs;
    288 
    289  struct BodyIdRefCounter {
    290    nsID mBodyId;
    291    MozRefCountType mCount;
    292    bool mOrphaned;
    293  };
    294  nsTArray<BodyIdRefCounter> mBodyIdRefs;
    295 
    296  struct ConstructorGuard {};
    297 
    298  void DoStringify(nsACString& aData) override;
    299 
    300 public:
    301  Manager(SafeRefPtr<ManagerId> aManagerId, nsIThread* aIOThread,
    302          const ConstructorGuard&);
    303  ~Manager();
    304 
    305  NS_DECL_OWNINGTHREAD
    306  MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Manager)
    307 };
    308 
    309 }  // namespace cache
    310 }  // namespace dom
    311 }  // namespace mozilla
    312 
    313 #endif  // mozilla_dom_cache_Manager_h