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