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 nsUrlClassifierDBService_h_ 7 #define nsUrlClassifierDBService_h_ 8 9 #include <nsISupportsUtils.h> 10 11 #include "nsID.h" 12 #include "nsInterfaceHashtable.h" 13 #include "nsIObserver.h" 14 #include "nsUrlClassifierPrefixSet.h" 15 #include "nsIUrlClassifierHashCompleter.h" 16 #include "nsIUrlClassifierDBService.h" 17 #include "nsIUrlClassifierInfo.h" 18 #include "nsIURIClassifier.h" 19 #include "mozilla/Attributes.h" 20 #include "mozilla/Mutex.h" 21 #include "mozilla/TimeStamp.h" 22 23 #include "Entries.h" 24 #include "LookupCache.h" 25 #include "HashStore.h" 26 27 // The hash length for a domain key. 28 #define DOMAIN_LENGTH 4 29 30 // The hash length of a partial hash entry. 31 #define PARTIAL_LENGTH 4 32 33 // The hash length of a complete hash entry. 34 #define COMPLETE_LENGTH 32 35 36 // Comma-separated lists 37 #define DISALLOW_COMPLETION_TABLE_PREF "urlclassifier.disallow_completions" 38 39 using namespace mozilla::safebrowsing; 40 41 class nsUrlClassifierDBServiceWorker; 42 class nsIThread; 43 class nsIURI; 44 class UrlClassifierDBServiceWorkerProxy; 45 46 namespace mozilla { 47 48 namespace safebrowsing { 49 class Classifier; 50 class ProtocolParser; 51 52 nsresult TablesToResponse(const nsACString& tables); 53 54 } // namespace safebrowsing 55 56 namespace net { 57 class AsyncUrlChannelClassifier; 58 } 59 60 } // namespace mozilla 61 62 // This is a proxy class that just creates a background thread and delegates 63 // calls to the background thread. 64 class nsUrlClassifierDBService final : public nsIUrlClassifierDBService, 65 public nsIURIClassifier, 66 public nsIUrlClassifierInfo, 67 public nsIObserver { 68 friend class mozilla::net::AsyncUrlChannelClassifier; 69 70 public: 71 class FeatureHolder; 72 73 // This is thread safe. It throws an exception if the thread is busy. 74 nsUrlClassifierDBService(); 75 76 nsresult Init(); 77 78 static already_AddRefed<nsUrlClassifierDBService> GetInstance( 79 nsresult* result); 80 81 NS_DECLARE_STATIC_IID_ACCESSOR(NS_URLCLASSIFIERDBSERVICE_CID) 82 83 NS_DECL_THREADSAFE_ISUPPORTS 84 NS_DECL_NSIURLCLASSIFIERDBSERVICE 85 NS_DECL_NSIURICLASSIFIER 86 NS_DECL_NSIURLCLASSIFIERINFO 87 NS_DECL_NSIOBSERVER 88 89 bool CanComplete(const nsACString& tableName); 90 bool GetCompleter(const nsACString& tableName, 91 nsIUrlClassifierHashCompleter** completer); 92 nsresult CacheCompletions( 93 const mozilla::safebrowsing::ConstCacheResultArray& results); 94 95 static nsIThread* BackgroundThread(); 96 97 static bool ShutdownHasStarted(); 98 99 private: 100 // This method is used only by AsyncUrlChannelClassifier. If you want to use 101 // it, please contact a safebrowsing/URL-Classifier peer. 102 static nsUrlClassifierDBServiceWorker* GetWorker(); 103 104 // No subclassing 105 ~nsUrlClassifierDBService(); 106 107 // Disallow copy constructor 108 nsUrlClassifierDBService(nsUrlClassifierDBService&); 109 110 nsresult LookupURI(const nsACString& aKey, FeatureHolder* aHolder, 111 nsIUrlClassifierCallback* c); 112 113 // Post an event to worker thread to release objects when receive 114 // 'quit-application' 115 nsresult PreShutdown(); 116 117 // Close db connection and join the background thread if it exists. 118 nsresult Shutdown(); 119 120 nsresult ReadDisallowCompletionsTablesFromPrefs(); 121 122 // This method checks if the classification can be done just using 123 // preferences. It returns true if the operation has been completed. 124 bool AsyncClassifyLocalWithFeaturesUsingPreferences( 125 nsIURI* aURI, const nsTArray<RefPtr<nsIUrlClassifierFeature>>& aFeatures, 126 nsIUrlClassifierFeature::listType aListType, 127 nsIUrlClassifierFeatureCallback* aCallback); 128 129 RefPtr<nsUrlClassifierDBServiceWorker> mWorker; 130 RefPtr<UrlClassifierDBServiceWorkerProxy> mWorkerProxy; 131 132 nsInterfaceHashtable<nsCStringHashKey, nsIUrlClassifierHashCompleter> 133 mCompleters; 134 135 // TRUE if a BeginUpdate() has been called without an accompanying 136 // CancelUpdate()/FinishUpdate(). This is used to prevent competing 137 // updates, not to determine whether an update is still being 138 // processed. 139 bool mInUpdate; 140 141 // The list of tables that should never be hash completed. 142 nsTArray<nsCString> mDisallowCompletionsTables; 143 144 // Thread that we do the updates on. 145 static nsIThread* gDbBackgroundThread; 146 }; 147 148 class nsUrlClassifierDBServiceWorker final : public nsIUrlClassifierDBService { 149 public: 150 nsUrlClassifierDBServiceWorker(); 151 152 NS_DECL_THREADSAFE_ISUPPORTS 153 NS_DECL_NSIURLCLASSIFIERDBSERVICE 154 155 nsresult Init(uint32_t aGethashNoise, nsCOMPtr<nsIFile> aCacheDir, 156 nsUrlClassifierDBService* aDBService); 157 158 // Queue a lookup for the worker to perform, called in the main thread. 159 nsresult QueueLookup(const nsACString& aLookupKey, 160 nsUrlClassifierDBService::FeatureHolder* aFeatureHolder, 161 nsIUrlClassifierLookupCallback* aLallback); 162 163 // Handle any queued-up lookups. We call this function during long-running 164 // update operations to prevent lookups from blocking for too long. 165 nsresult HandlePendingLookups(); 166 167 // Perform a blocking classifier lookup for a given url fragments set. 168 // Can be called on either the main thread or the worker thread. 169 nsresult DoSingleLocalLookupWithURIFragments( 170 const nsTArray<nsCString>& aSpecFragments, const nsACString& aTable, 171 LookupResultArray& aResults); 172 173 // Open the DB connection 174 nsresult OpenDb(); 175 176 // Provide a way to forcibly close the db connection. 177 nsresult CloseDb(); 178 179 nsresult PreShutdown(); 180 181 nsresult CacheCompletions(const ConstCacheResultArray& aEntries); 182 183 // Used to probe the state of the worker thread. When the update begins, 184 // mUpdateObserver will be set. When the update finished, mUpdateObserver 185 // will be nulled out in NotifyUpdateObserver. IsBusyUpdating()186 bool IsBusyUpdating() const { return !!mUpdateObserver; } 187 188 // Check the DB ready state of the worker thread IsDBOpened()189 bool IsDBOpened() const { return !!mClassifier; } 190 191 // Delegate Classifier to disable async update. If there is an 192 // ongoing update on the update thread, we will be blocked until 193 // the background update is done and callback is fired. 194 // Should be called on the worker thread. 195 void FlushAndDisableAsyncUpdate(); 196 197 // A synchronous call to get cache information for the given table. 198 // This is only used by about:url-classifier now. 199 nsresult GetCacheInfo(const nsACString& aTable, 200 nsIUrlClassifierCacheInfo** aCache); 201 202 private: 203 // No subclassing 204 ~nsUrlClassifierDBServiceWorker(); 205 206 // Disallow copy constructor 207 nsUrlClassifierDBServiceWorker(nsUrlClassifierDBServiceWorker&); 208 209 nsresult NotifyUpdateObserver(nsresult aUpdateStatus); 210 211 // Reset the in-progress update stream 212 void ResetStream(); 213 214 // Reset the in-progress update 215 void ResetUpdate(); 216 217 // Perform a classifier lookup for a given url. 218 nsresult DoLookup(const nsACString& spec, 219 nsUrlClassifierDBService::FeatureHolder* aFeatureHolder, 220 nsIUrlClassifierLookupCallback* c); 221 222 nsresult AddNoise(const Prefix aPrefix, const nsCString tableName, 223 uint32_t aCount, LookupResultArray& results); 224 225 nsresult CacheResultToTableUpdate(RefPtr<const CacheResult> aCacheResult, 226 RefPtr<TableUpdate> aUpdate); 227 228 bool IsSameAsLastResults(const ConstCacheResultArray& aResult) const; 229 230 RefPtr<mozilla::safebrowsing::Classifier> mClassifier; 231 // The class that actually parses the update chunks. 232 mozilla::UniquePtr<ProtocolParser> mProtocolParser; 233 234 // Directory where to store the SB databases. 235 nsCOMPtr<nsIFile> mCacheDir; 236 237 RefPtr<nsUrlClassifierDBService> mDBService; 238 239 TableUpdateArray mTableUpdates; 240 241 uint32_t mUpdateWaitSec; 242 243 // Stores the last results that triggered a table update. 244 ConstCacheResultArray mLastResults; 245 246 nsresult mUpdateStatus; 247 nsTArray<nsCString> mUpdateTables; 248 249 nsCOMPtr<nsIUrlClassifierUpdateObserver> mUpdateObserver; 250 bool mInStream; 251 252 // The number of noise entries to add to the set of lookup results. 253 uint32_t mGethashNoise; 254 255 // Pending lookups are stored in a queue for processing. The queue 256 // is protected by mPendingLookupLock. 257 mozilla::Mutex mPendingLookupLock; 258 259 class PendingLookup { 260 public: 261 mozilla::TimeStamp mStartTime; 262 nsCString mKey; 263 RefPtr<nsUrlClassifierDBService::FeatureHolder> mFeatureHolder; 264 nsCOMPtr<nsIUrlClassifierLookupCallback> mCallback; 265 }; 266 267 // list of pending lookups 268 nsTArray<PendingLookup> mPendingLookups; 269 270 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES 271 // The raw update response for debugging. 272 nsCString mRawTableUpdates; 273 #endif 274 }; 275 276 NS_DEFINE_STATIC_IID_ACCESSOR(nsUrlClassifierDBService, 277 NS_URLCLASSIFIERDBSERVICE_CID) 278 279 #endif // nsUrlClassifierDBService_h_ 280