HashStore.h 8.9 KB

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