tor-browser

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

CacheFile.h (11094B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef CacheFile__h__
      6 #define CacheFile__h__
      7 
      8 #include "CacheFileChunk.h"
      9 #include "CacheFileIOManager.h"
     10 #include "CacheFileMetadata.h"
     11 #include "Dictionary.h"
     12 #include "nsRefPtrHashtable.h"
     13 #include "nsClassHashtable.h"
     14 #include "mozilla/Mutex.h"
     15 
     16 class nsIAsyncOutputStream;
     17 class nsICacheEntry;
     18 class nsICacheEntryMetaDataVisitor;
     19 class nsIInputStream;
     20 class nsIOutputStream;
     21 
     22 namespace mozilla {
     23 namespace net {
     24 
     25 class CacheFileInputStream;
     26 class CacheFileOutputStream;
     27 class CacheOutputCloseListener;
     28 class MetadataWriteTimer;
     29 
     30 namespace CacheFileUtils {
     31 class CacheFileLock;
     32 };
     33 
     34 #define CACHEFILELISTENER_IID                 \
     35  {/* 95e7f284-84ba-48f9-b1fc-3a7336b4c33c */ \
     36   0x95e7f284,                                \
     37   0x84ba,                                    \
     38   0x48f9,                                    \
     39   {0xb1, 0xfc, 0x3a, 0x73, 0x36, 0xb4, 0xc3, 0x3c}}
     40 
     41 class CacheFileListener : public nsISupports {
     42 public:
     43  NS_INLINE_DECL_STATIC_IID(CACHEFILELISTENER_IID)
     44 
     45  NS_IMETHOD OnFileReady(nsresult aResult, bool aIsNew) = 0;
     46  NS_IMETHOD OnFileDoomed(nsresult aResult) = 0;
     47 };
     48 
     49 class MOZ_CAPABILITY("mutex") CacheFile final
     50    : public CacheFileChunkListener,
     51      public CacheFileIOListener,
     52      public CacheFileMetadataListener {
     53 public:
     54  NS_DECL_THREADSAFE_ISUPPORTS
     55 
     56  CacheFile();
     57 
     58  nsresult Init(const nsACString& aKey, bool aCreateNew, bool aMemoryOnly,
     59                bool aSkipSizeCheck, bool aPriority, bool aPinned,
     60                CacheFileListener* aCallback);
     61 
     62  NS_IMETHOD OnChunkRead(nsresult aResult, CacheFileChunk* aChunk) override;
     63  NS_IMETHOD OnChunkWritten(nsresult aResult, CacheFileChunk* aChunk) override;
     64  NS_IMETHOD OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
     65                              CacheFileChunk* aChunk) override;
     66  NS_IMETHOD OnChunkUpdated(CacheFileChunk* aChunk) override;
     67 
     68  NS_IMETHOD OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) override;
     69  NS_IMETHOD OnDataWritten(CacheFileHandle* aHandle, const char* aBuf,
     70                           nsresult aResult) override;
     71  NS_IMETHOD OnDataRead(CacheFileHandle* aHandle, char* aBuf,
     72                        nsresult aResult) override;
     73  NS_IMETHOD OnFileDoomed(CacheFileHandle* aHandle, nsresult aResult) override;
     74  NS_IMETHOD OnEOFSet(CacheFileHandle* aHandle, nsresult aResult) override;
     75  NS_IMETHOD OnFileRenamed(CacheFileHandle* aHandle, nsresult aResult) override;
     76  virtual bool IsKilled() override;
     77 
     78  NS_IMETHOD OnMetadataRead(nsresult aResult) override;
     79  NS_IMETHOD OnMetadataWritten(nsresult aResult) override;
     80 
     81  NS_IMETHOD OpenInputStream(nsICacheEntry* aCacheEntryHandle,
     82                             nsIInputStream** _retval);
     83  NS_IMETHOD OpenAlternativeInputStream(nsICacheEntry* aCacheEntryHandle,
     84                                        const char* aAltDataType,
     85                                        nsIInputStream** _retval);
     86  NS_IMETHOD OpenOutputStream(CacheOutputCloseListener* aCloseListener,
     87                              nsIOutputStream** _retval);
     88  NS_IMETHOD OpenAlternativeOutputStream(
     89      CacheOutputCloseListener* aCloseListener, const char* aAltDataType,
     90      nsIAsyncOutputStream** _retval);
     91  NS_IMETHOD SetMemoryOnly();
     92  NS_IMETHOD Doom(CacheFileListener* aCallback);
     93 
     94  void Kill() { mKill = true; }
     95  nsresult ThrowMemoryCachedData();
     96 
     97  nsresult GetAltDataSize(int64_t* aSize);
     98  nsresult GetAltDataType(nsACString& aType);
     99 
    100  // metadata forwarders
    101  nsresult GetElement(const char* aKey, char** _retval);
    102  nsresult SetElement(const char* aKey, const char* aValue);
    103  nsresult VisitMetaData(nsICacheEntryMetaDataVisitor* aVisitor);
    104  nsresult ElementsSize(uint32_t* _retval);
    105  nsresult SetExpirationTime(uint32_t aExpirationTime);
    106  nsresult GetExpirationTime(uint32_t* _retval);
    107  nsresult SetFrecency(uint32_t aFrecency);
    108  nsresult GetFrecency(uint32_t* _retval);
    109  nsresult SetNetworkTimes(uint64_t aOnStartTime, uint64_t aOnStopTime);
    110  nsresult SetContentType(uint8_t aContentType);
    111  nsresult GetOnStartTime(uint64_t* _retval);
    112  nsresult GetOnStopTime(uint64_t* _retval);
    113  nsresult GetLastModified(uint32_t* _retval);
    114  nsresult GetLastFetched(uint32_t* _retval);
    115  nsresult GetFetchCount(uint32_t* _retval);
    116  nsresult GetDiskStorageSizeInKB(uint32_t* aDiskStorageSize);
    117  // Called by upper layers to indicated the entry has been fetched,
    118  // i.e. delivered to the consumer.
    119  nsresult OnFetched();
    120 
    121  bool DataSize(int64_t* aSize);
    122  void Key(nsACString& aKey);
    123  bool IsDoomed();
    124  bool IsPinned();
    125  // Returns true when there is a potentially unfinished write operation.
    126  bool IsWriteInProgress();
    127  bool EntryWouldExceedLimit(int64_t aOffset, int64_t aSize, bool aIsAltData);
    128 
    129  void SetDictionary(DictionaryCacheEntry* aDict);
    130 
    131  // Memory reporting
    132  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    133  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    134 
    135 private:
    136  friend class CacheFileIOManager;
    137  friend class CacheFileChunk;
    138  friend class CacheFileInputStream;
    139  friend class CacheFileOutputStream;
    140  friend class CacheFileAutoLock;
    141  friend class MetadataWriteTimer;
    142 
    143  virtual ~CacheFile();
    144 
    145  void Lock() MOZ_CAPABILITY_ACQUIRE() { mLock->Lock().Lock(); }
    146  void Unlock() MOZ_CAPABILITY_RELEASE() {
    147    // move the elements out of mObjsToRelease
    148    // so that they can be released after we unlock
    149    nsTArray<RefPtr<nsISupports>> objs = std::move(mObjsToRelease);
    150 
    151    mLock->Lock().Unlock();
    152  }
    153  void AssertOwnsLock() const MOZ_ASSERT_CAPABILITY(this) {
    154    mLock->Lock().AssertCurrentThreadOwns();
    155  }
    156  void ReleaseOutsideLock(RefPtr<nsISupports> aObject);
    157 
    158  enum ECallerType { READER = 0, WRITER = 1, PRELOADER = 2 };
    159 
    160  nsresult DoomLocked(CacheFileListener* aCallback);
    161 
    162  nsresult GetChunkLocked(uint32_t aIndex, ECallerType aCaller,
    163                          CacheFileChunkListener* aCallback,
    164                          CacheFileChunk** _retval);
    165 
    166  void PreloadChunks(uint32_t aIndex);
    167  bool ShouldCacheChunk(uint32_t aIndex);
    168  bool MustKeepCachedChunk(uint32_t aIndex);
    169 
    170  nsresult DeactivateChunk(CacheFileChunk* aChunk);
    171  void RemoveChunkInternal(CacheFileChunk* aChunk, bool aCacheChunk);
    172 
    173  bool OutputStreamExists(bool aAlternativeData);
    174  // Returns number of bytes that are available and can be read by input stream
    175  // without waiting for the data. The amount is counted from the start of
    176  // aIndex chunk and it is guaranteed that this data won't be released by
    177  // CleanUpCachedChunks().
    178  int64_t BytesFromChunk(uint32_t aIndex, bool aAlternativeData);
    179  nsresult Truncate(int64_t aOffset);
    180 
    181  void RemoveInput(CacheFileInputStream* aInput, nsresult aStatus);
    182  void RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus);
    183  nsresult NotifyChunkListener(CacheFileChunkListener* aCallback,
    184                               nsIEventTarget* aTarget, nsresult aResult,
    185                               uint32_t aChunkIdx, CacheFileChunk* aChunk);
    186  void QueueChunkListener(uint32_t aIndex, CacheFileChunkListener* aCallback);
    187  nsresult NotifyChunkListeners(uint32_t aIndex, nsresult aResult,
    188                                CacheFileChunk* aChunk);
    189  bool HaveChunkListeners(uint32_t aIndex);
    190  void NotifyListenersAboutOutputRemoval();
    191 
    192  bool IsDirty() MOZ_REQUIRES(this);
    193  void WriteMetadataIfNeeded();
    194  void WriteMetadataIfNeededLocked(bool aFireAndForget = false)
    195      MOZ_REQUIRES(this);
    196  void PostWriteTimer() MOZ_REQUIRES(this);
    197 
    198  void CleanUpCachedChunks() MOZ_REQUIRES(this);
    199 
    200  nsresult PadChunkWithZeroes(uint32_t aChunkIdx);
    201 
    202  void SetError(nsresult aStatus);
    203  nsresult SetAltMetadata(const char* aAltMetadata);
    204 
    205  nsresult InitIndexEntry();
    206 
    207  bool mOpeningFile MOZ_GUARDED_BY(this){false};
    208  bool mReady MOZ_GUARDED_BY(this){false};
    209  bool mMemoryOnly MOZ_GUARDED_BY(this){false};
    210  bool mSkipSizeCheck MOZ_GUARDED_BY(this){false};
    211  bool mOpenAsMemoryOnly MOZ_GUARDED_BY(this){false};
    212  bool mPinned MOZ_GUARDED_BY(this){false};
    213  bool mPriority MOZ_GUARDED_BY(this){false};
    214  bool mDataAccessed MOZ_GUARDED_BY(this){false};
    215  bool mDataIsDirty MOZ_GUARDED_BY(this){false};
    216  bool mWritingMetadata MOZ_GUARDED_BY(this){false};
    217  bool mPreloadWithoutInputStreams MOZ_GUARDED_BY(this){true};
    218  uint32_t mPreloadChunkCount MOZ_GUARDED_BY(this){0};
    219  nsresult mStatus MOZ_GUARDED_BY(this){NS_OK};
    220  // Size of the whole data including eventual alternative data represenation.
    221  int64_t mDataSize MOZ_GUARDED_BY(this){-1};
    222 
    223  // If there is alternative data present, it contains size of the original
    224  // data, i.e. offset where alternative data starts. Otherwise it is -1.
    225  int64_t mAltDataOffset MOZ_GUARDED_BY(this){-1};
    226 
    227  nsCString mKey MOZ_GUARDED_BY(this);
    228  nsCString mAltDataType
    229      MOZ_GUARDED_BY(this);  // The type of the saved alt-data. May be empty.
    230 
    231  RefPtr<DictionaryCacheEntry> mDict MOZ_GUARDED_BY(this);
    232 
    233  RefPtr<CacheFileHandle> mHandle MOZ_GUARDED_BY(this);
    234  RefPtr<CacheFileMetadata> mMetadata MOZ_GUARDED_BY(this);
    235  nsCOMPtr<CacheFileListener> mListener MOZ_GUARDED_BY(this);
    236  nsCOMPtr<CacheFileIOListener> mDoomAfterOpenListener MOZ_GUARDED_BY(this);
    237  Atomic<bool, Relaxed> mKill{false};
    238 
    239  nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mChunks
    240      MOZ_GUARDED_BY(this);
    241  nsClassHashtable<nsUint32HashKey, ChunkListeners> mChunkListeners
    242      MOZ_GUARDED_BY(this);
    243  nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mCachedChunks
    244      MOZ_GUARDED_BY(this);
    245  // We can truncate data only if there is no input/output stream beyond the
    246  // truncate position, so only unused chunks can be thrown away. But it can
    247  // happen that we need to throw away a chunk that is still in mChunks (i.e.
    248  // an active chunk) because deactivation happens with a small delay. We cannot
    249  // delete such chunk immediately but we need to ensure that such chunk won't
    250  // be returned by GetChunkLocked, so we move this chunk into mDiscardedChunks
    251  // and mark it as discarded.
    252  nsTArray<RefPtr<CacheFileChunk>> mDiscardedChunks MOZ_GUARDED_BY(this);
    253 
    254  nsTArray<CacheFileInputStream*> mInputs MOZ_GUARDED_BY(this);
    255  CacheFileOutputStream* mOutput MOZ_GUARDED_BY(this){nullptr};
    256 
    257  nsTArray<RefPtr<nsISupports>> mObjsToRelease MOZ_GUARDED_BY(this);
    258  RefPtr<CacheFileUtils::CacheFileLock> mLock;
    259 };
    260 
    261 class MOZ_RAII MOZ_SCOPED_CAPABILITY CacheFileAutoLock {
    262 public:
    263  explicit CacheFileAutoLock(CacheFile* aFile) MOZ_CAPABILITY_ACQUIRE(aFile)
    264      : mFile(aFile), mLocked(true) {
    265    mFile->Lock();
    266  }
    267  ~CacheFileAutoLock() MOZ_CAPABILITY_RELEASE() {
    268    if (mLocked) {
    269      mFile->Unlock();
    270    }
    271  }
    272  void Lock() MOZ_CAPABILITY_ACQUIRE() {
    273    MOZ_ASSERT(!mLocked);
    274    mFile->Lock();
    275    mLocked = true;
    276  }
    277  void Unlock() MOZ_CAPABILITY_RELEASE() {
    278    MOZ_ASSERT(mLocked);
    279    mFile->Unlock();
    280    mLocked = false;
    281  }
    282 
    283 private:
    284  RefPtr<CacheFile> mFile;
    285  bool mLocked;
    286 };
    287 
    288 }  // namespace net
    289 }  // namespace mozilla
    290 
    291 #endif