LCOV - app.info - toolkit/components/url-classifier/nsUrlClassifierDBService.cpp

LCOV - code coverage report
| Current view: | directory - toolkit/components/url-classifier - nsUrlClassifierDBService.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 595 | 481 | 80.8 %
| Date: | 2012-04-21 | Functions: | 71 | 63 | 88.7 %

           1                 : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is Url Classifier code
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Google Inc.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2006
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Tony Chang <tony@ponderer.org> (original author)
          24                 :  *   Brett Wilson <brettw@gmail.com>
          25                 :  *   Dave Camp <dcamp@mozilla.com>
          26                 :  *   David Dahl <ddahl@mozilla.com>
          27                 :  *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
          28                 :  *
          29                 :  * Alternatively, the contents of this file may be used under the terms of
          30                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          31                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          33                 :  * of those above. If you wish to allow use of your version of this file only
          34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          35                 :  * use your version of this file under the terms of the MPL, indicate your
          36                 :  * decision by deleting the provisions above and replace them with the notice
          37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          38                 :  * the provisions above, a recipient may use your version of this file under
          39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          40                 :  *
          41                 :  * ***** END LICENSE BLOCK ***** */
          42                 :
          43                 : #include "nsAutoPtr.h"
          44                 : #include "nsCOMPtr.h"
          45                 : #include "nsAppDirectoryServiceDefs.h"
          46                 : #include "nsCRT.h"
          47                 : #include "nsICryptoHash.h"
          48                 : #include "nsICryptoHMAC.h"
          49                 : #include "nsIDirectoryService.h"
          50                 : #include "nsIKeyModule.h"
          51                 : #include "nsIObserverService.h"
          52                 : #include "nsIPermissionManager.h"
          53                 : #include "nsIPrefBranch.h"
          54                 : #include "nsIPrefService.h"
          55                 : #include "nsIProperties.h"
          56                 : #include "nsToolkitCompsCID.h"
          57                 : #include "nsIUrlClassifierUtils.h"
          58                 : #include "nsUrlClassifierDBService.h"
          59                 : #include "nsUrlClassifierUtils.h"
          60                 : #include "nsUrlClassifierProxies.h"
          61                 : #include "nsURILoader.h"
          62                 : #include "nsString.h"
          63                 : #include "nsReadableUtils.h"
          64                 : #include "nsTArray.h"
          65                 : #include "nsNetUtil.h"
          66                 : #include "nsNetCID.h"
          67                 : #include "nsThreadUtils.h"
          68                 : #include "nsXPCOMStrings.h"
          69                 : #include "nsProxyRelease.h"
          70                 : #include "mozilla/Mutex.h"
          71                 : #include "mozilla/TimeStamp.h"
          72                 : #include "mozilla/Telemetry.h"
          73                 : #include "prlog.h"
          74                 : #include "prprf.h"
          75                 : #include "prnetdb.h"
          76                 : #include "Entries.h"
          77                 : #include "Classifier.h"
          78                 : #include "ProtocolParser.h"
          79                 :
          80                 : using namespace mozilla;
          81                 : using namespace mozilla::safebrowsing;
          82                 :
          83                 : // NSPR_LOG_MODULES=UrlClassifierDbService:5
          84                 : #if defined(PR_LOGGING)
          85                 : PRLogModuleInfo *gUrlClassifierDbServiceLog = nsnull;
          86                 : #define LOG(args) PR_LOG(gUrlClassifierDbServiceLog, PR_LOG_DEBUG, args)
          87                 : #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierDbServiceLog, 4)
          88                 : #else
          89                 : #define LOG(args)
          90                 : #define LOG_ENABLED() (false)
          91                 : #endif
          92                 :
          93                 : // Prefs for implementing nsIURIClassifier to block page loads
          94                 : #define CHECK_MALWARE_PREF      "browser.safebrowsing.malware.enabled"
          95                 : #define CHECK_MALWARE_DEFAULT   false
          96                 :
          97                 : #define CHECK_PHISHING_PREF     "browser.safebrowsing.enabled"
          98                 : #define CHECK_PHISHING_DEFAULT  false
          99                 :
         100                 : #define GETHASH_NOISE_PREF      "urlclassifier.gethashnoise"
         101                 : #define GETHASH_NOISE_DEFAULT   4
         102                 :
         103                 : #define GETHASH_TABLES_PREF     "urlclassifier.gethashtables"
         104                 :
         105                 : #define CONFIRM_AGE_PREF        "urlclassifier.confirm-age"
         106                 : #define CONFIRM_AGE_DEFAULT_SEC (45 * 60)
         107                 :
         108                 : class nsUrlClassifierDBServiceWorker;
         109                 :
         110                 : // Singleton instance.
         111                 : static nsUrlClassifierDBService* sUrlClassifierDBService;
         112                 :
         113                 : nsIThread* nsUrlClassifierDBService::gDbBackgroundThread = nsnull;
         114                 :
         115                 : // Once we've committed to shutting down, don't do work in the background
         116                 : // thread.
         117                 : static bool gShuttingDownThread = false;
         118                 :
         119                 : static PRInt32 gFreshnessGuarantee = CONFIRM_AGE_DEFAULT_SEC;
         120                 :
         121                 : static void
         122              84 : SplitTables(const nsACString& str, nsTArray<nsCString>& tables)
         123                 : {
         124              84 :   tables.Clear();
         125                 :
         126              84 :   nsACString::const_iterator begin, iter, end;
         127              84 :   str.BeginReading(begin);
         128              84 :   str.EndReading(end);
         129             335 :   while (begin != end) {
         130             167 :     iter = begin;
         131             167 :     FindCharInReadable(',', iter, end);
         132             167 :     tables.AppendElement(Substring(begin, iter));
         133             167 :     begin = iter;
         134             167 :     if (begin != end)
         135              83 :       begin++;
         136                 :   }
         137              84 : }
         138                 :
         139                 : // -------------------------------------------------------------------------
         140                 : // Actual worker implemenatation
         141                 : class nsUrlClassifierDBServiceWorker : public nsIUrlClassifierDBServiceWorker
         142                 : {
         143                 : public:
         144                 :   nsUrlClassifierDBServiceWorker();
         145                 :
         146                 :   NS_DECL_ISUPPORTS
         147                 :   NS_DECL_NSIURLCLASSIFIERDBSERVICE
         148                 :   NS_DECL_NSIURLCLASSIFIERDBSERVICEWORKER
         149                 :
         150                 :   // Initialize, called in the main thread
         151                 :   nsresult Init(PRInt32 gethashNoise, nsCOMPtr<nsIFile> aCacheDir);
         152                 :
         153                 :   // Queue a lookup for the worker to perform, called in the main thread.
         154                 :   nsresult QueueLookup(const nsACString& lookupKey,
         155                 :                        nsIUrlClassifierLookupCallback* callback);
         156                 :
         157                 :   // Handle any queued-up lookups.  We call this function during long-running
         158                 :   // update operations to prevent lookups from blocking for too long.
         159                 :   nsresult HandlePendingLookups();
         160                 :
         161                 : private:
         162                 :   // No subclassing
         163                 :   ~nsUrlClassifierDBServiceWorker();
         164                 :
         165                 :   // Disallow copy constructor
         166                 :   nsUrlClassifierDBServiceWorker(nsUrlClassifierDBServiceWorker&);
         167                 :
         168                 :   nsresult OpenDb();
         169                 :
         170                 :   // Applies the current transaction and resets the update/working times.
         171                 :   nsresult ApplyUpdate();
         172                 :
         173                 :   // Reset the in-progress update stream
         174                 :   void ResetStream();
         175                 :
         176                 :  // Reset the in-progress update
         177                 :  void ResetUpdate();
         178                 :
         179                 :   // Perform a classifier lookup for a given url.
         180                 :   nsresult DoLookup(const nsACString& spec, nsIUrlClassifierLookupCallback* c);
         181                 :
         182                 :   // Add entries to the results.
         183                 :   nsresult AddNoise(const Prefix aPrefix,
         184                 :                     const nsCString tableName,
         185                 :                     PRInt32 aCount,
         186                 :                     LookupResultArray& results);
         187                 :
         188                 :   nsCOMPtr<nsICryptoHash> mCryptoHash;
         189                 :
         190                 :   nsAutoPtr<Classifier> mClassifier;
         191                 :   nsAutoPtr<ProtocolParser> mProtocolParser;
         192                 :
         193                 :   // Directory where to store the SB databases.
         194                 :   nsCOMPtr<nsIFile> mCacheDir;
         195                 :
         196                 :   // XXX: maybe an array of autoptrs.  Or maybe a class specifically
         197                 :   // storing a series of updates.
         198                 :   nsTArray<TableUpdate*> mTableUpdates;
         199                 :
         200                 :   PRInt32 mUpdateWait;
         201                 :
         202                 :   // Entries that cannot be completed. We expect them to die at
         203                 :   // the next update
         204                 :   PrefixArray mMissCache;
         205                 :
         206                 :   nsresult mUpdateStatus;
         207                 :   nsTArray<nsCString> mUpdateTables;
         208                 :
         209                 :   nsCOMPtr<nsIUrlClassifierUpdateObserver> mUpdateObserver;
         210                 :   bool mInStream;
         211                 :
         212                 :   // The client key with which the data from the server will be MAC'ed.
         213                 :   nsCString mUpdateClientKey;
         214                 :
         215                 :   // The client-specific hash key to rehash
         216                 :   PRUint32 mHashKey;
         217                 :
         218                 :   // The number of noise entries to add to the set of lookup results.
         219                 :   PRInt32 mGethashNoise;
         220                 :
         221                 :   // Pending lookups are stored in a queue for processing.  The queue
         222                 :   // is protected by mPendingLookupLock.
         223                 :   Mutex mPendingLookupLock;
         224                 :
         225             560 :   class PendingLookup {
         226                 :   public:
         227                 :     TimeStamp mStartTime;
         228                 :     nsCString mKey;
         229                 :     nsCOMPtr<nsIUrlClassifierLookupCallback> mCallback;
         230                 :   };
         231                 :
         232                 :   // list of pending lookups
         233                 :   nsTArray<PendingLookup> mPendingLookups;
         234                 : };
         235                 :
         236            4023 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsUrlClassifierDBServiceWorker,
         237                 :                               nsIUrlClassifierDBServiceWorker,
         238                 :                               nsIUrlClassifierDBService)
         239                 :
         240               7 : nsUrlClassifierDBServiceWorker::nsUrlClassifierDBServiceWorker()
         241                 : : mInStream(false)
         242                 :   , mGethashNoise(0)
         243               7 :   , mPendingLookupLock("nsUrlClassifierDBServerWorker.mPendingLookupLock")
         244                 : {
         245               7 : }
         246                 :
         247              14 : nsUrlClassifierDBServiceWorker::~nsUrlClassifierDBServiceWorker()
         248                 : {
         249               7 :   NS_ASSERTION(!mClassifier,
         250                 :                "Db connection not closed, leaking memory!  Call CloseDb "
         251                 :                "to close the connection.");
         252               7 : }
         253                 :
         254                 : nsresult
         255               7 : nsUrlClassifierDBServiceWorker::Init(PRInt32 gethashNoise,
         256                 :                                      nsCOMPtr<nsIFile> aCacheDir)
         257                 : {
         258               7 :   mGethashNoise = gethashNoise;
         259               7 :   mCacheDir = aCacheDir;
         260                 :
         261               7 :   ResetUpdate();
         262                 :
         263               7 :   return NS_OK;
         264                 : }
         265                 :
         266                 : nsresult
         267             140 : nsUrlClassifierDBServiceWorker::QueueLookup(const nsACString& spec,
         268                 :                                             nsIUrlClassifierLookupCallback* callback)
         269                 : {
         270             280 :   MutexAutoLock lock(mPendingLookupLock);
         271                 :
         272             140 :   PendingLookup* lookup = mPendingLookups.AppendElement();
         273             140 :   if (!lookup) return NS_ERROR_OUT_OF_MEMORY;
         274                 :
         275             140 :   lookup->mStartTime = TimeStamp::Now();
         276             140 :   lookup->mKey = spec;
         277             140 :   lookup->mCallback = callback;
         278                 :
         279             140 :   return NS_OK;
         280                 : }
         281                 :
         282                 : /**
         283                 :  * Lookup up a key in the database is a two step process:
         284                 :  *
         285                 :  * a) First we look for any Entries in the database that might apply to this
         286                 :  *    url.  For each URL there are one or two possible domain names to check:
         287                 :  *    the two-part domain name (example.com) and the three-part name
         288                 :  *    (www.example.com).  We check the database for both of these.
         289                 :  * b) If we find any entries, we check the list of fragments for that entry
         290                 :  *    against the possible subfragments of the URL as described in the
         291                 :  *    "Simplified Regular Expression Lookup" section of the protocol doc.
         292                 :  */
         293                 : nsresult
         294             140 : nsUrlClassifierDBServiceWorker::DoLookup(const nsACString& spec,
         295                 :                                          nsIUrlClassifierLookupCallback* c)
         296                 : {
         297             140 :   if (gShuttingDownThread) {
         298               0 :     c->LookupComplete(nsnull);
         299               0 :     return NS_ERROR_NOT_INITIALIZED;
         300                 :   }
         301                 :
         302             140 :   nsresult rv = OpenDb();
         303             140 :   if (NS_FAILED(rv)) {
         304               0 :     c->LookupComplete(nsnull);
         305               0 :     return NS_ERROR_FAILURE;
         306                 :   }
         307                 :
         308                 : #if defined(PR_LOGGING)
         309             140 :   PRIntervalTime clockStart = 0;
         310             140 :   if (LOG_ENABLED()) {
         311               0 :     clockStart = PR_IntervalNow();
         312                 :   }
         313                 : #endif
         314                 :
         315             280 :   nsAutoPtr<LookupResultArray> results(new LookupResultArray());
         316             140 :   if (!results) {
         317               0 :     c->LookupComplete(nsnull);
         318               0 :     return NS_ERROR_OUT_OF_MEMORY;
         319                 :   }
         320                 :
         321                 :   // we ignore failures from Check because we'd rather return the
         322                 :   // results that were found than fail.
         323             140 :   mClassifier->SetFreshTime(gFreshnessGuarantee);
         324             140 :   mClassifier->Check(spec, *results);
         325                 :
         326             140 :   LOG(("Found %d results.", results->Length()));
         327                 :
         328                 : #if defined(PR_LOGGING)
         329             140 :   if (LOG_ENABLED()) {
         330               0 :     PRIntervalTime clockEnd = PR_IntervalNow();
         331               0 :     LOG(("query took %dms\n",
         332                 :          PR_IntervalToMilliseconds(clockEnd - clockStart)));
         333                 :   }
         334                 : #endif
         335                 :
         336             280 :   nsAutoPtr<LookupResultArray> completes(new LookupResultArray());
         337                 :
         338             256 :   for (PRUint32 i = 0; i < results->Length(); i++) {
         339             116 :     if (!mMissCache.Contains(results->ElementAt(i).hash.prefix)) {
         340             115 :       completes->AppendElement(results->ElementAt(i));
         341                 :     }
         342                 :   }
         343                 :
         344             201 :   for (PRUint32 i = 0; i < completes->Length(); i++) {
         345              99 :     if (!completes->ElementAt(i).Confirmed()) {
         346                 :       // We're going to be doing a gethash request, add some extra entries.
         347                 :       // Note that we cannot pass the first two by reference, because we
         348                 :       // add to completes, whicah can cause completes to reallocate and move.
         349              38 :       AddNoise(completes->ElementAt(i).mCodedPrefix,
         350              38 :                completes->ElementAt(i).mTableName,
         351             114 :                mGethashNoise, *completes);
         352              38 :       break;
         353                 :     }
         354                 :   }
         355                 :
         356                 :   // At this point ownership of 'results' is handed to the callback.
         357             140 :   c->LookupComplete(completes.forget());
         358                 :
         359             140 :   return NS_OK;
         360                 : }
         361                 :
         362                 : nsresult
         363             227 : nsUrlClassifierDBServiceWorker::HandlePendingLookups()
         364                 : {
         365             454 :   MutexAutoLock lock(mPendingLookupLock);
         366             594 :   while (mPendingLookups.Length() > 0) {
         367             280 :     PendingLookup lookup = mPendingLookups[0];
         368             140 :     mPendingLookups.RemoveElementAt(0);
         369                 :     {
         370             280 :       MutexAutoUnlock unlock(mPendingLookupLock);
         371             140 :       DoLookup(lookup.mKey, lookup.mCallback);
         372                 :     }
         373             140 :     double lookupTime = (TimeStamp::Now() - lookup.mStartTime).ToMilliseconds();
         374                 :     Telemetry::Accumulate(Telemetry::URLCLASSIFIER_LOOKUP_TIME,
         375             140 :                           static_cast<PRUint32>(lookupTime));
         376                 :   }
         377                 :
         378             227 :   return NS_OK;
         379                 : }
         380                 :
         381                 : nsresult
         382              38 : nsUrlClassifierDBServiceWorker::AddNoise(const Prefix aPrefix,
         383                 :                                          const nsCString tableName,
         384                 :                                          PRInt32 aCount,
         385                 :                                          LookupResultArray& results)
         386                 : {
         387              38 :   if (aCount < 1) {
         388              38 :     return NS_OK;
         389                 :   }
         390                 :
         391               0 :   PrefixArray noiseEntries;
         392                 :   nsresult rv = mClassifier->ReadNoiseEntries(aPrefix, tableName,
         393               0 :                                               aCount, &noiseEntries);
         394               0 :   NS_ENSURE_SUCCESS(rv, rv);
         395                 :
         396               0 :   for (PRUint32 i = 0; i < noiseEntries.Length(); i++) {
         397               0 :     LookupResult *result = results.AppendElement();
         398               0 :     if (!result)
         399               0 :       return NS_ERROR_OUT_OF_MEMORY;
         400                 :
         401               0 :     result->hash.prefix = noiseEntries[i];
         402               0 :     result->mNoise = true;
         403               0 :     result->mTableName.Assign(tableName);
         404                 :   }
         405                 :
         406               0 :   return NS_OK;
         407                 : }
         408                 :
         409                 : // Lookup a key in the db.
         410                 : NS_IMETHODIMP
         411             140 : nsUrlClassifierDBServiceWorker::Lookup(const nsACString& spec,
         412                 :                                        nsIUrlClassifierCallback* c)
         413                 : {
         414             140 :   return HandlePendingLookups();
         415                 : }
         416                 :
         417                 : NS_IMETHODIMP
         418              48 : nsUrlClassifierDBServiceWorker::GetTables(nsIUrlClassifierCallback* c)
         419                 : {
         420              48 :   if (gShuttingDownThread)
         421               0 :     return NS_ERROR_NOT_INITIALIZED;
         422                 :
         423              48 :   nsresult rv = OpenDb();
         424              48 :   if (NS_FAILED(rv)) {
         425               0 :     NS_ERROR("Unable to open database");
         426               0 :     return NS_ERROR_FAILURE;
         427                 :   }
         428                 :
         429              48 :   NS_ENSURE_SUCCESS(rv, rv);
         430                 :
         431              96 :   nsCAutoString response;
         432              48 :   mClassifier->TableRequest(response);
         433              48 :   c->HandleEvent(response);
         434                 :
         435              48 :   return rv;
         436                 : }
         437                 :
         438                 : void
         439               2 : nsUrlClassifierDBServiceWorker::ResetStream()
         440                 : {
         441               2 :   LOG(("ResetStream"));
         442               2 :   mInStream = false;
         443               2 :   mProtocolParser = nsnull;
         444               2 : }
         445                 :
         446                 : void
         447               9 : nsUrlClassifierDBServiceWorker::ResetUpdate()
         448                 : {
         449               9 :   LOG(("ResetUpdate"));
         450               9 :   mUpdateWait = 0;
         451               9 :   mUpdateStatus = NS_OK;
         452               9 :   mUpdateObserver = nsnull;
         453               9 :   mUpdateClientKey.Truncate();
         454               9 : }
         455                 :
         456                 : NS_IMETHODIMP
         457               0 : nsUrlClassifierDBServiceWorker::SetHashCompleter(const nsACString &tableName,
         458                 :                                                  nsIUrlClassifierHashCompleter *completer)
         459                 : {
         460               0 :   return NS_ERROR_NOT_IMPLEMENTED;
         461                 : }
         462                 :
         463                 : NS_IMETHODIMP
         464              77 : nsUrlClassifierDBServiceWorker::BeginUpdate(nsIUrlClassifierUpdateObserver *observer,
         465                 :                                             const nsACString &tables,
         466                 :                                             const nsACString &clientKey)
         467                 : {
         468              77 :   LOG(("nsUrlClassifierDBServiceWorker::BeginUpdate [%s]", PromiseFlatCString(tables).get()));
         469                 :
         470              77 :   if (gShuttingDownThread)
         471               0 :     return NS_ERROR_NOT_INITIALIZED;
         472                 :
         473              77 :   NS_ENSURE_STATE(!mUpdateObserver);
         474                 :
         475              77 :   nsresult rv = OpenDb();
         476              77 :   if (NS_FAILED(rv)) {
         477               0 :     NS_ERROR("Unable to open database");
         478               0 :     return NS_ERROR_FAILURE;
         479                 :   }
         480                 :
         481              77 :   mUpdateStatus = NS_OK;
         482              77 :   mUpdateObserver = observer;
         483              77 :   SplitTables(tables, mUpdateTables);
         484                 :
         485              77 :   if (!clientKey.IsEmpty()) {
         486               7 :     rv = nsUrlClassifierUtils::DecodeClientKey(clientKey, mUpdateClientKey);
         487               7 :     NS_ENSURE_SUCCESS(rv, rv);
         488               7 :     LOG(("clientKey present, marking update key"));
         489                 :   }
         490                 :
         491              77 :   return NS_OK;
         492                 : }
         493                 :
         494                 : NS_IMETHODIMP
         495              89 : nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table,
         496                 :                                             const nsACString &serverMAC)
         497                 : {
         498              89 :   LOG(("nsUrlClassifierDBServiceWorker::BeginStream"));
         499                 :
         500              89 :   if (gShuttingDownThread)
         501               0 :     return NS_ERROR_NOT_INITIALIZED;
         502                 :
         503              89 :   NS_ENSURE_STATE(mUpdateObserver);
         504              89 :   NS_ENSURE_STATE(!mInStream);
         505                 :
         506              89 :   mInStream = true;
         507                 :
         508              89 :   NS_ASSERTION(!mProtocolParser, "Should not have a protocol parser.");
         509                 :
         510              89 :   mProtocolParser = new ProtocolParser(mHashKey);
         511              89 :   if (!mProtocolParser)
         512               0 :     return NS_ERROR_OUT_OF_MEMORY;
         513                 :
         514              89 :   mProtocolParser->Init(mCryptoHash);
         515                 :
         516                 :   nsresult rv;
         517                 :
         518                 :   // If we're expecting a MAC, create the nsICryptoHMAC component now.
         519              89 :   if (!mUpdateClientKey.IsEmpty()) {
         520              11 :     LOG(("Expecting MAC in this stream"));
         521              11 :     rv = mProtocolParser->InitHMAC(mUpdateClientKey, serverMAC);
         522              11 :     NS_ENSURE_SUCCESS(rv, rv);
         523                 :   } else {
         524              78 :     LOG(("No MAC in this stream"));
         525                 :   }
         526                 :
         527              89 :   if (!table.IsEmpty()) {
         528              12 :     mProtocolParser->SetCurrentTable(table);
         529                 :   }
         530                 :
         531              89 :   return NS_OK;
         532                 : }
         533                 :
         534                 : /**
         535                 :  * Updating the database:
         536                 :  *
         537                 :  * The Update() method takes a series of chunks separated with control data,
         538                 :  * as described in
         539                 :  * http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec
         540                 :  *
         541                 :  * It will iterate through the control data until it reaches a chunk.  By
         542                 :  * the time it reaches a chunk, it should have received
         543                 :  * a) the table to which this chunk applies
         544                 :  * b) the type of chunk (add, delete, expire add, expire delete).
         545                 :  * c) the chunk ID
         546                 :  * d) the length of the chunk.
         547                 :  *
         548                 :  * For add and subtract chunks, it needs to read the chunk data (expires
         549                 :  * don't have any data).  Chunk data is a list of URI fragments whose
         550                 :  * encoding depends on the type of table (which is indicated by the end
         551                 :  * of the table name):
         552                 :  * a) tables ending with -exp are a zlib-compressed list of URI fragments
         553                 :  *    separated by newlines.
         554                 :  * b) tables ending with -sha128 have the form
         555                 :  *    [domain][N][frag0]...[fragN]
         556                 :  *       16    1   16        16
         557                 :  *    If N is 0, the domain is reused as a fragment.
         558                 :  * c) any other tables are assumed to be a plaintext list of URI fragments
         559                 :  *    separated by newlines.
         560                 :  *
         561                 :  * Update() can be fed partial data;  It will accumulate data until there is
         562                 :  * enough to act on.  Finish() should be called when there will be no more
         563                 :  * data.
         564                 :  */
         565                 : NS_IMETHODIMP
         566              87 : nsUrlClassifierDBServiceWorker::UpdateStream(const nsACString& chunk)
         567                 : {
         568              87 :   if (gShuttingDownThread)
         569               0 :     return NS_ERROR_NOT_INITIALIZED;
         570                 :
         571              87 :   NS_ENSURE_STATE(mInStream);
         572                 :
         573              87 :   HandlePendingLookups();
         574                 :
         575              87 :   return mProtocolParser->AppendStream(chunk);
         576                 : }
         577                 :
         578                 : NS_IMETHODIMP
         579              87 : nsUrlClassifierDBServiceWorker::FinishStream()
         580                 : {
         581              87 :   if (gShuttingDownThread)
         582               0 :     return NS_ERROR_NOT_INITIALIZED;
         583                 :
         584              87 :   NS_ENSURE_STATE(mInStream);
         585              87 :   NS_ENSURE_STATE(mUpdateObserver);
         586                 :
         587              87 :   mInStream = false;
         588                 :
         589              87 :   mProtocolParser->FinishHMAC();
         590                 :
         591              87 :   if (NS_SUCCEEDED(mProtocolParser->Status())) {
         592              80 :     if (mProtocolParser->UpdateWait()) {
         593              80 :       mUpdateWait = mProtocolParser->UpdateWait();
         594                 :     }
         595                 :     // XXX: Only allow forwards from the initial update?
         596                 :     const nsTArray<ProtocolParser::ForwardedUpdate> &forwards =
         597              80 :       mProtocolParser->Forwards();
         598              96 :     for (uint32 i = 0; i < forwards.Length(); i++) {
         599              16 :       const ProtocolParser::ForwardedUpdate &forward = forwards[i];
         600              16 :       mUpdateObserver->UpdateUrlRequested(forward.url, forward.table, forward.mac);
         601                 :     }
         602                 :     // Hold on to any TableUpdate objects that were created by the
         603                 :     // parser.
         604              80 :     mTableUpdates.AppendElements(mProtocolParser->GetTableUpdates());
         605              80 :     mProtocolParser->ForgetTableUpdates();
         606                 :   } else {
         607               7 :     mUpdateStatus = mProtocolParser->Status();
         608                 :   }
         609              87 :   mUpdateObserver->StreamFinished(mProtocolParser->Status(), 0);
         610                 :
         611                 :   // Only reset if MAC was OK
         612              87 :   if (NS_SUCCEEDED(mUpdateStatus)) {
         613              80 :     if (mProtocolParser->ResetRequested()) {
         614               1 :       mClassifier->Reset();
         615                 :     }
         616                 :   }
         617                 :   // Rekey will cause update to fail (can't check MACs)
         618              87 :   if (mProtocolParser->RekeyRequested()) {
         619               1 :     mUpdateObserver->RekeyRequested();
         620                 :   }
         621                 :
         622              87 :   mProtocolParser = nsnull;
         623              87 :   return NS_OK;
         624                 : }
         625                 :
         626                 : NS_IMETHODIMP
         627              75 : nsUrlClassifierDBServiceWorker::FinishUpdate()
         628                 : {
         629              75 :   if (gShuttingDownThread)
         630               0 :     return NS_ERROR_NOT_INITIALIZED;
         631              75 :   NS_ENSURE_STATE(mUpdateObserver);
         632                 :
         633              75 :   if (NS_SUCCEEDED(mUpdateStatus)) {
         634              68 :     mUpdateStatus = ApplyUpdate();
         635                 :   }
         636                 :
         637              75 :   mMissCache.Clear();
         638                 :
         639              75 :   if (NS_SUCCEEDED(mUpdateStatus)) {
         640              68 :     LOG(("Notifying success: %d", mUpdateWait));
         641              68 :     mUpdateObserver->UpdateSuccess(mUpdateWait);
         642                 :   } else {
         643               7 :     LOG(("Notifying error: %d", mUpdateStatus));
         644               7 :     mUpdateObserver->UpdateError(mUpdateStatus);
         645                 :     /*
         646                 :      * mark the tables as spoiled, we don't want to block hosts
         647                 :      * longer than normal because our update failed
         648                 :     */
         649               7 :     mClassifier->MarkSpoiled(mUpdateTables);
         650                 :   }
         651              75 :   mUpdateObserver = nsnull;
         652                 :
         653              75 :   return NS_OK;
         654                 : }
         655                 :
         656                 : nsresult
         657              68 : nsUrlClassifierDBServiceWorker::ApplyUpdate()
         658                 : {
         659              68 :   LOG(("nsUrlClassifierDBServiceWorker::ApplyUpdate()"));
         660              68 :   return mClassifier->ApplyUpdates(&mTableUpdates);
         661                 : }
         662                 :
         663                 : NS_IMETHODIMP
         664              46 : nsUrlClassifierDBServiceWorker::ResetDatabase()
         665                 : {
         666              46 :   nsresult rv = OpenDb();
         667              46 :   NS_ENSURE_SUCCESS(rv, rv);
         668                 :
         669              46 :   mClassifier->Reset();
         670                 :
         671              46 :   rv = CloseDb();
         672              46 :   NS_ENSURE_SUCCESS(rv, rv);
         673                 :
         674              46 :   return NS_OK;
         675                 : }
         676                 :
         677                 : NS_IMETHODIMP
         678               9 : nsUrlClassifierDBServiceWorker::CancelUpdate()
         679                 : {
         680               9 :   LOG(("nsUrlClassifierDBServiceWorker::CancelUpdate"));
         681                 :
         682               9 :   if (mUpdateObserver) {
         683               2 :     LOG(("UpdateObserver exists, cancelling"));
         684                 :
         685               2 :     mUpdateStatus = NS_BINDING_ABORTED;
         686                 :
         687               2 :     mUpdateObserver->UpdateError(mUpdateStatus);
         688                 :
         689                 :     /*
         690                 :      * mark the tables as spoiled, we don't want to block hosts
         691                 :      * longer than normal because our update failed
         692                 :     */
         693               2 :     mClassifier->MarkSpoiled(mUpdateTables);
         694                 :
         695               2 :     ResetStream();
         696               2 :     ResetUpdate();
         697                 :   } else {
         698               7 :     LOG(("No UpdateObserver, nothing to cancel"));
         699                 :   }
         700                 :
         701               9 :   return NS_OK;
         702                 : }
         703                 :
         704                 : // Allows the main thread to delete the connection which may be in
         705                 : // a background thread.
         706                 : // XXX This could be turned into a single shutdown event so the logic
         707                 : // is simpler in nsUrlClassifierDBService::Shutdown.
         708                 : NS_IMETHODIMP
         709              53 : nsUrlClassifierDBServiceWorker::CloseDb()
         710                 : {
         711              53 :   if (mClassifier) {
         712              50 :     mClassifier->Close();
         713              50 :     mClassifier = nsnull;
         714                 :   }
         715                 :
         716              53 :   mCryptoHash = nsnull;
         717              53 :   LOG(("urlclassifier db closed\n"));
         718                 :
         719              53 :   return NS_OK;
         720                 : }
         721                 :
         722                 : NS_IMETHODIMP
         723              29 : nsUrlClassifierDBServiceWorker::CacheCompletions(CacheResultArray *results)
         724                 : {
         725              29 :   LOG(("nsUrlClassifierDBServiceWorker::CacheCompletions [%p]", this));
         726              29 :   if (!mClassifier)
         727               0 :     return NS_OK;
         728                 :
         729                 :   // Ownership is transferred in to us
         730              58 :   nsAutoPtr<CacheResultArray> resultsPtr(results);
         731                 :
         732              58 :   nsAutoPtr<ProtocolParser> pParse(new ProtocolParser(mHashKey));
         733              58 :   nsTArray<TableUpdate*> updates;
         734                 :
         735                 :   // Only cache results for tables that we have, don't take
         736                 :   // in tables we might accidentally have hit during a completion.
         737                 :   // This happens due to goog vs googpub lists existing.
         738              58 :   nsTArray<nsCString> tables;
         739              29 :   nsresult rv = mClassifier->ActiveTables(tables);
         740              29 :   NS_ENSURE_SUCCESS(rv, rv);
         741                 :
         742              76 :   for (PRUint32 i = 0; i < resultsPtr->Length(); i++) {
         743              47 :     bool activeTable = false;
         744              95 :     for (PRUint32 table = 0; table < tables.Length(); table++) {
         745              48 :       if (tables[table].Equals(resultsPtr->ElementAt(i).table)) {
         746              46 :         activeTable = true;
         747                 :       }
         748                 :     }
         749              47 :     if (activeTable) {
         750              46 :       TableUpdate * tu = pParse->GetTableUpdate(resultsPtr->ElementAt(i).table);
         751              46 :       LOG(("CacheCompletion Addchunk %d hash %X", resultsPtr->ElementAt(i).entry.addChunk,
         752                 :            resultsPtr->ElementAt(i).entry.hash.prefix));
         753              46 :       tu->NewAddComplete(resultsPtr->ElementAt(i).entry.addChunk,
         754              92 :                          resultsPtr->ElementAt(i).entry.hash.complete);
         755              46 :       tu->NewAddChunk(resultsPtr->ElementAt(i).entry.addChunk);
         756              46 :       tu->SetLocalUpdate();
         757              46 :       updates.AppendElement(tu);
         758              46 :       pParse->ForgetTableUpdates();
         759                 :     } else {
         760               1 :       LOG(("Completion received, but table is not active, so not caching."));
         761                 :     }
         762                 :    }
         763                 :
         764              29 :   mClassifier->ApplyUpdates(&updates);
         765              29 :   return NS_OK;
         766                 : }
         767                 :
         768                 : NS_IMETHODIMP
         769             140 : nsUrlClassifierDBServiceWorker::CacheMisses(PrefixArray *results)
         770                 : {
         771             140 :   LOG(("nsUrlClassifierDBServiceWorker::CacheMisses [%p] %d",
         772                 :        this, results->Length()));
         773                 :
         774                 :   // Ownership is transferred in to us
         775             280 :   nsAutoPtr<PrefixArray> resultsPtr(results);
         776                 :
         777             153 :   for (PRUint32 i = 0; i < resultsPtr->Length(); i++) {
         778              13 :     mMissCache.AppendElement(resultsPtr->ElementAt(i));
         779                 :    }
         780             140 :   return NS_OK;
         781                 : }
         782                 :
         783                 : nsresult
         784             311 : nsUrlClassifierDBServiceWorker::OpenDb()
         785                 : {
         786                 :   // Connection already open, don't do anything.
         787             311 :   if (mClassifier) {
         788             261 :     return NS_OK;
         789                 :   }
         790                 :
         791              50 :   LOG(("Opening db"));
         792                 :
         793             100 :   nsAutoPtr<Classifier> classifier(new Classifier());
         794              50 :   if (!classifier) {
         795               0 :     return NS_ERROR_OUT_OF_MEMORY;
         796                 :   }
         797                 :
         798              50 :   classifier->SetFreshTime(gFreshnessGuarantee);
         799                 :
         800              50 :   nsresult rv = classifier->Open(*mCacheDir);
         801              50 :   if (NS_FAILED(rv)) {
         802               0 :     NS_WARNING("Failed to open URL classifier.");
         803                 :   }
         804                 :
         805              50 :   mHashKey = classifier->GetHashKey();
         806              50 :   mClassifier = classifier;
         807                 :
         808              50 :   mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
         809              50 :   NS_ENSURE_SUCCESS(rv, rv);
         810                 :
         811              50 :   return NS_OK;
         812                 : }
         813                 :
         814                 : // -------------------------------------------------------------------------
         815                 : // nsUrlClassifierLookupCallback
         816                 : //
         817                 : // This class takes the results of a lookup found on the worker thread
         818                 : // and handles any necessary partial hash expansions before calling
         819                 : // the client callback.
         820                 :
         821                 : class nsUrlClassifierLookupCallback : public nsIUrlClassifierLookupCallback
         822                 :                                     , public nsIUrlClassifierHashCompleterCallback
         823                 : {
         824                 : public:
         825                 :   NS_DECL_ISUPPORTS
         826                 :   NS_DECL_NSIURLCLASSIFIERLOOKUPCALLBACK
         827                 :   NS_DECL_NSIURLCLASSIFIERHASHCOMPLETERCALLBACK
         828                 :
         829             140 :   nsUrlClassifierLookupCallback(nsUrlClassifierDBService *dbservice,
         830                 :                                 nsIUrlClassifierCallback *c)
         831                 :     : mDBService(dbservice)
         832                 :     , mResults(nsnull)
         833                 :     , mPendingCompletions(0)
         834             140 :     , mCallback(c)
         835             140 :     {}
         836                 :
         837                 :   ~nsUrlClassifierLookupCallback();
         838                 :
         839                 : private:
         840                 :   nsresult HandleResults();
         841                 :
         842                 :   nsRefPtr<nsUrlClassifierDBService> mDBService;
         843                 :   nsAutoPtr<LookupResultArray> mResults;
         844                 :
         845                 :   // Completed results to send back to the worker for caching.
         846                 :   nsAutoPtr<CacheResultArray> mCacheResults;
         847                 :
         848                 :   PRUint32 mPendingCompletions;
         849                 :   nsCOMPtr<nsIUrlClassifierCallback> mCallback;
         850                 : };
         851                 :
         852            2760 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsUrlClassifierLookupCallback,
         853                 :                               nsIUrlClassifierLookupCallback,
         854                 :                               nsIUrlClassifierHashCompleterCallback)
         855                 :
         856             280 : nsUrlClassifierLookupCallback::~nsUrlClassifierLookupCallback()
         857                 : {
         858             280 :   nsCOMPtr<nsIThread> thread;
         859             140 :   (void)NS_GetMainThread(getter_AddRefs(thread));
         860                 :
         861             140 :   if (mCallback) {
         862             140 :     (void)NS_ProxyRelease(thread, mCallback, false);
         863                 :   }
         864             140 : }
         865                 :
         866                 : NS_IMETHODIMP
         867             140 : nsUrlClassifierLookupCallback::LookupComplete(nsTArray<LookupResult>* results)
         868                 : {
         869             140 :   NS_ASSERTION(mResults == nsnull,
         870                 :                "Should only get one set of results per nsUrlClassifierLookupCallback!");
         871                 :
         872             140 :   if (!results) {
         873               0 :     HandleResults();
         874               0 :     return NS_OK;
         875                 :   }
         876                 :
         877             140 :   mResults = results;
         878                 :
         879                 :   // Check the results entries that need to be completed.
         880             255 :   for (PRUint32 i = 0; i < results->Length(); i++) {
         881             115 :     LookupResult& result = results->ElementAt(i);
         882                 :
         883                 :     // We will complete partial matches and matches that are stale.
         884             115 :     if (!result.Confirmed()) {
         885             108 :       nsCOMPtr<nsIUrlClassifierHashCompleter> completer;
         886             108 :       if (mDBService->GetCompleter(result.mTableName,
         887             108 :                                    getter_AddRefs(completer))) {
         888             108 :         nsCAutoString partialHash;
         889                 :         partialHash.Assign(reinterpret_cast<char*>(&result.hash.prefix),
         890              54 :                            PREFIX_SIZE);
         891                 :
         892              54 :         nsresult rv = completer->Complete(partialHash, this);
         893              54 :         if (NS_SUCCEEDED(rv)) {
         894              54 :           mPendingCompletions++;
         895                 :         }
         896                 :       } else {
         897                 :         // For tables with no hash completer, a complete hash match is
         898                 :         // good enough, we'll consider it fresh.
         899               0 :         if (result.Complete()) {
         900               0 :           result.mFresh = true;
         901                 :         } else {
         902               0 :           NS_WARNING("Partial match in a table without a valid completer, ignoring partial match.");
         903                 :         }
         904                 :       }
         905                 :     }
         906                 :   }
         907                 :
         908             140 :   if (mPendingCompletions == 0) {
         909                 :     // All results were complete, we're ready!
         910             102 :     HandleResults();
         911                 :   }
         912                 :
         913             140 :   return NS_OK;
         914                 : }
         915                 :
         916                 : NS_IMETHODIMP
         917              54 : nsUrlClassifierLookupCallback::CompletionFinished(nsresult status)
         918                 : {
         919              54 :   LOG(("nsUrlClassifierLookupCallback::CompletionFinished [%p, %08x]",
         920                 :        this, status));
         921              54 :   if (NS_FAILED(status)) {
         922               0 :     NS_WARNING("gethash response failed.");
         923                 :   }
         924                 :
         925              54 :   mPendingCompletions--;
         926              54 :   if (mPendingCompletions == 0) {
         927              38 :     HandleResults();
         928                 :   }
         929                 :
         930              54 :   return NS_OK;
         931                 : }
         932                 :
         933                 : NS_IMETHODIMP
         934              48 : nsUrlClassifierLookupCallback::Completion(const nsACString& completeHash,
         935                 :                                           const nsACString& tableName,
         936                 :                                           PRUint32 chunkId,
         937                 :                                           bool verified)
         938                 : {
         939              48 :   LOG(("nsUrlClassifierLookupCallback::Completion [%p, %s, %d, %d]",
         940                 :        this, PromiseFlatCString(tableName).get(), chunkId, verified));
         941                 :   mozilla::safebrowsing::Completion hash;
         942              48 :   hash.Assign(completeHash);
         943                 :
         944                 :   // Send this completion to the store for caching.
         945              48 :   if (!mCacheResults) {
         946              29 :     mCacheResults = new CacheResultArray();
         947              29 :     if (!mCacheResults)
         948               0 :       return NS_ERROR_OUT_OF_MEMORY;
         949                 :   }
         950                 :
         951              48 :   if (verified) {
         952              94 :     CacheResult result;
         953              47 :     result.entry.addChunk = chunkId;
         954              47 :     result.entry.hash.complete = hash;
         955              47 :     result.table = tableName;
         956                 :
         957                 :     // OK if this fails, we just won't cache the item.
         958              47 :     mCacheResults->AppendElement(result);
         959                 :   }
         960                 :
         961                 :   // Check if this matched any of our results.
         962             242 :   for (PRUint32 i = 0; i < mResults->Length(); i++) {
         963             194 :     LookupResult& result = mResults->ElementAt(i);
         964                 :
         965                 :     // Now, see if it verifies a lookup
         966             194 :     if (result.CompleteHash() == hash && result.mTableName.Equals(tableName)) {
         967              41 :       result.mProtocolConfirmed = true;
         968                 :     }
         969                 :   }
         970                 :
         971              48 :   return NS_OK;
         972                 : }
         973                 :
         974                 : nsresult
         975             140 : nsUrlClassifierLookupCallback::HandleResults()
         976                 : {
         977             140 :   if (!mResults) {
         978                 :     // No results, this URI is clean.
         979               0 :     return mCallback->HandleEvent(NS_LITERAL_CSTRING(""));
         980                 :   }
         981                 :
         982             280 :   nsTArray<nsCString> tables;
         983                 :   // Build a stringified list of result tables.
         984             255 :   for (PRUint32 i = 0; i < mResults->Length(); i++) {
         985             115 :     LookupResult& result = mResults->ElementAt(i);
         986                 :
         987                 :     // Leave out results that weren't confirmed, as their existence on
         988                 :     // the list can't be verified.  Also leave out randomly-generated
         989                 :     // noise.
         990             115 :     if (!result.Confirmed() || result.mNoise) {
         991              13 :       LOG(("Skipping result from table %s", result.mTableName.get()));
         992              13 :       continue;
         993                 :     }
         994                 :
         995             102 :     LOG(("Confirmed result from table %s", result.mTableName.get()));
         996                 :
         997             102 :     if (tables.IndexOf(result.mTableName) == nsTArray<nsCString>::NoIndex) {
         998              86 :       tables.AppendElement(result.mTableName);
         999                 :     }
        1000                 :   }
        1001                 :
        1002                 :   // Some parts of this gethash request generated no hits at all.
        1003                 :   // Prefixes must have been removed from the database since our last update.
        1004                 :   // Save the prefixes we checked to prevent repeated requests
        1005                 :   // until the next update.
        1006             280 :   nsAutoPtr<PrefixArray> cacheMisses(new PrefixArray());
        1007             140 :   if (cacheMisses) {
        1008             255 :     for (uint32 i = 0; i < mResults->Length(); i++) {
        1009             115 :       LookupResult &result = mResults->ElementAt(i);
        1010             115 :       if (!result.Confirmed()) {
        1011              13 :         cacheMisses->AppendElement(result.PrefixHash());
        1012                 :       }
        1013                 :     }
        1014                 :     // Hands ownership of the miss array back to the worker thread.
        1015             140 :     mDBService->CacheMisses(cacheMisses.forget());
        1016                 :   }
        1017                 :
        1018             140 :   if (mCacheResults) {
        1019                 :     // This hands ownership of the cache results array back to the worker
        1020                 :     // thread.
        1021              29 :     mDBService->CacheCompletions(mCacheResults.forget());
        1022                 :   }
        1023                 :
        1024             280 :   nsCAutoString tableStr;
        1025             226 :   for (PRUint32 i = 0; i < tables.Length(); i++) {
        1026              86 :     if (i != 0)
        1027               9 :       tableStr.Append(',');
        1028              86 :     tableStr.Append(tables[i]);
        1029                 :   }
        1030                 :
        1031             140 :   return mCallback->HandleEvent(tableStr);
        1032                 : }
        1033                 :
        1034                 :
        1035                 : // -------------------------------------------------------------------------
        1036                 : // Helper class for nsIURIClassifier implementation, translates table names
        1037                 : // to nsIURIClassifier enums.
        1038                 :
        1039                 : class nsUrlClassifierClassifyCallback : public nsIUrlClassifierCallback
        1040               0 : {
        1041                 : public:
        1042                 :   NS_DECL_ISUPPORTS
        1043                 :   NS_DECL_NSIURLCLASSIFIERCALLBACK
        1044                 :
        1045               0 :   nsUrlClassifierClassifyCallback(nsIURIClassifierCallback *c,
        1046                 :                                   bool checkMalware,
        1047                 :                                   bool checkPhishing)
        1048                 :     : mCallback(c)
        1049                 :     , mCheckMalware(checkMalware)
        1050               0 :     , mCheckPhishing(checkPhishing)
        1051               0 :     {}
        1052                 :
        1053                 : private:
        1054                 :   nsCOMPtr<nsIURIClassifierCallback> mCallback;
        1055                 :   bool mCheckMalware;
        1056                 :   bool mCheckPhishing;
        1057                 : };
        1058                 :
        1059               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierClassifyCallback,
        1060                 :                               nsIUrlClassifierCallback)
        1061                 :
        1062                 : NS_IMETHODIMP
        1063               0 : nsUrlClassifierClassifyCallback::HandleEvent(const nsACString& tables)
        1064                 : {
        1065                 :   // XXX: we should probably have the wardens tell the service which table
        1066                 :   // names match with which classification.  For now the table names give
        1067                 :   // enough information.
        1068               0 :   nsresult response = NS_OK;
        1069                 :
        1070               0 :   nsACString::const_iterator begin, end;
        1071                 :
        1072               0 :   tables.BeginReading(begin);
        1073               0 :   tables.EndReading(end);
        1074               0 :   if (mCheckMalware &&
        1075               0 :       FindInReadable(NS_LITERAL_CSTRING("-malware-"), begin, end)) {
        1076               0 :     response = NS_ERROR_MALWARE_URI;
        1077                 :   } else {
        1078                 :     // Reset begin before checking phishing table
        1079               0 :     tables.BeginReading(begin);
        1080                 :
        1081               0 :     if (mCheckPhishing &&
        1082               0 :         FindInReadable(NS_LITERAL_CSTRING("-phish-"), begin, end)) {
        1083               0 :       response = NS_ERROR_PHISHING_URI;
        1084                 :     }
        1085                 :   }
        1086                 :
        1087               0 :   mCallback->OnClassifyComplete(response);
        1088                 :
        1089               0 :   return NS_OK;
        1090                 : }
        1091                 :
        1092                 :
        1093                 : // -------------------------------------------------------------------------
        1094                 : // Proxy class implementation
        1095                 :
        1096            1057 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsUrlClassifierDBService,
        1097                 :                               nsIUrlClassifierDBService,
        1098                 :                               nsIURIClassifier,
        1099                 :                               nsIObserver)
        1100                 :
        1101                 : /* static */ nsUrlClassifierDBService*
        1102               7 : nsUrlClassifierDBService::GetInstance(nsresult *result)
        1103                 : {
        1104               7 :   *result = NS_OK;
        1105               7 :   if (!sUrlClassifierDBService) {
        1106               7 :     sUrlClassifierDBService = new nsUrlClassifierDBService();
        1107               7 :     if (!sUrlClassifierDBService) {
        1108               0 :       *result = NS_ERROR_OUT_OF_MEMORY;
        1109               0 :       return nsnull;
        1110                 :     }
        1111                 :
        1112               7 :     NS_ADDREF(sUrlClassifierDBService);   // addref the global
        1113                 :
        1114               7 :     *result = sUrlClassifierDBService->Init();
        1115               7 :     if (NS_FAILED(*result)) {
        1116               0 :       NS_RELEASE(sUrlClassifierDBService);
        1117               0 :       return nsnull;
        1118                 :     }
        1119                 :   } else {
        1120                 :     // Already exists, just add a ref
        1121               0 :     NS_ADDREF(sUrlClassifierDBService);   // addref the return result
        1122                 :   }
        1123               7 :   return sUrlClassifierDBService;
        1124                 : }
        1125                 :
        1126                 :
        1127               7 : nsUrlClassifierDBService::nsUrlClassifierDBService()
        1128                 :  : mCheckMalware(CHECK_MALWARE_DEFAULT)
        1129                 :  , mCheckPhishing(CHECK_PHISHING_DEFAULT)
        1130               7 :  , mInUpdate(false)
        1131                 : {
        1132               7 : }
        1133                 :
        1134              14 : nsUrlClassifierDBService::~nsUrlClassifierDBService()
        1135                 : {
        1136               7 :   sUrlClassifierDBService = nsnull;
        1137               7 : }
        1138                 :
        1139                 : nsresult
        1140               7 : nsUrlClassifierDBService::Init()
        1141                 : {
        1142                 : #if defined(PR_LOGGING)
        1143               7 :   if (!gUrlClassifierDbServiceLog)
        1144               7 :     gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService");
        1145                 : #endif
        1146                 :
        1147                 :   nsresult rv;
        1148                 :
        1149                 :   // Should we check document loads for malware URIs?
        1150              14 :   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
        1151                 :
        1152               7 :   PRInt32 gethashNoise = 0;
        1153               7 :   if (prefs) {
        1154                 :     bool tmpbool;
        1155               7 :     rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool);
        1156               7 :     mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT;
        1157                 :
        1158               7 :     prefs->AddObserver(CHECK_MALWARE_PREF, this, false);
        1159                 :
        1160               7 :     rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool);
        1161               7 :     mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT;
        1162                 :
        1163               7 :     prefs->AddObserver(CHECK_PHISHING_PREF, this, false);
        1164                 :
        1165               7 :     if (NS_FAILED(prefs->GetIntPref(GETHASH_NOISE_PREF, &gethashNoise))) {
        1166               0 :       gethashNoise = GETHASH_NOISE_DEFAULT;
        1167                 :     }
        1168                 :
        1169              14 :     nsXPIDLCString tmpstr;
        1170               7 :     if (NS_SUCCEEDED(prefs->GetCharPref(GETHASH_TABLES_PREF, getter_Copies(tmpstr)))) {
        1171               7 :       SplitTables(tmpstr, mGethashWhitelist);
        1172                 :     }
        1173                 :
        1174               7 :     prefs->AddObserver(GETHASH_TABLES_PREF, this, false);
        1175                 :
        1176                 :     PRInt32 tmpint;
        1177               7 :     rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint);
        1178               7 :     PR_ATOMIC_SET(&gFreshnessGuarantee, NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC);
        1179                 :
        1180               7 :     prefs->AddObserver(CONFIRM_AGE_PREF, this, false);
        1181                 :   }
        1182                 :
        1183                 :   // Force PSM loading on main thread
        1184              14 :   nsCOMPtr<nsICryptoHash> acryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
        1185               7 :   NS_ENSURE_SUCCESS(rv, rv);
        1186                 :
        1187                 :   // Directory providers must also be accessed on the main thread.
        1188              14 :   nsCOMPtr<nsIFile> cacheDir;
        1189                 :   rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
        1190               7 :                               getter_AddRefs(cacheDir));
        1191               7 :   if (NS_FAILED(rv)) {
        1192                 :     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
        1193               0 :                                 getter_AddRefs(cacheDir));
        1194                 :   }
        1195                 :
        1196                 :   // Start the background thread.
        1197               7 :   rv = NS_NewThread(&gDbBackgroundThread);
        1198               7 :   if (NS_FAILED(rv))
        1199               0 :     return rv;
        1200                 :
        1201               7 :   mWorker = new nsUrlClassifierDBServiceWorker();
        1202               7 :   if (!mWorker)
        1203               0 :     return NS_ERROR_OUT_OF_MEMORY;
        1204                 :
        1205               7 :   rv = mWorker->Init(gethashNoise, cacheDir);
        1206               7 :   if (NS_FAILED(rv)) {
        1207               0 :     mWorker = nsnull;
        1208               0 :     return rv;
        1209                 :   }
        1210                 :
        1211                 :   // Proxy for calling the worker on the background thread
        1212              14 :   mWorkerProxy = new UrlClassifierDBServiceWorkerProxy(mWorker);
        1213                 :
        1214               7 :   mCompleters.Init();
        1215                 :
        1216                 :   // Add an observer for shutdown
        1217                 :   nsCOMPtr<nsIObserverService> observerService =
        1218              14 :       mozilla::services::GetObserverService();
        1219               7 :   if (!observerService)
        1220               0 :     return NS_ERROR_FAILURE;
        1221                 :
        1222               7 :   observerService->AddObserver(this, "profile-before-change", false);
        1223               7 :   observerService->AddObserver(this, "xpcom-shutdown-threads", false);
        1224                 :
        1225               7 :   return NS_OK;
        1226                 : }
        1227                 :
        1228                 : NS_IMETHODIMP
        1229               0 : nsUrlClassifierDBService::Classify(nsIURI *uri,
        1230                 :                                    nsIURIClassifierCallback* c,
        1231                 :                                    bool* result)
        1232                 : {
        1233               0 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1234                 :
        1235               0 :   if (!(mCheckMalware || mCheckPhishing)) {
        1236               0 :     *result = false;
        1237               0 :     return NS_OK;
        1238                 :   }
        1239                 :
        1240                 :   nsRefPtr<nsUrlClassifierClassifyCallback> callback =
        1241               0 :     new nsUrlClassifierClassifyCallback(c, mCheckMalware, mCheckPhishing);
        1242               0 :   if (!callback) return NS_ERROR_OUT_OF_MEMORY;
        1243                 :
        1244               0 :   nsresult rv = LookupURI(uri, callback, false, result);
        1245               0 :   if (rv == NS_ERROR_MALFORMED_URI) {
        1246               0 :     *result = false;
        1247                 :     // The URI had no hostname, don't try to classify it.
        1248               0 :     return NS_OK;
        1249                 :   }
        1250               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1251                 :
        1252               0 :   return NS_OK;
        1253                 : }
        1254                 :
        1255                 : NS_IMETHODIMP
        1256             140 : nsUrlClassifierDBService::Lookup(const nsACString& spec,
        1257                 :                                  nsIUrlClassifierCallback* c)
        1258                 : {
        1259             140 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1260                 :
        1261             280 :   nsCOMPtr<nsIURI> uri;
        1262                 :
        1263             140 :   nsresult rv = NS_NewURI(getter_AddRefs(uri), spec);
        1264             140 :   NS_ENSURE_SUCCESS(rv, rv);
        1265                 :
        1266             140 :   uri = NS_GetInnermostURI(uri);
        1267             140 :   if (!uri) {
        1268               0 :     return NS_ERROR_FAILURE;
        1269                 :   }
        1270                 :
        1271                 :   bool didLookup;
        1272             140 :   return LookupURI(uri, c, true, &didLookup);
        1273                 : }
        1274                 :
        1275                 : nsresult
        1276             140 : nsUrlClassifierDBService::LookupURI(nsIURI* uri,
        1277                 :                                     nsIUrlClassifierCallback* c,
        1278                 :                                     bool forceLookup,
        1279                 :                                     bool *didLookup)
        1280                 : {
        1281             140 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1282                 :
        1283             280 :   nsCAutoString key;
        1284                 :   // Canonicalize the url
        1285                 :   nsCOMPtr<nsIUrlClassifierUtils> utilsService =
        1286             280 :     do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
        1287             140 :   nsresult rv = utilsService->GetKeyForURI(uri, key);
        1288             140 :   if (NS_FAILED(rv))
        1289               0 :     return rv;
        1290                 :
        1291             140 :   if (forceLookup) {
        1292             140 :     *didLookup = true;
        1293                 :   } else {
        1294               0 :     bool clean = false;
        1295                 :
        1296               0 :     if (!clean) {
        1297                 :       nsCOMPtr<nsIPermissionManager> permissionManager =
        1298               0 :         do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
        1299                 :
        1300               0 :       if (permissionManager) {
        1301                 :         PRUint32 perm;
        1302               0 :         permissionManager->TestPermission(uri, "safe-browsing", &perm);
        1303               0 :         clean |= (perm == nsIPermissionManager::ALLOW_ACTION);
        1304                 :       }
        1305                 :     }
        1306                 :
        1307               0 :     *didLookup = !clean;
        1308               0 :     if (clean) {
        1309               0 :       return NS_OK;
        1310                 :     }
        1311                 :   }
        1312                 :
        1313                 :   // Create an nsUrlClassifierLookupCallback object.  This object will
        1314                 :   // take care of confirming partial hash matches if necessary before
        1315                 :   // calling the client's callback.
        1316                 :   nsCOMPtr<nsIUrlClassifierLookupCallback> callback =
        1317             280 :     new nsUrlClassifierLookupCallback(this, c);
        1318             140 :   if (!callback)
        1319               0 :     return NS_ERROR_OUT_OF_MEMORY;
        1320                 :
        1321                 :   nsCOMPtr<nsIUrlClassifierLookupCallback> proxyCallback =
        1322             420 :     new UrlClassifierLookupCallbackProxy(callback);
        1323                 :
        1324                 :   // Queue this lookup and call the lookup function to flush the queue if
        1325                 :   // necessary.
        1326             140 :   rv = mWorker->QueueLookup(key, proxyCallback);
        1327             140 :   NS_ENSURE_SUCCESS(rv, rv);
        1328                 :
        1329             140 :   return mWorkerProxy->Lookup(EmptyCString(), nsnull);
        1330                 : }
        1331                 :
        1332                 : NS_IMETHODIMP
        1333              48 : nsUrlClassifierDBService::GetTables(nsIUrlClassifierCallback* c)
        1334                 : {
        1335              48 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1336                 :
        1337                 :   // The proxy callback uses the current thread.
        1338                 :   nsCOMPtr<nsIUrlClassifierCallback> proxyCallback =
        1339              96 :     new UrlClassifierCallbackProxy(c);
        1340                 :
        1341              48 :   return mWorkerProxy->GetTables(proxyCallback);
        1342                 : }
        1343                 :
        1344                 : NS_IMETHODIMP
        1345              73 : nsUrlClassifierDBService::SetHashCompleter(const nsACString &tableName,
        1346                 :                                            nsIUrlClassifierHashCompleter *completer)
        1347                 : {
        1348              73 :   if (completer) {
        1349              27 :     if (!mCompleters.Put(tableName, completer)) {
        1350               0 :       return NS_ERROR_OUT_OF_MEMORY;
        1351                 :     }
        1352                 :   } else {
        1353              46 :     mCompleters.Remove(tableName);
        1354                 :   }
        1355                 :
        1356              73 :   return NS_OK;
        1357                 : }
        1358                 :
        1359                 : NS_IMETHODIMP
        1360              77 : nsUrlClassifierDBService::BeginUpdate(nsIUrlClassifierUpdateObserver *observer,
        1361                 :                                       const nsACString &updateTables,
        1362                 :                                       const nsACString &clientKey)
        1363                 : {
        1364              77 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1365                 :
        1366              77 :   if (mInUpdate)
        1367               0 :     return NS_ERROR_NOT_AVAILABLE;
        1368                 :
        1369              77 :   mInUpdate = true;
        1370                 :
        1371                 :   // The proxy observer uses the current thread
        1372                 :   nsCOMPtr<nsIUrlClassifierUpdateObserver> proxyObserver =
        1373             154 :     new UrlClassifierUpdateObserverProxy(observer);
        1374                 :
        1375              77 :   return mWorkerProxy->BeginUpdate(proxyObserver, updateTables, clientKey);
        1376                 : }
        1377                 :
        1378                 : NS_IMETHODIMP
        1379              89 : nsUrlClassifierDBService::BeginStream(const nsACString &table,
        1380                 :                                       const nsACString &serverMAC)
        1381                 : {
        1382              89 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1383                 :
        1384              89 :   return mWorkerProxy->BeginStream(table, serverMAC);
        1385                 : }
        1386                 :
        1387                 : NS_IMETHODIMP
        1388              87 : nsUrlClassifierDBService::UpdateStream(const nsACString& aUpdateChunk)
        1389                 : {
        1390              87 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1391                 :
        1392              87 :   return mWorkerProxy->UpdateStream(aUpdateChunk);
        1393                 : }
        1394                 :
        1395                 : NS_IMETHODIMP
        1396              87 : nsUrlClassifierDBService::FinishStream()
        1397                 : {
        1398              87 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1399                 :
        1400              87 :   return mWorkerProxy->FinishStream();
        1401                 : }
        1402                 :
        1403                 : NS_IMETHODIMP
        1404              75 : nsUrlClassifierDBService::FinishUpdate()
        1405                 : {
        1406              75 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1407                 :
        1408              75 :   mInUpdate = false;
        1409                 :
        1410              75 :   return mWorkerProxy->FinishUpdate();
        1411                 : }
        1412                 :
        1413                 :
        1414                 : NS_IMETHODIMP
        1415               2 : nsUrlClassifierDBService::CancelUpdate()
        1416                 : {
        1417               2 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1418                 :
        1419               2 :   mInUpdate = false;
        1420                 :
        1421               2 :   return mWorkerProxy->CancelUpdate();
        1422                 : }
        1423                 :
        1424                 : NS_IMETHODIMP
        1425              46 : nsUrlClassifierDBService::ResetDatabase()
        1426                 : {
        1427              46 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1428                 :
        1429              46 :   return mWorkerProxy->ResetDatabase();
        1430                 : }
        1431                 :
        1432                 : nsresult
        1433              29 : nsUrlClassifierDBService::CacheCompletions(CacheResultArray *results)
        1434                 : {
        1435              29 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1436                 :
        1437              29 :   return mWorkerProxy->CacheCompletions(results);
        1438                 : }
        1439                 :
        1440                 : nsresult
        1441             140 : nsUrlClassifierDBService::CacheMisses(PrefixArray *results)
        1442                 : {
        1443             140 :   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
        1444                 :
        1445             140 :   return mWorkerProxy->CacheMisses(results);
        1446                 : }
        1447                 :
        1448                 : bool
        1449              54 : nsUrlClassifierDBService::GetCompleter(const nsACString &tableName,
        1450                 :                                        nsIUrlClassifierHashCompleter **completer)
        1451                 : {
        1452              54 :   if (mCompleters.Get(tableName, completer)) {
        1453              54 :     return true;
        1454                 :   }
        1455                 :
        1456               0 :   if (!mGethashWhitelist.Contains(tableName)) {
        1457               0 :     return false;
        1458                 :   }
        1459                 :
        1460               0 :   return NS_SUCCEEDED(CallGetService(NS_URLCLASSIFIERHASHCOMPLETER_CONTRACTID,
        1461                 :                                      completer));
        1462                 : }
        1463                 :
        1464                 : NS_IMETHODIMP
        1465              18 : nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic,
        1466                 :                                   const PRUnichar *aData)
        1467                 : {
        1468              18 :   if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
        1469                 :     nsresult rv;
        1470               8 :     nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject, &rv));
        1471               4 :     NS_ENSURE_SUCCESS(rv, rv);
        1472               4 :     if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) {
        1473                 :       bool tmpbool;
        1474               0 :       rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool);
        1475               0 :       mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT;
        1476               4 :     } else if (NS_LITERAL_STRING(CHECK_PHISHING_PREF).Equals(aData)) {
        1477                 :       bool tmpbool;
        1478               0 :       rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool);
        1479               0 :       mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT;
        1480               4 :     } else if (NS_LITERAL_STRING(GETHASH_TABLES_PREF).Equals(aData)) {
        1481               0 :       mGethashWhitelist.Clear();
        1482               0 :       nsXPIDLCString val;
        1483               0 :       if (NS_SUCCEEDED(prefs->GetCharPref(GETHASH_TABLES_PREF, getter_Copies(val)))) {
        1484               0 :         SplitTables(val, mGethashWhitelist);
        1485                 :       }
        1486               4 :     } else if (NS_LITERAL_STRING(CONFIRM_AGE_PREF).Equals(aData)) {
        1487                 :       PRInt32 tmpint;
        1488               4 :       rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint);
        1489               4 :       PR_ATOMIC_SET(&gFreshnessGuarantee, NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC);
        1490                 :     }
        1491              21 :   } else if (!strcmp(aTopic, "profile-before-change") ||
        1492               7 :              !strcmp(aTopic, "xpcom-shutdown-threads")) {
        1493              14 :     Shutdown();
        1494                 :   } else {
        1495               0 :     return NS_ERROR_UNEXPECTED;
        1496                 :   }
        1497                 :
        1498              18 :   return NS_OK;
        1499                 : }
        1500                 :
        1501                 : // Join the background thread if it exists.
        1502                 : nsresult
        1503              14 : nsUrlClassifierDBService::Shutdown()
        1504                 : {
        1505              14 :   LOG(("shutting down db service\n"));
        1506                 :
        1507              14 :   if (!gDbBackgroundThread)
        1508               7 :     return NS_OK;
        1509                 :
        1510               7 :   mCompleters.Clear();
        1511                 :
        1512              14 :   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
        1513               7 :   if (prefs) {
        1514               7 :     prefs->RemoveObserver(CHECK_MALWARE_PREF, this);
        1515               7 :     prefs->RemoveObserver(CHECK_PHISHING_PREF, this);
        1516               7 :     prefs->RemoveObserver(GETHASH_TABLES_PREF, this);
        1517               7 :     prefs->RemoveObserver(CONFIRM_AGE_PREF, this);
        1518                 :   }
        1519                 :
        1520                 :   nsresult rv;
        1521                 :   // First close the db connection.
        1522               7 :   if (mWorker) {
        1523               7 :     rv = mWorkerProxy->CancelUpdate();
        1524               7 :     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to post cancel update event");
        1525                 :
        1526               7 :     rv = mWorkerProxy->CloseDb();
        1527               7 :     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to post close db event");
        1528                 :   }
        1529                 :
        1530               7 :   mWorkerProxy = nsnull;
        1531                 :
        1532               7 :   LOG(("joining background thread"));
        1533                 :
        1534               7 :   gShuttingDownThread = true;
        1535                 :
        1536               7 :   nsIThread *backgroundThread = gDbBackgroundThread;
        1537               7 :   gDbBackgroundThread = nsnull;
        1538               7 :   backgroundThread->Shutdown();
        1539               7 :   NS_RELEASE(backgroundThread);
        1540                 :
        1541               7 :   return NS_OK;
        1542                 : }
        1543                 :
        1544                 : nsIThread*
        1545             834 : nsUrlClassifierDBService::BackgroundThread()
        1546                 : {
        1547             834 :   return gDbBackgroundThread;
        1548                 : }
        1549                 :

Generated by: LCOV version 1.7