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 CacheFileMetadata__h__
6 #define CacheFileMetadata__h__
7 
8 #include "CacheFileIOManager.h"
9 #include "CacheStorageService.h"
10 #include "CacheHashUtils.h"
11 #include "CacheObserver.h"
12 #include "mozilla/EndianUtils.h"
13 #include "mozilla/BasePrincipal.h"
14 #include "nsString.h"
15 
16 class nsICacheEntryMetaDataVisitor;
17 
18 namespace mozilla {
19 namespace net {
20 
21 // Flags stored in CacheFileMetadataHeader.mFlags
22 
23 // Whether an entry is a pinned entry (created with
24 // nsICacheStorageService.pinningCacheStorage.)
25 static const uint32_t kCacheEntryIsPinned = 1 << 0;
26 
27 // By multiplying with the current half-life we convert the frecency
28 // to time independent of half-life value.  The range fits 32bits.
29 // When decay time changes on next run of the browser, we convert
30 // the frecency value to a correct internal representation again.
31 // It might not be 100% accurate, but for the purpose it suffice.
32 #define FRECENCY2INT(aFrecency) \
33   ((uint32_t)((aFrecency)*CacheObserver::HalfLifeSeconds()))
34 #define INT2FRECENCY(aInt) \
35   ((double)(aInt) / (double)CacheObserver::HalfLifeSeconds())
36 
37 #define kCacheEntryVersion 3
38 
39 #pragma pack(push)
40 #pragma pack(1)
41 
42 class CacheFileMetadataHeader {
43  public:
44   uint32_t mVersion;
45   uint32_t mFetchCount;
46   uint32_t mLastFetched;
47   uint32_t mLastModified;
48   uint32_t mFrecency;
49   uint32_t mExpirationTime;
50   uint32_t mKeySize;
51   uint32_t mFlags;
52 
WriteToBuf(void * aBuf)53   void WriteToBuf(void* aBuf) {
54     EnsureCorrectClassSize();
55 
56     uint8_t* ptr = static_cast<uint8_t*>(aBuf);
57     MOZ_ASSERT(mVersion == kCacheEntryVersion);
58     NetworkEndian::writeUint32(ptr, mVersion);
59     ptr += sizeof(uint32_t);
60     NetworkEndian::writeUint32(ptr, mFetchCount);
61     ptr += sizeof(uint32_t);
62     NetworkEndian::writeUint32(ptr, mLastFetched);
63     ptr += sizeof(uint32_t);
64     NetworkEndian::writeUint32(ptr, mLastModified);
65     ptr += sizeof(uint32_t);
66     NetworkEndian::writeUint32(ptr, mFrecency);
67     ptr += sizeof(uint32_t);
68     NetworkEndian::writeUint32(ptr, mExpirationTime);
69     ptr += sizeof(uint32_t);
70     NetworkEndian::writeUint32(ptr, mKeySize);
71     ptr += sizeof(uint32_t);
72     NetworkEndian::writeUint32(ptr, mFlags);
73   }
74 
ReadFromBuf(const void * aBuf)75   void ReadFromBuf(const void* aBuf) {
76     EnsureCorrectClassSize();
77 
78     const uint8_t* ptr = static_cast<const uint8_t*>(aBuf);
79     mVersion = BigEndian::readUint32(ptr);
80     ptr += sizeof(uint32_t);
81     mFetchCount = BigEndian::readUint32(ptr);
82     ptr += sizeof(uint32_t);
83     mLastFetched = BigEndian::readUint32(ptr);
84     ptr += sizeof(uint32_t);
85     mLastModified = BigEndian::readUint32(ptr);
86     ptr += sizeof(uint32_t);
87     mFrecency = BigEndian::readUint32(ptr);
88     ptr += sizeof(uint32_t);
89     mExpirationTime = BigEndian::readUint32(ptr);
90     ptr += sizeof(uint32_t);
91     mKeySize = BigEndian::readUint32(ptr);
92     ptr += sizeof(uint32_t);
93     if (mVersion >= 2) {
94       mFlags = BigEndian::readUint32(ptr);
95     } else {
96       mFlags = 0;
97     }
98   }
99 
EnsureCorrectClassSize()100   inline void EnsureCorrectClassSize() {
101     static_assert(
102         (sizeof(mVersion) + sizeof(mFetchCount) + sizeof(mLastFetched) +
103          sizeof(mLastModified) + sizeof(mFrecency) + sizeof(mExpirationTime) +
104          sizeof(mKeySize)) +
105                 sizeof(mFlags) ==
106             sizeof(CacheFileMetadataHeader),
107         "Unexpected sizeof(CacheFileMetadataHeader)!");
108   }
109 };
110 
111 #pragma pack(pop)
112 
113 #define CACHEFILEMETADATALISTENER_IID                \
114   { /* a9e36125-3f01-4020-9540-9dafa8d31ba7 */       \
115     0xa9e36125, 0x3f01, 0x4020, {                    \
116       0x95, 0x40, 0x9d, 0xaf, 0xa8, 0xd3, 0x1b, 0xa7 \
117     }                                                \
118   }
119 
120 class CacheFileMetadataListener : public nsISupports {
121  public:
122   NS_DECLARE_STATIC_IID_ACCESSOR(CACHEFILEMETADATALISTENER_IID)
123 
124   NS_IMETHOD OnMetadataRead(nsresult aResult) = 0;
125   NS_IMETHOD OnMetadataWritten(nsresult aResult) = 0;
126   virtual bool IsKilled() = 0;
127 };
128 
NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileMetadataListener,CACHEFILEMETADATALISTENER_IID)129 NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileMetadataListener,
130                               CACHEFILEMETADATALISTENER_IID)
131 
132 class CacheFileMetadata final : public CacheFileIOListener,
133                                 public CacheMemoryConsumer {
134  public:
135   NS_DECL_THREADSAFE_ISUPPORTS
136 
137   CacheFileMetadata(CacheFileHandle* aHandle, const nsACString& aKey);
138   CacheFileMetadata(bool aMemoryOnly, bool aPinned, const nsACString& aKey);
139   CacheFileMetadata();
140 
141   void SetHandle(CacheFileHandle* aHandle);
142 
143   const nsACString& GetKey() const { return mKey; }
144 
145   void ReadMetadata(CacheFileMetadataListener* aListener);
146   uint32_t CalcMetadataSize(uint32_t aElementsSize, uint32_t aHashCount);
147   nsresult WriteMetadata(uint32_t aOffset,
148                          CacheFileMetadataListener* aListener);
149   nsresult SyncReadMetadata(nsIFile* aFile);
150 
151   bool IsAnonymous() const { return mAnonymous; }
152   mozilla::OriginAttributes const& OriginAttributes() const {
153     return mOriginAttributes;
154   }
155   bool Pinned() const { return !!(mMetaHdr.mFlags & kCacheEntryIsPinned); }
156 
157   const char* GetElement(const char* aKey);
158   nsresult SetElement(const char* aKey, const char* aValue);
159   void Visit(nsICacheEntryMetaDataVisitor* aVisitor);
160 
161   CacheHash::Hash16_t GetHash(uint32_t aIndex);
162   nsresult SetHash(uint32_t aIndex, CacheHash::Hash16_t aHash);
163   nsresult RemoveHash(uint32_t aIndex);
164 
165   void AddFlags(uint32_t aFlags);
166   void RemoveFlags(uint32_t aFlags);
167   uint32_t GetFlags() const { return mMetaHdr.mFlags; }
168   void SetExpirationTime(uint32_t aExpirationTime);
169   uint32_t GetExpirationTime() const { return mMetaHdr.mExpirationTime; }
170   void SetFrecency(uint32_t aFrecency);
171   uint32_t GetFrecency() const { return mMetaHdr.mFrecency; }
172   uint32_t GetLastModified() const { return mMetaHdr.mLastModified; }
173   uint32_t GetLastFetched() const { return mMetaHdr.mLastFetched; }
174   uint32_t GetFetchCount() const { return mMetaHdr.mFetchCount; }
175   // Called by upper layers to indicate the entry this metadata belongs
176   // with has been fetched, i.e. delivered to the consumer.
177   void OnFetched();
178 
179   int64_t Offset() { return mOffset; }
180   uint32_t ElementsSize() { return mElementsSize; }
181   void MarkDirty(bool aUpdateLastModified = true);
182   bool IsDirty() { return mIsDirty; }
183   uint32_t MemoryUsage() {
184     return sizeof(CacheFileMetadata) + mHashArraySize + mBufSize;
185   }
186 
187   NS_IMETHOD OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) override;
188   NS_IMETHOD OnDataWritten(CacheFileHandle* aHandle, const char* aBuf,
189                            nsresult aResult) override;
190   NS_IMETHOD OnDataRead(CacheFileHandle* aHandle, char* aBuf,
191                         nsresult aResult) override;
192   NS_IMETHOD OnFileDoomed(CacheFileHandle* aHandle, nsresult aResult) override;
193   NS_IMETHOD OnEOFSet(CacheFileHandle* aHandle, nsresult aResult) override;
194   NS_IMETHOD OnFileRenamed(CacheFileHandle* aHandle, nsresult aResult) override;
195   virtual bool IsKilled() override {
196     return mListener && mListener->IsKilled();
197   }
198   void InitEmptyMetadata();
199 
200   // Memory reporting
201   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
202   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
203 
204  private:
205   virtual ~CacheFileMetadata();
206 
207   nsresult ParseMetadata(uint32_t aMetaOffset, uint32_t aBufOffset,
208                          bool aHaveKey);
209   nsresult CheckElements(const char* aBuf, uint32_t aSize);
210   nsresult EnsureBuffer(uint32_t aSize);
211   nsresult ParseKey(const nsACString& aKey);
212 
213   RefPtr<CacheFileHandle> mHandle;
214   nsCString mKey;
215   CacheHash::Hash16_t* mHashArray{nullptr};
216   uint32_t mHashArraySize{0};
217   uint32_t mHashCount{0};
218   int64_t mOffset{0};
219   // used for parsing, then points to elements
220   char* mBuf{nullptr};
221   uint32_t mBufSize{0};
222   char* mWriteBuf{nullptr};
223   CacheFileMetadataHeader mMetaHdr{0};
224   uint32_t mElementsSize{0};
225   bool mIsDirty : 1;
226   bool mAnonymous : 1;
227   bool mAllocExactSize : 1;
228   bool mFirstRead : 1;
229   mozilla::OriginAttributes mOriginAttributes;
230   mozilla::TimeStamp mReadStart;
231   nsCOMPtr<CacheFileMetadataListener> mListener;
232 };
233 
234 }  // namespace net
235 }  // namespace mozilla
236 
237 #endif
238