mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-10-31 08:18:54 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			356 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			356 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //* -*- 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
 | 
