/src/mozilla-central/toolkit/components/url-classifier/HashStore.h
Line | Count | Source (jump to first uncovered line) |
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 HashStore_h__ |
6 | | #define HashStore_h__ |
7 | | |
8 | | #include "Entries.h" |
9 | | #include "ChunkSet.h" |
10 | | |
11 | | #include "nsString.h" |
12 | | #include "nsTArray.h" |
13 | | #include "nsIFile.h" |
14 | | #include "nsIFileStreams.h" |
15 | | #include "nsISupports.h" |
16 | | #include "nsCOMPtr.h" |
17 | | #include "nsClassHashtable.h" |
18 | | #include <string> |
19 | | |
20 | | namespace mozilla { |
21 | | namespace safebrowsing { |
22 | | |
23 | | // The abstract class of TableUpdateV2 and TableUpdateV4. This |
24 | | // is convenient for passing the TableUpdate* around associated |
25 | | // with v2 and v4 instance. |
26 | | class TableUpdate { |
27 | | public: |
28 | | TableUpdate(const nsACString& aTable) |
29 | | : mTable(aTable) |
30 | 0 | { |
31 | 0 | } |
32 | | |
33 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TableUpdate); |
34 | | |
35 | | // To be overriden. |
36 | | virtual bool Empty() const = 0; |
37 | | |
38 | | // Common interfaces. |
39 | 0 | const nsCString& TableName() const { return mTable; } |
40 | | |
41 | | template<typename T> |
42 | 0 | static T* Cast(TableUpdate* aThat) { |
43 | 0 | return (T::TAG == aThat->Tag() ? reinterpret_cast<T*>(aThat) : nullptr); |
44 | 0 | } Unexecuted instantiation: mozilla::safebrowsing::TableUpdateV2* mozilla::safebrowsing::TableUpdate::Cast<mozilla::safebrowsing::TableUpdateV2>(mozilla::safebrowsing::TableUpdate*) Unexecuted instantiation: mozilla::safebrowsing::TableUpdateV4* mozilla::safebrowsing::TableUpdate::Cast<mozilla::safebrowsing::TableUpdateV4>(mozilla::safebrowsing::TableUpdate*) |
45 | | template<typename T> |
46 | 0 | static const T* Cast(const TableUpdate* aThat) { |
47 | 0 | return (T::TAG == aThat->Tag() ? reinterpret_cast<const T*>(aThat) : nullptr); |
48 | 0 | } Unexecuted instantiation: mozilla::safebrowsing::TableUpdateV2 const* mozilla::safebrowsing::TableUpdate::Cast<mozilla::safebrowsing::TableUpdateV2>(mozilla::safebrowsing::TableUpdate const*) Unexecuted instantiation: mozilla::safebrowsing::TableUpdateV4 const* mozilla::safebrowsing::TableUpdate::Cast<mozilla::safebrowsing::TableUpdateV4>(mozilla::safebrowsing::TableUpdate const*) |
49 | | |
50 | | protected: |
51 | 0 | virtual ~TableUpdate() {} |
52 | | |
53 | | private: |
54 | | virtual int Tag() const = 0; |
55 | | |
56 | | const nsCString mTable; |
57 | | }; |
58 | | |
59 | | typedef nsTArray<RefPtr<TableUpdate>> TableUpdateArray; |
60 | | typedef nsTArray<RefPtr<const TableUpdate>> ConstTableUpdateArray; |
61 | | |
62 | | // A table update is built from a single update chunk from the server. As the |
63 | | // protocol parser processes each chunk, it constructs a table update with the |
64 | | // new hashes. |
65 | | class TableUpdateV2 : public TableUpdate { |
66 | | public: |
67 | | explicit TableUpdateV2(const nsACString& aTable) |
68 | 0 | : TableUpdate(aTable) {} |
69 | | |
70 | 0 | bool Empty() const override { |
71 | 0 | return mAddChunks.Length() == 0 && |
72 | 0 | mSubChunks.Length() == 0 && |
73 | 0 | mAddExpirations.Length() == 0 && |
74 | 0 | mSubExpirations.Length() == 0 && |
75 | 0 | mAddPrefixes.Length() == 0 && |
76 | 0 | mSubPrefixes.Length() == 0 && |
77 | 0 | mAddCompletes.Length() == 0 && |
78 | 0 | mSubCompletes.Length() == 0 && |
79 | 0 | mMissPrefixes.Length() == 0; |
80 | 0 | } |
81 | | |
82 | | // Throughout, uint32_t aChunk refers only to the chunk number. Chunk data is |
83 | | // stored in the Prefix structures. |
84 | 0 | MOZ_MUST_USE nsresult NewAddChunk(uint32_t aChunk) { |
85 | 0 | return mAddChunks.Set(aChunk); |
86 | 0 | }; |
87 | 0 | MOZ_MUST_USE nsresult NewSubChunk(uint32_t aChunk) { |
88 | 0 | return mSubChunks.Set(aChunk); |
89 | 0 | }; |
90 | 0 | MOZ_MUST_USE nsresult NewAddExpiration(uint32_t aChunk) { |
91 | 0 | return mAddExpirations.Set(aChunk); |
92 | 0 | }; |
93 | 0 | MOZ_MUST_USE nsresult NewSubExpiration(uint32_t aChunk) { |
94 | 0 | return mSubExpirations.Set(aChunk); |
95 | 0 | }; |
96 | | MOZ_MUST_USE nsresult NewAddPrefix(uint32_t aAddChunk, const Prefix& aPrefix); |
97 | | MOZ_MUST_USE nsresult NewSubPrefix(uint32_t aAddChunk, |
98 | | const Prefix& aPrefix, |
99 | | uint32_t aSubChunk); |
100 | | MOZ_MUST_USE nsresult NewAddComplete(uint32_t aChunk, |
101 | | const Completion& aCompletion); |
102 | | MOZ_MUST_USE nsresult NewSubComplete(uint32_t aAddChunk, |
103 | | const Completion& aCompletion, |
104 | | uint32_t aSubChunk); |
105 | | MOZ_MUST_USE nsresult NewMissPrefix(const Prefix& aPrefix); |
106 | | |
107 | 0 | const ChunkSet& AddChunks() const { return mAddChunks; } |
108 | 0 | const ChunkSet& SubChunks() const { return mSubChunks; } |
109 | | |
110 | | // Expirations for chunks. |
111 | 0 | const ChunkSet& AddExpirations() const { return mAddExpirations; } |
112 | 0 | const ChunkSet& SubExpirations() const { return mSubExpirations; } |
113 | | |
114 | | // Hashes associated with this chunk. |
115 | 0 | AddPrefixArray& AddPrefixes() { return mAddPrefixes; } |
116 | 0 | SubPrefixArray& SubPrefixes() { return mSubPrefixes; } |
117 | 0 | const AddCompleteArray& AddCompletes() const { return mAddCompletes; } |
118 | 0 | AddCompleteArray& AddCompletes() { return mAddCompletes; } |
119 | 0 | SubCompleteArray& SubCompletes() { return mSubCompletes; } |
120 | | |
121 | | // Entries that cannot be completed. |
122 | 0 | const MissPrefixArray& MissPrefixes() const { return mMissPrefixes; } |
123 | | |
124 | | // For downcasting. |
125 | | static const int TAG = 2; |
126 | | |
127 | | private: |
128 | | |
129 | | // The list of chunk numbers that we have for each of the type of chunks. |
130 | | ChunkSet mAddChunks; |
131 | | ChunkSet mSubChunks; |
132 | | ChunkSet mAddExpirations; |
133 | | ChunkSet mSubExpirations; |
134 | | |
135 | | // 4-byte sha256 prefixes. |
136 | | AddPrefixArray mAddPrefixes; |
137 | | SubPrefixArray mSubPrefixes; |
138 | | |
139 | | // This is only used by gethash so don't add this to Header. |
140 | | MissPrefixArray mMissPrefixes; |
141 | | |
142 | | // 32-byte hashes. |
143 | | AddCompleteArray mAddCompletes; |
144 | | SubCompleteArray mSubCompletes; |
145 | | |
146 | 0 | virtual int Tag() const override { return TAG; } |
147 | | }; |
148 | | |
149 | | // Structure for DBService/HashStore/Classifiers to update. |
150 | | // It would contain the prefixes (both fixed and variable length) |
151 | | // for addition and indices to removal. See Bug 1283009. |
152 | | class TableUpdateV4 : public TableUpdate { |
153 | | public: |
154 | | typedef nsTArray<int32_t> RemovalIndiceArray; |
155 | | |
156 | | public: |
157 | | explicit TableUpdateV4(const nsACString& aTable) |
158 | | : TableUpdate(aTable) |
159 | | , mFullUpdate(false) |
160 | 0 | { |
161 | 0 | } |
162 | | |
163 | | bool Empty() const override |
164 | 0 | { |
165 | 0 | return mPrefixesMap.IsEmpty() && |
166 | 0 | mRemovalIndiceArray.IsEmpty() && |
167 | 0 | mFullHashResponseMap.IsEmpty(); |
168 | 0 | } |
169 | | |
170 | 0 | bool IsFullUpdate() const { return mFullUpdate; } |
171 | 0 | const PrefixStringMap& Prefixes() const { return mPrefixesMap; } |
172 | 0 | const RemovalIndiceArray& RemovalIndices() const { return mRemovalIndiceArray; } |
173 | 0 | const nsACString& ClientState() const { return mClientState; } |
174 | 0 | const nsACString& Checksum() const { return mChecksum; } |
175 | 0 | const FullHashResponseMap& FullHashResponse() const { return mFullHashResponseMap; } |
176 | | |
177 | | // For downcasting. |
178 | | static const int TAG = 4; |
179 | | |
180 | 0 | void SetFullUpdate(bool aIsFullUpdate) { mFullUpdate = aIsFullUpdate; } |
181 | | void NewPrefixes(int32_t aSize, const nsACString& aPrefixes); |
182 | 0 | void SetNewClientState(const nsACString& aState) { mClientState = aState; } |
183 | | void NewChecksum(const std::string& aChecksum); |
184 | | |
185 | | nsresult NewRemovalIndices(const uint32_t* aIndices, size_t aNumOfIndices); |
186 | | nsresult NewFullHashResponse(const Prefix& aPrefix, |
187 | | const CachedFullHashResponse& aResponse); |
188 | | |
189 | | private: |
190 | 0 | virtual int Tag() const override { return TAG; } |
191 | | |
192 | | bool mFullUpdate; |
193 | | PrefixStringMap mPrefixesMap; |
194 | | RemovalIndiceArray mRemovalIndiceArray; |
195 | | nsCString mClientState; |
196 | | nsCString mChecksum; |
197 | | |
198 | | // This is used to store response from fullHashes.find. |
199 | | FullHashResponseMap mFullHashResponseMap; |
200 | | }; |
201 | | |
202 | | // There is one hash store per table. |
203 | | class HashStore { |
204 | | public: |
205 | | HashStore(const nsACString& aTableName, |
206 | | const nsACString& aProvider, |
207 | | nsIFile* aRootStoreFile); |
208 | | ~HashStore(); |
209 | | |
210 | 0 | const nsCString& TableName() const { return mTableName; } |
211 | | |
212 | | nsresult Open(); |
213 | | // Add Prefixes are stored partly in the PrefixSet (contains the |
214 | | // Prefix data organized for fast lookup/low RAM usage) and partly in the |
215 | | // HashStore (Add Chunk numbers - only used for updates, slow retrieval). |
216 | | // AugmentAdds function joins the separate datasets into one complete |
217 | | // prefixes+chunknumbers dataset. |
218 | | nsresult AugmentAdds(const nsTArray<uint32_t>& aPrefixes); |
219 | | |
220 | | ChunkSet& AddChunks(); |
221 | | ChunkSet& SubChunks(); |
222 | 0 | AddPrefixArray& AddPrefixes() { return mAddPrefixes; } |
223 | 0 | SubPrefixArray& SubPrefixes() { return mSubPrefixes; } |
224 | | AddCompleteArray& AddCompletes(); |
225 | | SubCompleteArray& SubCompletes(); |
226 | | |
227 | | // ======= |
228 | | // Updates |
229 | | // ======= |
230 | | // Begin the update process. Reads the store into memory. |
231 | | nsresult BeginUpdate(); |
232 | | |
233 | | // Imports the data from a TableUpdate. |
234 | | nsresult ApplyUpdate(RefPtr<TableUpdateV2> aUpdate); |
235 | | |
236 | | // Process expired chunks |
237 | | nsresult Expire(); |
238 | | |
239 | | // Rebuild the store, Incorporating all the applied updates. |
240 | | nsresult Rebuild(); |
241 | | |
242 | | // Write the current state of the store to disk. |
243 | | // If you call between ApplyUpdate() and Rebuild(), you'll |
244 | | // have a mess on your hands. |
245 | | nsresult WriteFile(); |
246 | | |
247 | | // Wipe out all Completes. |
248 | | void ClearCompletes(); |
249 | | |
250 | | private: |
251 | | nsresult Reset(); |
252 | | |
253 | | nsresult ReadHeader(); |
254 | | nsresult SanityCheck() const; |
255 | | nsresult CalculateChecksum(nsAutoCString& aChecksum, uint32_t aFileSize, |
256 | | bool aChecksumPresent); |
257 | | nsresult CheckChecksum(uint32_t aFileSize); |
258 | | void UpdateHeader(); |
259 | | |
260 | | nsresult ReadCompletions(); |
261 | | nsresult ReadChunkNumbers(); |
262 | | nsresult ReadHashes(); |
263 | | |
264 | | nsresult ReadAddPrefixes(); |
265 | | nsresult ReadSubPrefixes(); |
266 | | |
267 | | nsresult WriteAddPrefixes(nsIOutputStream* aOut); |
268 | | nsresult WriteSubPrefixes(nsIOutputStream* aOut); |
269 | | |
270 | | nsresult ProcessSubs(); |
271 | | |
272 | | nsresult PrepareForUpdate(); |
273 | | |
274 | | bool AlreadyReadChunkNumbers() const; |
275 | | bool AlreadyReadCompletions() const; |
276 | | |
277 | | // This is used for checking that the database is correct and for figuring out |
278 | | // the number of chunks, etc. to read from disk on restart. |
279 | | struct Header { |
280 | | uint32_t magic; |
281 | | uint32_t version; |
282 | | uint32_t numAddChunks; |
283 | | uint32_t numSubChunks; |
284 | | uint32_t numAddPrefixes; |
285 | | uint32_t numSubPrefixes; |
286 | | uint32_t numAddCompletes; |
287 | | uint32_t numSubCompletes; |
288 | | }; |
289 | | |
290 | | Header mHeader; |
291 | | |
292 | | // The name of the table (must end in -shavar or -digest256, or evidently |
293 | | // -simple for unittesting. |
294 | | const nsCString mTableName; |
295 | | nsCOMPtr<nsIFile> mStoreDirectory; |
296 | | |
297 | | bool mInUpdate; |
298 | | |
299 | | nsCOMPtr<nsIInputStream> mInputStream; |
300 | | |
301 | | // Chunk numbers, stored as uint32_t arrays. |
302 | | ChunkSet mAddChunks; |
303 | | ChunkSet mSubChunks; |
304 | | |
305 | | ChunkSet mAddExpirations; |
306 | | ChunkSet mSubExpirations; |
307 | | |
308 | | // Chunk data for shavar tables. See Entries.h for format. |
309 | | AddPrefixArray mAddPrefixes; |
310 | | SubPrefixArray mSubPrefixes; |
311 | | |
312 | | // See bug 806422 for background. We must be able to distinguish between |
313 | | // updates from the completion server and updates from the regular server. |
314 | | AddCompleteArray mAddCompletes; |
315 | | SubCompleteArray mSubCompletes; |
316 | | |
317 | | uint32_t mFileSize; |
318 | | |
319 | | // For gtest to inspect private members. |
320 | | friend class PerProviderDirectoryTestUtils; |
321 | | }; |
322 | | |
323 | | } // namespace safebrowsing |
324 | | } // namespace mozilla |
325 | | |
326 | | #endif |