/work/obj-fuzz/dist/include/LookupCache.h
Line | Count | Source (jump to first uncovered line) |
1 | | //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #ifndef LookupCache_h__ |
7 | | #define LookupCache_h__ |
8 | | |
9 | | #include "Entries.h" |
10 | | #include "nsString.h" |
11 | | #include "nsTArray.h" |
12 | | #include "nsCOMPtr.h" |
13 | | #include "nsIFile.h" |
14 | | #include "nsIFileStreams.h" |
15 | | #include "mozilla/RefPtr.h" |
16 | | #include "nsUrlClassifierPrefixSet.h" |
17 | | #include "VariableLengthPrefixSet.h" |
18 | | #include "mozilla/Logging.h" |
19 | | #include "mozilla/TypedEnumBits.h" |
20 | | #include "nsIUrlClassifierInfo.h" |
21 | | |
22 | | namespace mozilla { |
23 | | namespace safebrowsing { |
24 | | |
25 | 0 | #define MAX_HOST_COMPONENTS 5 |
26 | 0 | #define MAX_PATH_COMPONENTS 4 |
27 | | |
28 | | class LookupResult { |
29 | | public: |
30 | | LookupResult() : mNoise(false), mProtocolConfirmed(false), |
31 | | mPartialHashLength(0), mConfirmed(false), |
32 | 0 | mProtocolV2(true) {} |
33 | | |
34 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LookupResult); |
35 | | |
36 | | // The fragment that matched in the LookupCache |
37 | | union { |
38 | | Prefix fixedLengthPrefix; |
39 | | Completion complete; |
40 | | } hash; |
41 | | |
42 | 0 | const Completion &CompleteHash() const { |
43 | 0 | MOZ_ASSERT(!mNoise); |
44 | 0 | return hash.complete; |
45 | 0 | } |
46 | | |
47 | 0 | nsCString PartialHash() const { |
48 | 0 | MOZ_ASSERT(mPartialHashLength <= COMPLETE_SIZE); |
49 | 0 | if (mNoise) { |
50 | 0 | return nsCString(reinterpret_cast<const char*>(hash.fixedLengthPrefix.buf), |
51 | 0 | PREFIX_SIZE); |
52 | 0 | } else { |
53 | 0 | return nsCString(reinterpret_cast<const char*>(hash.complete.buf), |
54 | 0 | mPartialHashLength); |
55 | 0 | } |
56 | 0 | } |
57 | | |
58 | 0 | nsAutoCString PartialHashHex() const { |
59 | 0 | nsAutoCString hex; |
60 | 0 | for (size_t i = 0; i < mPartialHashLength; i++) { |
61 | 0 | hex.AppendPrintf("%.2X", hash.complete.buf[i]); |
62 | 0 | } |
63 | 0 | return hex; |
64 | 0 | } |
65 | | |
66 | 0 | bool Confirmed() const { return mConfirmed || mProtocolConfirmed; } |
67 | | |
68 | | // True if we have a complete match for this hash in the table. |
69 | 0 | bool Complete() const { return mPartialHashLength == COMPLETE_SIZE; } |
70 | | |
71 | | // True if this is a noise entry, i.e. an extra entry |
72 | | // that is inserted to mask the true URL we are requesting. |
73 | | // Noise entries will not have a complete 256-bit hash as |
74 | | // they are fetched from the local 32-bit database and we |
75 | | // don't know the corresponding full URL. |
76 | | bool mNoise; |
77 | | |
78 | | bool mProtocolConfirmed; |
79 | | |
80 | | nsCString mTableName; |
81 | | |
82 | | uint32_t mPartialHashLength; |
83 | | |
84 | | // True as long as this lookup is complete and hasn't expired. |
85 | | bool mConfirmed; |
86 | | |
87 | | bool mProtocolV2; |
88 | | private: |
89 | 0 | ~LookupResult() {} |
90 | | }; |
91 | | |
92 | | typedef nsTArray<RefPtr<LookupResult>> LookupResultArray; |
93 | | |
94 | | class CacheResult { |
95 | | public: |
96 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheResult); |
97 | | |
98 | | enum { V2, V4 }; |
99 | | |
100 | | virtual int Ver() const = 0; |
101 | | virtual bool findCompletion(const Completion& aCompletion) const = 0; |
102 | | |
103 | | template<typename T> |
104 | 0 | static const T* Cast(const CacheResult* aThat) { |
105 | 0 | return ((aThat && T::VER == aThat->Ver()) ? |
106 | 0 | reinterpret_cast<const T*>(aThat) : nullptr); |
107 | 0 | } Unexecuted instantiation: mozilla::safebrowsing::CacheResultV2 const* mozilla::safebrowsing::CacheResult::Cast<mozilla::safebrowsing::CacheResultV2 const>(mozilla::safebrowsing::CacheResult const*) Unexecuted instantiation: mozilla::safebrowsing::CacheResultV4 const* mozilla::safebrowsing::CacheResult::Cast<mozilla::safebrowsing::CacheResultV4 const>(mozilla::safebrowsing::CacheResult const*) |
108 | | |
109 | | nsCString table; |
110 | | Prefix prefix; |
111 | | |
112 | | protected: |
113 | 0 | virtual ~CacheResult() {} |
114 | | }; |
115 | | |
116 | | class CacheResultV2 final : public CacheResult |
117 | | { |
118 | | public: |
119 | | static const int VER; |
120 | | |
121 | | // True when 'prefix' in CacheResult indicates a prefix that |
122 | | // cannot be completed. |
123 | | bool miss = false; |
124 | | |
125 | | // 'completion' and 'addChunk' are used when 'miss' field is false. |
126 | | Completion completion; |
127 | | uint32_t addChunk; |
128 | | |
129 | 0 | bool operator==(const CacheResultV2& aOther) const { |
130 | 0 | if (table != aOther.table || |
131 | 0 | prefix != aOther.prefix || |
132 | 0 | miss != aOther.miss) { |
133 | 0 | return false; |
134 | 0 | } |
135 | 0 | |
136 | 0 | if (miss) { |
137 | 0 | return true; |
138 | 0 | } |
139 | 0 | return completion == aOther.completion && addChunk == aOther.addChunk; |
140 | 0 | } |
141 | | |
142 | 0 | bool findCompletion(const Completion& aCompletion) const override { |
143 | 0 | return completion == aCompletion; |
144 | 0 | } |
145 | | |
146 | 0 | virtual int Ver() const override { return VER; } |
147 | | }; |
148 | | |
149 | | class CacheResultV4 final : public CacheResult |
150 | | { |
151 | | public: |
152 | | static const int VER; |
153 | | |
154 | | CachedFullHashResponse response; |
155 | | |
156 | 0 | bool operator==(const CacheResultV4& aOther) const { |
157 | 0 | return table == aOther.table && |
158 | 0 | prefix == aOther.prefix && |
159 | 0 | response == aOther.response; |
160 | 0 | } |
161 | | |
162 | 0 | bool findCompletion(const Completion& aCompletion) const override { |
163 | 0 | nsDependentCSubstring completion( |
164 | 0 | reinterpret_cast<const char*>(aCompletion.buf), COMPLETE_SIZE); |
165 | 0 | return response.fullHashes.Contains(completion); |
166 | 0 | } |
167 | | |
168 | 0 | virtual int Ver() const override { return VER; } |
169 | | }; |
170 | | |
171 | | typedef nsTArray<RefPtr<const CacheResult>> ConstCacheResultArray; |
172 | | |
173 | | class LookupCache { |
174 | | public: |
175 | | // Check for a canonicalized IP address. |
176 | | static bool IsCanonicalizedIP(const nsACString& aHost); |
177 | | |
178 | | // take a lookup string (www.hostname.com/path/to/resource.html) and |
179 | | // expand it into the set of fragments that should be searched for in an |
180 | | // entry |
181 | | static nsresult GetLookupFragments(const nsACString& aSpec, |
182 | | nsTArray<nsCString>* aFragments); |
183 | | // Similar to GetKey(), but if the domain contains three or more components, |
184 | | // two keys will be returned: |
185 | | // hostname.com/foo/bar -> [hostname.com] |
186 | | // mail.hostname.com/foo/bar -> [hostname.com, mail.hostname.com] |
187 | | // www.mail.hostname.com/foo/bar -> [hostname.com, mail.hostname.com] |
188 | | static nsresult GetHostKeys(const nsACString& aSpec, |
189 | | nsTArray<nsCString>* aHostKeys); |
190 | | |
191 | | LookupCache(const nsACString& aTableName, |
192 | | const nsACString& aProvider, |
193 | | nsCOMPtr<nsIFile>& aStoreFile); |
194 | | |
195 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LookupCache); |
196 | | |
197 | 0 | const nsCString &TableName() const { return mTableName; } |
198 | | |
199 | | // The directory handle where we operate will |
200 | | // be moved away when a backup is made. |
201 | | nsresult UpdateRootDirHandle(nsCOMPtr<nsIFile>& aRootStoreDirectory); |
202 | | |
203 | | // Write data stored in lookup cache to disk. |
204 | | nsresult WriteFile(); |
205 | | |
206 | 0 | bool IsPrimed() const { return mPrimed; }; |
207 | | |
208 | | // Called when update to clear expired entries. |
209 | | void InvalidateExpiredCacheEntries(); |
210 | | |
211 | | // Copy fullhash cache from another LookupCache. |
212 | | void CopyFullHashCache(const LookupCache* aSource); |
213 | | |
214 | | // Clear fullhash cache from fullhash/gethash response. |
215 | | void ClearCache(); |
216 | | |
217 | | // Check if completions can be found in cache. |
218 | | // Currently this is only used by testcase. |
219 | 0 | bool IsInCache(uint32_t key) const { return mFullHashCache.Get(key); }; |
220 | | |
221 | | #if DEBUG |
222 | | void DumpCache() const; |
223 | | #endif |
224 | | |
225 | | void GetCacheInfo(nsIUrlClassifierCacheInfo** aCache) const; |
226 | | |
227 | | virtual nsresult Open(); |
228 | | virtual nsresult Init() = 0; |
229 | | virtual nsresult ClearPrefixes() = 0; |
230 | | virtual nsresult Has(const Completion& aCompletion, |
231 | | bool* aHas, |
232 | | uint32_t* aMatchLength, |
233 | | bool* aConfirmed) = 0; |
234 | | |
235 | | virtual bool IsEmpty() const = 0; |
236 | | |
237 | | virtual void ClearAll(); |
238 | | |
239 | | template<typename T> |
240 | 0 | static T* Cast(LookupCache* aThat) { |
241 | 0 | return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<T*>(aThat) : nullptr); |
242 | 0 | } Unexecuted instantiation: mozilla::safebrowsing::LookupCacheV2* mozilla::safebrowsing::LookupCache::Cast<mozilla::safebrowsing::LookupCacheV2>(mozilla::safebrowsing::LookupCache*) Unexecuted instantiation: mozilla::safebrowsing::LookupCacheV4* mozilla::safebrowsing::LookupCache::Cast<mozilla::safebrowsing::LookupCacheV4>(mozilla::safebrowsing::LookupCache*) |
243 | | template<typename T> |
244 | 0 | static const T* Cast(const LookupCache* aThat) { |
245 | 0 | return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<const T*>(aThat) : nullptr); |
246 | 0 | } |
247 | | |
248 | | private: |
249 | | nsresult LoadPrefixSet(); |
250 | | |
251 | | virtual nsresult StoreToFile(nsCOMPtr<nsIFile>& aFile) = 0; |
252 | | virtual nsresult LoadFromFile(nsCOMPtr<nsIFile>& aFile) = 0; |
253 | | virtual size_t SizeOfPrefixSet() const = 0; |
254 | | |
255 | | virtual int Ver() const = 0; |
256 | | |
257 | | protected: |
258 | 0 | virtual ~LookupCache() {} |
259 | | |
260 | | // Check completions in positive cache and prefix in negative cache. |
261 | | // 'aHas' and 'aConfirmed' are output parameters. |
262 | | nsresult CheckCache(const Completion& aCompletion, |
263 | | bool* aHas, |
264 | | bool* aConfirmed); |
265 | | |
266 | | bool mPrimed; // true when the PrefixSet has been loaded (or constructed) |
267 | | const nsCString mTableName; |
268 | | const nsCString mProvider; |
269 | | nsCOMPtr<nsIFile> mRootStoreDirectory; |
270 | | nsCOMPtr<nsIFile> mStoreDirectory; |
271 | | |
272 | | // For gtest to inspect private members. |
273 | | friend class PerProviderDirectoryTestUtils; |
274 | | |
275 | | // Cache stores fullhash response(V4)/gethash response(V2) |
276 | | FullHashResponseMap mFullHashCache; |
277 | | }; |
278 | | |
279 | | typedef nsTArray<RefPtr<LookupCache>> LookupCacheArray; |
280 | | |
281 | | class LookupCacheV2 final : public LookupCache |
282 | | { |
283 | | public: |
284 | | explicit LookupCacheV2(const nsACString& aTableName, |
285 | | const nsACString& aProvider, |
286 | | nsCOMPtr<nsIFile>& aStoreFile) |
287 | 0 | : LookupCache(aTableName, aProvider, aStoreFile) {} |
288 | | |
289 | | virtual nsresult Init() override; |
290 | | virtual nsresult Open() override; |
291 | | virtual void ClearAll() override; |
292 | | virtual nsresult Has(const Completion& aCompletion, |
293 | | bool* aHas, |
294 | | uint32_t* aMatchLength, |
295 | | bool* aConfirmed) override; |
296 | | |
297 | | virtual bool IsEmpty() const override; |
298 | | |
299 | | nsresult Build(AddPrefixArray& aAddPrefixes, |
300 | | AddCompleteArray& aAddCompletes); |
301 | | |
302 | | nsresult GetPrefixes(FallibleTArray<uint32_t>& aAddPrefixes); |
303 | | |
304 | | // This will Clear() the passed arrays when done. |
305 | | // 'aExpirySec' is used by testcase to config an expired time. |
306 | | void AddGethashResultToCache(const AddCompleteArray& aAddCompletes, |
307 | | const MissPrefixArray& aMissPrefixes, |
308 | | int64_t aExpirySec = 0); |
309 | | |
310 | | #if DEBUG |
311 | | void DumpCompletions() const; |
312 | | #endif |
313 | | |
314 | | static const int VER; |
315 | | |
316 | | protected: |
317 | | nsresult ReadCompletions(); |
318 | | |
319 | | virtual nsresult ClearPrefixes() override; |
320 | | virtual nsresult StoreToFile(nsCOMPtr<nsIFile>& aFile) override; |
321 | | virtual nsresult LoadFromFile(nsCOMPtr<nsIFile>& aFile) override; |
322 | | virtual size_t SizeOfPrefixSet() const override; |
323 | | |
324 | | private: |
325 | 0 | ~LookupCacheV2() {} |
326 | | |
327 | 0 | virtual int Ver() const override { return VER; } |
328 | | |
329 | | // Construct a Prefix Set with known prefixes. |
330 | | // This will Clear() aAddPrefixes when done. |
331 | | nsresult ConstructPrefixSet(AddPrefixArray& aAddPrefixes); |
332 | | |
333 | | // Full length hashes obtained in update request |
334 | | CompletionArray mUpdateCompletions; |
335 | | |
336 | | // Set of prefixes known to be in the database |
337 | | RefPtr<nsUrlClassifierPrefixSet> mPrefixSet; |
338 | | }; |
339 | | |
340 | | } // namespace safebrowsing |
341 | | } // namespace mozilla |
342 | | |
343 | | #endif |