summaryrefslogtreecommitdiffstats
path: root/toolkit/components/url-classifier/LookupCache.h
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/url-classifier/LookupCache.h')
-rw-r--r--toolkit/components/url-classifier/LookupCache.h356
1 files changed, 356 insertions, 0 deletions
diff --git a/toolkit/components/url-classifier/LookupCache.h b/toolkit/components/url-classifier/LookupCache.h
new file mode 100644
index 0000000000..090f8eb733
--- /dev/null
+++ b/toolkit/components/url-classifier/LookupCache.h
@@ -0,0 +1,356 @@
+//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef LookupCache_h__
+#define LookupCache_h__
+
+#include "Entries.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "mozilla/RefPtr.h"
+#include "nsUrlClassifierPrefixSet.h"
+#include "VariableLengthPrefixSet.h"
+#include "mozilla/Logging.h"
+#include "mozilla/TypedEnumBits.h"
+#include "nsIUrlClassifierInfo.h"
+
+namespace mozilla {
+namespace safebrowsing {
+
+#define MAX_HOST_COMPONENTS 5
+#define MAX_PATH_COMPONENTS 4
+
+class LookupResult {
+ public:
+ LookupResult()
+ : mNoise(false),
+ mProtocolConfirmed(false),
+ mPartialHashLength(0),
+ mConfirmed(false),
+ mProtocolV2(true) {}
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LookupResult);
+
+ // The fragment that matched in the LookupCache
+ union {
+ Prefix fixedLengthPrefix;
+ Completion complete;
+ } hash;
+
+ const Completion& CompleteHash() const {
+ MOZ_ASSERT(!mNoise);
+ return hash.complete;
+ }
+
+ nsCString PartialHash() const {
+ MOZ_ASSERT(mPartialHashLength <= COMPLETE_SIZE);
+ if (mNoise) {
+ return nsCString(
+ reinterpret_cast<const char*>(hash.fixedLengthPrefix.buf),
+ PREFIX_SIZE);
+ } else {
+ return nsCString(reinterpret_cast<const char*>(hash.complete.buf),
+ mPartialHashLength);
+ }
+ }
+
+ nsAutoCString PartialHashHex() const {
+ nsAutoCString hex;
+ for (size_t i = 0; i < mPartialHashLength; i++) {
+ hex.AppendPrintf("%.2X", hash.complete.buf[i]);
+ }
+ return hex;
+ }
+
+ bool Confirmed() const { return mConfirmed || mProtocolConfirmed; }
+
+ // True if we have a complete match for this hash in the table.
+ bool Complete() const { return mPartialHashLength == COMPLETE_SIZE; }
+
+ // True if this is a noise entry, i.e. an extra entry
+ // that is inserted to mask the true URL we are requesting.
+ // Noise entries will not have a complete 256-bit hash as
+ // they are fetched from the local 32-bit database and we
+ // don't know the corresponding full URL.
+ bool mNoise;
+
+ bool mProtocolConfirmed;
+
+ nsCString mTableName;
+
+ uint32_t mPartialHashLength;
+
+ // True as long as this lookup is complete and hasn't expired.
+ bool mConfirmed;
+
+ bool mProtocolV2;
+
+ private:
+ ~LookupResult() = default;
+};
+
+typedef nsTArray<RefPtr<LookupResult>> LookupResultArray;
+
+class CacheResult {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheResult);
+
+ enum { V2, V4 };
+
+ virtual int Ver() const = 0;
+ virtual bool findCompletion(const Completion& aCompletion) const = 0;
+
+ template <typename T>
+ static const T* Cast(const CacheResult* aThat) {
+ return ((aThat && T::VER == aThat->Ver())
+ ? reinterpret_cast<const T*>(aThat)
+ : nullptr);
+ }
+
+ nsCString table;
+ Prefix prefix;
+
+ protected:
+ virtual ~CacheResult() = default;
+};
+
+class CacheResultV2 final : public CacheResult {
+ public:
+ static const int VER;
+
+ // True when 'prefix' in CacheResult indicates a prefix that
+ // cannot be completed.
+ bool miss = false;
+
+ // 'completion' and 'addChunk' are used when 'miss' field is false.
+ Completion completion;
+ uint32_t addChunk;
+
+ bool operator==(const CacheResultV2& aOther) const {
+ if (table != aOther.table || prefix != aOther.prefix ||
+ miss != aOther.miss) {
+ return false;
+ }
+
+ if (miss) {
+ return true;
+ }
+ return completion == aOther.completion && addChunk == aOther.addChunk;
+ }
+
+ bool findCompletion(const Completion& aCompletion) const override {
+ return completion == aCompletion;
+ }
+
+ virtual int Ver() const override { return VER; }
+};
+
+class CacheResultV4 final : public CacheResult {
+ public:
+ static const int VER;
+
+ CachedFullHashResponse response;
+
+ bool operator==(const CacheResultV4& aOther) const {
+ return table == aOther.table && prefix == aOther.prefix &&
+ response == aOther.response;
+ }
+
+ bool findCompletion(const Completion& aCompletion) const override {
+ nsDependentCSubstring completion(
+ reinterpret_cast<const char*>(aCompletion.buf), COMPLETE_SIZE);
+ return response.fullHashes.Contains(completion);
+ }
+
+ virtual int Ver() const override { return VER; }
+};
+
+typedef nsTArray<RefPtr<const CacheResult>> ConstCacheResultArray;
+
+class LookupCache {
+ public:
+ // Check for a canonicalized IP address.
+ static bool IsCanonicalizedIP(const nsACString& aHost);
+
+ // take a lookup string (www.hostname.com/path/to/resource.html) and
+ // expand it into the set of fragments that should be searched for in an
+ // entry
+ static nsresult GetLookupFragments(const nsACString& aSpec,
+ nsTArray<nsCString>* aFragments);
+
+ static nsresult GetLookupEntitylistFragments(const nsACString& aSpec,
+ nsTArray<nsCString>* aFragments);
+
+ LookupCache(const nsACString& aTableName, const nsACString& aProvider,
+ nsCOMPtr<nsIFile>& aStoreFile);
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LookupCache);
+
+ const nsCString& TableName() const { return mTableName; }
+
+ // The directory handle where we operate will
+ // be moved away when a backup is made.
+ nsresult UpdateRootDirHandle(nsCOMPtr<nsIFile>& aRootStoreDirectory);
+
+ // Write data stored in lookup cache to disk.
+ nsresult WriteFile();
+
+ bool IsPrimed() const { return mPrimed; };
+
+ // Called when update to clear expired entries.
+ void InvalidateExpiredCacheEntries();
+
+ // Copy fullhash cache from another LookupCache.
+ void CopyFullHashCache(const LookupCache* aSource);
+
+ // Clear fullhash cache from fullhash/gethash response.
+ void ClearCache();
+
+ // Check if completions can be found in cache.
+ // Currently this is only used by testcase.
+ bool IsInCache(uint32_t key) const { return mFullHashCache.Get(key); };
+
+ uint32_t PrefixLength() const {
+ return mVLPrefixSet->FixedLengthPrefixLength();
+ }
+
+#if DEBUG
+ void DumpCache() const;
+#endif
+
+ void GetCacheInfo(nsIUrlClassifierCacheInfo** aCache) const;
+
+ nsresult VerifyCRC32(nsCOMPtr<nsIInputStream>& aIn);
+
+ virtual nsresult Open();
+ virtual nsresult Init();
+ ;
+ virtual nsresult ClearPrefixes();
+ virtual nsresult Has(const Completion& aCompletion, bool* aHas,
+ uint32_t* aMatchLength, bool* aConfirmed) = 0;
+
+ // Prefix files file header
+ struct Header {
+ uint32_t magic;
+ uint32_t version;
+ };
+
+ virtual nsresult StoreToFile(nsCOMPtr<nsIFile>& aFile);
+ virtual nsresult LoadFromFile(nsCOMPtr<nsIFile>& aFile);
+
+ virtual bool IsEmpty() const;
+
+ virtual void ClearAll();
+
+ virtual nsresult LoadMozEntries() = 0;
+
+ template <typename T>
+ static T* Cast(LookupCache* aThat) {
+ return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<T*>(aThat)
+ : nullptr);
+ }
+ template <typename T>
+ static const T* Cast(const LookupCache* aThat) {
+ return ((aThat && T::VER == aThat->Ver())
+ ? reinterpret_cast<const T*>(aThat)
+ : nullptr);
+ }
+
+ private:
+ nsresult LoadPrefixSet();
+
+ virtual size_t SizeOfPrefixSet() const;
+ virtual nsCString GetPrefixSetSuffix() const = 0;
+
+ virtual int Ver() const = 0;
+
+ virtual void GetHeader(Header& aHeader) = 0;
+ virtual nsresult SanityCheck(const Header& aHeader) = 0;
+ virtual nsresult LoadLegacyFile() = 0;
+ virtual nsresult ClearLegacyFile() = 0;
+
+ protected:
+ virtual ~LookupCache() = default;
+
+ // Buffer size for file read/write
+ static const uint32_t MAX_BUFFER_SIZE;
+
+ // Check completions in positive cache and prefix in negative cache.
+ // 'aHas' and 'aConfirmed' are output parameters.
+ nsresult CheckCache(const Completion& aCompletion, bool* aHas,
+ bool* aConfirmed);
+
+ bool mPrimed; // true when the PrefixSet has been loaded (or constructed)
+ const nsCString mTableName;
+ const nsCString mProvider;
+ nsCOMPtr<nsIFile> mRootStoreDirectory;
+ nsCOMPtr<nsIFile> mStoreDirectory;
+
+ // For gtest to inspect private members.
+ friend class PerProviderDirectoryTestUtils;
+
+ // Cache stores fullhash response(V4)/gethash response(V2)
+ FullHashResponseMap mFullHashCache;
+
+ RefPtr<VariableLengthPrefixSet> mVLPrefixSet;
+
+ template <typename T>
+ static nsresult WriteValue(nsIOutputStream* aOutputStream, const T& aValue);
+ template <typename T>
+ static nsresult ReadValue(nsIInputStream* aInputStream, T& aValue);
+};
+
+typedef nsTArray<RefPtr<LookupCache>> LookupCacheArray;
+
+class LookupCacheV2 final : public LookupCache {
+ public:
+ explicit LookupCacheV2(const nsACString& aTableName,
+ const nsACString& aProvider,
+ nsCOMPtr<nsIFile>& aStoreFile)
+ : LookupCache(aTableName, aProvider, aStoreFile) {}
+
+ virtual nsresult Has(const Completion& aCompletion, bool* aHas,
+ uint32_t* aMatchLength, bool* aConfirmed) override;
+
+ nsresult Build(AddPrefixArray& aAddPrefixes, AddCompleteArray& aAddCompletes);
+
+ nsresult GetPrefixes(FallibleTArray<uint32_t>& aAddPrefixes);
+ nsresult GetPrefixes(FallibleTArray<uint32_t>& aAddPrefixes,
+ FallibleTArray<nsCString>& aAddCompletes);
+ nsresult GetPrefixByIndex(uint32_t aIndex, uint32_t* aOutPrefix) const;
+
+ // This will Clear() the passed arrays when done.
+ // 'aExpirySec' is used by testcase to config an expired time.
+ void AddGethashResultToCache(const AddCompleteArray& aAddCompletes,
+ const MissPrefixArray& aMissPrefixes,
+ int64_t aExpirySec = 0);
+
+ virtual nsresult LoadMozEntries() override;
+
+ static const int VER;
+ static const uint32_t VLPSET_MAGIC;
+ static const uint32_t VLPSET_VERSION;
+
+ protected:
+ virtual nsCString GetPrefixSetSuffix() const override;
+
+ private:
+ ~LookupCacheV2() = default;
+
+ virtual int Ver() const override { return VER; }
+
+ virtual void GetHeader(Header& aHeader) override;
+ virtual nsresult SanityCheck(const Header& aHeader) override;
+
+ virtual nsresult LoadLegacyFile() override;
+ virtual nsresult ClearLegacyFile() override;
+};
+
+} // namespace safebrowsing
+} // namespace mozilla
+
+#endif