Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / safe_browsing / database_manager.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/safe_browsing/database_manager.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/debug/leak_tracker.h"
14 #include "base/path_service.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/threading/thread.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/metrics/metrics_service.h"
22 #include "chrome/browser/prerender/prerender_field_trial.h"
23 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
24 #include "chrome/browser/safe_browsing/download_protection_service.h"
25 #include "chrome/browser/safe_browsing/malware_details.h"
26 #include "chrome/browser/safe_browsing/protocol_manager.h"
27 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
28 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
29 #include "chrome/browser/safe_browsing/ui_manager.h"
30 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_paths.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "chrome/common/url_constants.h"
34 #include "components/startup_metric_utils/startup_metric_utils.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37
38 using content::BrowserThread;
39
40 namespace {
41
42 // Timeout for match checks, e.g. download URLs, hashes.
43 const int kCheckTimeoutMs = 10000;
44
45 // Records disposition information about the check.  |hit| should be
46 // |true| if there were any prefix hits in |full_hashes|.
47 void RecordGetHashCheckStatus(
48     bool hit,
49     safe_browsing_util::ListType check_type,
50     const std::vector<SBFullHashResult>& full_hashes) {
51   SafeBrowsingProtocolManager::ResultType result;
52   if (full_hashes.empty()) {
53     result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
54   } else if (hit) {
55     result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
56   } else {
57     result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
58   }
59   bool is_download = check_type == safe_browsing_util::BINURL;
60   SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
61 }
62
63 bool IsExpectedThreat(
64     const SBThreatType threat_type,
65     const std::vector<SBThreatType>& expected_threats) {
66   return expected_threats.end() != std::find(expected_threats.begin(),
67                                              expected_threats.end(),
68                                              threat_type);
69 }
70
71 }  // namespace
72
73 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
74     const std::vector<GURL>& urls,
75     const std::vector<SBFullHash>& full_hashes,
76     Client* client,
77     safe_browsing_util::ListType check_type,
78     const std::vector<SBThreatType>& expected_threats)
79     : urls(urls),
80       url_results(urls.size(), SB_THREAT_TYPE_SAFE),
81       full_hashes(full_hashes),
82       full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE),
83       client(client),
84       need_get_hash(false),
85       check_type(check_type),
86       expected_threats(expected_threats) {
87   DCHECK_EQ(urls.empty(), !full_hashes.empty())
88       << "Exactly one of urls and full_hashes must be set";
89 }
90
91 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
92
93 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
94     const SafeBrowsingCheck& check) {
95   DCHECK_EQ(check.urls.size(), check.url_results.size());
96   DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
97   if (!check.urls.empty()) {
98     DCHECK(check.full_hashes.empty());
99     switch (check.check_type) {
100       case safe_browsing_util::MALWARE:
101       case safe_browsing_util::PHISH:
102         DCHECK_EQ(1u, check.urls.size());
103         OnCheckBrowseUrlResult(check.urls[0], check.url_results[0]);
104         break;
105       case safe_browsing_util::BINURL:
106         DCHECK_EQ(check.urls.size(), check.url_results.size());
107         OnCheckDownloadUrlResult(
108             check.urls,
109             *std::max_element(check.url_results.begin(),
110                               check.url_results.end()));
111         break;
112       default:
113         NOTREACHED();
114     }
115   } else if (!check.full_hashes.empty()) {
116     switch (check.check_type) {
117       case safe_browsing_util::EXTENSIONBLACKLIST: {
118         std::set<std::string> unsafe_extension_ids;
119         for (size_t i = 0; i < check.full_hashes.size(); ++i) {
120           std::string extension_id =
121               safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
122           if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
123             unsafe_extension_ids.insert(extension_id);
124         }
125         OnCheckExtensionsResult(unsafe_extension_ids);
126         break;
127       }
128       default:
129         NOTREACHED();
130     }
131   } else {
132     NOTREACHED();
133   }
134 }
135
136 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
137     const scoped_refptr<SafeBrowsingService>& service)
138     : sb_service_(service),
139       database_(NULL),
140       enabled_(false),
141       enable_download_protection_(false),
142       enable_csd_whitelist_(false),
143       enable_download_whitelist_(false),
144       enable_extension_blacklist_(false),
145       enable_side_effect_free_whitelist_(false),
146       enable_ip_blacklist_(false),
147       update_in_progress_(false),
148       database_update_in_progress_(false),
149       closing_database_(false),
150       check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
151   DCHECK(sb_service_.get() != NULL);
152
153   CommandLine* cmdline = CommandLine::ForCurrentProcess();
154   enable_download_protection_ =
155       !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
156
157   // We only download the csd-whitelist if client-side phishing detection is
158   // enabled.
159   enable_csd_whitelist_ =
160       !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
161
162   // TODO(noelutz): remove this boolean variable since it should always be true
163   // if SafeBrowsing is enabled.  Unfortunately, we have no test data for this
164   // list right now.  This means that we need to be able to disable this list
165   // for the SafeBrowsing test to pass.
166   enable_download_whitelist_ = enable_csd_whitelist_;
167
168   // TODO(kalman): there really shouldn't be a flag for this.
169   enable_extension_blacklist_ =
170       !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
171
172   enable_side_effect_free_whitelist_ =
173       prerender::IsSideEffectFreeWhitelistEnabled() &&
174       !cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist);
175
176   // The client-side IP blacklist feature is tightly integrated with client-side
177   // phishing protection for now.
178   enable_ip_blacklist_ = enable_csd_whitelist_;
179
180   enum SideEffectFreeWhitelistStatus {
181     SIDE_EFFECT_FREE_WHITELIST_ENABLED,
182     SIDE_EFFECT_FREE_WHITELIST_DISABLED,
183     SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
184   };
185
186   SideEffectFreeWhitelistStatus side_effect_free_whitelist_status =
187       enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED :
188       SIDE_EFFECT_FREE_WHITELIST_DISABLED;
189
190   UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
191                             side_effect_free_whitelist_status,
192                             SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX);
193 }
194
195 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
196   // We should have already been shut down. If we're still enabled, then the
197   // database isn't going to be closed properly, which could lead to corruption.
198   DCHECK(!enabled_);
199 }
200
201 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
202   return url.SchemeIs(content::kFtpScheme) ||
203          url.SchemeIs(content::kHttpScheme) ||
204          url.SchemeIs(content::kHttpsScheme);
205 }
206
207 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
208     const std::vector<GURL>& url_chain,
209     Client* client) {
210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211   if (!enabled_ || !enable_download_protection_)
212     return true;
213
214   // We need to check the database for url prefix, and later may fetch the url
215   // from the safebrowsing backends. These need to be asynchronous.
216   SafeBrowsingCheck* check =
217       new SafeBrowsingCheck(url_chain,
218                             std::vector<SBFullHash>(),
219                             client,
220                             safe_browsing_util::BINURL,
221                             std::vector<SBThreatType>(1,
222                                 SB_THREAT_TYPE_BINARY_MALWARE_URL));
223   StartSafeBrowsingCheck(
224       check,
225       base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
226                  check));
227   return false;
228 }
229
230 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
231     const std::set<std::string>& extension_ids,
232     Client* client) {
233   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
234
235   if (!enabled_ || !enable_extension_blacklist_)
236     return true;
237
238   std::vector<SBFullHash> extension_id_hashes;
239   std::transform(extension_ids.begin(), extension_ids.end(),
240                  std::back_inserter(extension_id_hashes),
241                  safe_browsing_util::StringToSBFullHash);
242
243   SafeBrowsingCheck* check = new SafeBrowsingCheck(
244       std::vector<GURL>(),
245       extension_id_hashes,
246       client,
247       safe_browsing_util::EXTENSIONBLACKLIST,
248       std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION));
249
250   StartSafeBrowsingCheck(
251       check,
252       base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
253                  this,
254                  check));
255   return false;
256 }
257
258 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
259     const GURL& url) {
260   if (!enabled_)
261     return false;
262
263   if (!CanCheckUrl(url))
264     return false;
265
266   return database_->ContainsSideEffectFreeWhitelistUrl(url);
267 }
268
269 bool SafeBrowsingDatabaseManager::MatchMalwareIP(
270     const std::string& ip_address) {
271   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
272   if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
273     return false;  // Fail open.
274   }
275   return database_->ContainsMalwareIP(ip_address);
276 }
277
278 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
279   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
280   if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
281     // There is something funky going on here -- for example, perhaps the user
282     // has not restarted since enabling metrics reporting, so we haven't
283     // enabled the csd whitelist yet.  Just to be safe we return true in this
284     // case.
285     return true;
286   }
287   return database_->ContainsCsdWhitelistedUrl(url);
288 }
289
290 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
291   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292   if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
293     return true;
294   }
295   return database_->ContainsDownloadWhitelistedUrl(url);
296 }
297
298 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
299     const std::string& str) {
300   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301   if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
302     return true;
303   }
304   return database_->ContainsDownloadWhitelistedString(str);
305 }
306
307 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
308   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309   if (!enabled_ || !MakeDatabaseAvailable()) {
310     return true;
311   }
312   return database_->IsMalwareIPMatchKillSwitchOn();
313 }
314
315 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
316                                                  Client* client) {
317   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
318   if (!enabled_)
319     return true;
320
321   if (!CanCheckUrl(url))
322     return true;
323
324   std::vector<SBThreatType> expected_threats;
325   expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
326   expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
327
328   const base::TimeTicks start = base::TimeTicks::Now();
329   if (!MakeDatabaseAvailable()) {
330     QueuedCheck queued_check(safe_browsing_util::MALWARE,  // or PHISH
331                              client,
332                              url,
333                              expected_threats,
334                              start);
335     queued_checks_.push_back(queued_check);
336     return false;
337   }
338
339   std::string list;
340   std::vector<SBPrefix> prefix_hits;
341   std::vector<SBFullHashResult> full_hits;
342
343   bool prefix_match =
344       database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits,
345           sb_service_->protocol_manager()->last_update());
346
347   UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
348
349   if (!prefix_match)
350     return true;  // URL is okay.
351
352   // Needs to be asynchronous, since we could be in the constructor of a
353   // ResourceDispatcherHost event handler which can't pause there.
354   SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
355                                                    std::vector<SBFullHash>(),
356                                                    client,
357                                                    safe_browsing_util::MALWARE,
358                                                    expected_threats);
359   check->need_get_hash = full_hits.empty();
360   check->prefix_hits.swap(prefix_hits);
361   check->full_hits.swap(full_hits);
362   checks_.insert(check);
363
364   BrowserThread::PostTask(
365       BrowserThread::IO, FROM_HERE,
366       base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
367
368   return false;
369 }
370
371 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
372   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
373   for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
374     // We can't delete matching checks here because the db thread has a copy of
375     // the pointer.  Instead, we simply NULL out the client, and when the db
376     // thread calls us back, we'll clean up the check.
377     if ((*i)->client == client)
378       (*i)->client = NULL;
379   }
380
381   // Scan the queued clients store. Clients may be here if they requested a URL
382   // check before the database has finished loading.
383   for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
384        it != queued_checks_.end(); ) {
385     // In this case it's safe to delete matches entirely since nothing has a
386     // pointer to them.
387     if (it->client == client)
388       it = queued_checks_.erase(it);
389     else
390       ++it;
391   }
392 }
393
394 void SafeBrowsingDatabaseManager::HandleGetHashResults(
395     SafeBrowsingCheck* check,
396     const std::vector<SBFullHashResult>& full_hashes,
397     bool can_cache) {
398   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
399
400   if (!enabled_)
401     return;
402
403   // If the service has been shut down, |check| should have been deleted.
404   DCHECK(checks_.find(check) != checks_.end());
405
406   // |start| is set before calling |GetFullHash()|, which should be
407   // the only path which gets to here.
408   DCHECK(!check->start.is_null());
409   UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
410                            base::TimeTicks::Now() - check->start);
411
412   std::vector<SBPrefix> prefixes = check->prefix_hits;
413   OnHandleGetHashResults(check, full_hashes);  // 'check' is deleted here.
414
415   if (can_cache && MakeDatabaseAvailable()) {
416     // Cache the GetHash results in memory:
417     database_->CacheHashResults(prefixes, full_hashes);
418   }
419 }
420
421 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
422   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
423   DCHECK(enabled_);
424   DCHECK(!callback.is_null());
425   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
426       &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, callback));
427 }
428
429 void SafeBrowsingDatabaseManager::AddChunks(const std::string& list,
430                                             SBChunkList* chunks,
431                                             AddChunksCallback callback) {
432   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
433   DCHECK(enabled_);
434   DCHECK(!callback.is_null());
435   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
436       &SafeBrowsingDatabaseManager::AddDatabaseChunks, this, list,
437       chunks, callback));
438 }
439
440 void SafeBrowsingDatabaseManager::DeleteChunks(
441     std::vector<SBChunkDelete>* chunk_deletes) {
442   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
443   DCHECK(enabled_);
444   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
445       &SafeBrowsingDatabaseManager::DeleteDatabaseChunks, this, chunk_deletes));
446 }
447
448 void SafeBrowsingDatabaseManager::UpdateStarted() {
449   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
450   DCHECK(enabled_);
451   DCHECK(!update_in_progress_);
452   update_in_progress_ = true;
453 }
454
455 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
456   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
457   DCHECK(enabled_);
458   if (update_in_progress_) {
459     update_in_progress_ = false;
460     safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
461       base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished,
462                  this, update_succeeded));
463   }
464 }
465
466 void SafeBrowsingDatabaseManager::ResetDatabase() {
467   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
468   DCHECK(enabled_);
469   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
470       &SafeBrowsingDatabaseManager::OnResetDatabase, this));
471 }
472
473 void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time) {
474   UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
475 }
476
477 void SafeBrowsingDatabaseManager::StartOnIOThread() {
478   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
479   if (enabled_)
480     return;
481
482   DCHECK(!safe_browsing_thread_.get());
483   safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
484   if (!safe_browsing_thread_->Start())
485     return;
486   enabled_ = true;
487
488   MakeDatabaseAvailable();
489 }
490
491 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
492   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
493
494   DoStopOnIOThread();
495   if (shutdown) {
496     sb_service_ = NULL;
497   }
498 }
499
500 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
501     bool update_succeeded) {
502   content::NotificationService::current()->Notify(
503       chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
504       content::Source<SafeBrowsingDatabaseManager>(this),
505       content::Details<bool>(&update_succeeded));
506 }
507
508 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
509     const safe_browsing_util::ListType check_type,
510     Client* client,
511     const GURL& url,
512     const std::vector<SBThreatType>& expected_threats,
513     const base::TimeTicks& start)
514     : check_type(check_type),
515       client(client),
516       url(url),
517       expected_threats(expected_threats),
518       start(start) {
519 }
520
521 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
522 }
523
524 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
525   if (!enabled_)
526     return;
527
528   enabled_ = false;
529
530   // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
531   while (!queued_checks_.empty()) {
532     QueuedCheck queued = queued_checks_.front();
533     if (queued.client) {
534       SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
535                                  std::vector<SBFullHash>(),
536                                  queued.client,
537                                  queued.check_type,
538                                  queued.expected_threats);
539       queued.client->OnSafeBrowsingResult(sb_check);
540     }
541     queued_checks_.pop_front();
542   }
543
544   // Close the database.  Cases to avoid:
545   //  * If |closing_database_| is true, continuing will queue up a second
546   //    request, |closing_database_| will be reset after handling the first
547   //    request, and if any functions on the db thread recreate the database, we
548   //    could start using it on the IO thread and then have the second request
549   //    handler delete it out from under us.
550   //  * If |database_| is NULL, then either no creation request is in flight, in
551   //    which case we don't need to do anything, or one is in flight, in which
552   //    case the database will be recreated before our deletion request is
553   //    handled, and could be used on the IO thread in that time period, leading
554   //    to the same problem as above.
555   // Checking DatabaseAvailable() avoids both of these.
556   if (DatabaseAvailable()) {
557     closing_database_ = true;
558     safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
559         base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
560   }
561
562   // Flush the database thread. Any in-progress database check results will be
563   // ignored and cleaned up below.
564   //
565   // Note that to avoid leaking the database, we rely on the fact that no new
566   // tasks will be added to the db thread between the call above and this one.
567   // See comments on the declaration of |safe_browsing_thread_|.
568   {
569     // A ScopedAllowIO object is required to join the thread when calling Stop.
570     // See http://crbug.com/72696. Note that we call Stop() first to clear out
571     // any remaining tasks before clearing safe_browsing_thread_.
572     base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
573     safe_browsing_thread_->Stop();
574     safe_browsing_thread_.reset();
575   }
576
577   // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
578   // We have to do this after the db thread returns because methods on it can
579   // have copies of these pointers, so deleting them might lead to accessing
580   // garbage.
581   for (CurrentChecks::iterator it = checks_.begin();
582        it != checks_.end(); ++it) {
583     SafeBrowsingCheck* check = *it;
584     if (check->client)
585       check->client->OnSafeBrowsingResult(*check);
586   }
587   STLDeleteElements(&checks_);
588
589   gethash_requests_.clear();
590 }
591
592 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
593   base::AutoLock lock(database_lock_);
594   return !closing_database_ && (database_ != NULL);
595 }
596
597 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
598   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
599   DCHECK(enabled_);
600   if (DatabaseAvailable())
601     return true;
602   safe_browsing_thread_->message_loop()->PostTask(
603       FROM_HERE,
604       base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
605                  this));
606   return false;
607 }
608
609 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
610   DCHECK_EQ(base::MessageLoop::current(),
611             safe_browsing_thread_->message_loop());
612   if (database_)
613     return database_;
614   startup_metric_utils::ScopedSlowStartupUMA
615       scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
616   const base::TimeTicks before = base::TimeTicks::Now();
617
618   SafeBrowsingDatabase* database =
619       SafeBrowsingDatabase::Create(enable_download_protection_,
620                                    enable_csd_whitelist_,
621                                    enable_download_whitelist_,
622                                    enable_extension_blacklist_,
623                                    enable_side_effect_free_whitelist_,
624                                    enable_ip_blacklist_);
625
626   database->Init(SafeBrowsingService::GetBaseFilename());
627   {
628     // Acquiring the lock here guarantees correct ordering between the writes to
629     // the new database object above, and the setting of |databse_| below.
630     base::AutoLock lock(database_lock_);
631     database_ = database;
632   }
633
634   BrowserThread::PostTask(
635       BrowserThread::IO, FROM_HERE,
636       base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
637
638   UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
639   return database_;
640 }
641
642 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
643   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
644
645   if (!enabled_)
646     return;
647
648   // If the service has been shut down, |check| should have been deleted.
649   DCHECK(checks_.find(check) != checks_.end());
650
651   if (check->client && check->need_get_hash) {
652     // We have a partial match so we need to query Google for the full hash.
653     // Clean up will happen in HandleGetHashResults.
654
655     // See if we have a GetHash request already in progress for this particular
656     // prefix. If so, we just append ourselves to the list of interested parties
657     // when the results arrive. We only do this for checks involving one prefix,
658     // since that is the common case (multiple prefixes will issue the request
659     // as normal).
660     if (check->prefix_hits.size() == 1) {
661       SBPrefix prefix = check->prefix_hits[0];
662       GetHashRequests::iterator it = gethash_requests_.find(prefix);
663       if (it != gethash_requests_.end()) {
664         // There's already a request in progress.
665         it->second.push_back(check);
666         return;
667       }
668
669       // No request in progress, so we're the first for this prefix.
670       GetHashRequestors requestors;
671       requestors.push_back(check);
672       gethash_requests_[prefix] = requestors;
673     }
674
675     // Reset the start time so that we can measure the network time without the
676     // database time.
677     check->start = base::TimeTicks::Now();
678     // Note: If |this| is deleted or stopped, the protocol_manager will
679     // be destroyed as well - hence it's OK to do unretained in this case.
680     bool is_download = check->check_type == safe_browsing_util::BINURL;
681     sb_service_->protocol_manager()->GetFullHash(
682         check->prefix_hits,
683         base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
684                    base::Unretained(this),
685                    check),
686         is_download);
687   } else {
688     // We may have cached results for previous GetHash queries.  Since
689     // this data comes from cache, don't histogram hits.
690     HandleOneCheck(check, check->full_hits);
691   }
692 }
693
694 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
695     GetChunksCallback callback) {
696   DCHECK_EQ(base::MessageLoop::current(),
697             safe_browsing_thread_->message_loop());
698
699   bool database_error = true;
700   std::vector<SBListChunkRanges> lists;
701   DCHECK(!database_update_in_progress_);
702   database_update_in_progress_ = true;
703   GetDatabase();  // This guarantees that |database_| is non-NULL.
704   if (database_->UpdateStarted(&lists)) {
705     database_error = false;
706   } else {
707     database_->UpdateFinished(false);
708   }
709
710   BrowserThread::PostTask(
711       BrowserThread::IO, FROM_HERE,
712       base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
713                  this, lists, database_error, callback));
714 }
715
716 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
717     const std::vector<SBListChunkRanges>& lists, bool database_error,
718     GetChunksCallback callback) {
719   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
720   if (enabled_)
721     callback.Run(lists, database_error);
722 }
723
724 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
725     AddChunksCallback callback) {
726   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
727   if (enabled_)
728     callback.Run();
729 }
730
731 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
732   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
733   if (!enabled_)
734     return;
735
736   HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
737   if (queued_checks_.empty())
738     return;
739
740   // If the database isn't already available, calling CheckUrl() in the loop
741   // below will add the check back to the queue, and we'll infinite-loop.
742   DCHECK(DatabaseAvailable());
743   while (!queued_checks_.empty()) {
744     QueuedCheck check = queued_checks_.front();
745     DCHECK(!check.start.is_null());
746     HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
747     // If CheckUrl() determines the URL is safe immediately, it doesn't call the
748     // client's handler function (because normally it's being directly called by
749     // the client).  Since we're not the client, we have to convey this result.
750     if (check.client && CheckBrowseUrl(check.url, check.client)) {
751       SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
752                                  std::vector<SBFullHash>(),
753                                  check.client,
754                                  check.check_type,
755                                  check.expected_threats);
756       check.client->OnSafeBrowsingResult(sb_check);
757     }
758     queued_checks_.pop_front();
759   }
760 }
761
762 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
763     const std::string& list_name, SBChunkList* chunks,
764     AddChunksCallback callback) {
765   DCHECK_EQ(base::MessageLoop::current(),
766             safe_browsing_thread_->message_loop());
767   if (chunks) {
768     GetDatabase()->InsertChunks(list_name, *chunks);
769     delete chunks;
770   }
771   BrowserThread::PostTask(
772       BrowserThread::IO, FROM_HERE,
773       base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
774                  callback));
775 }
776
777 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
778     std::vector<SBChunkDelete>* chunk_deletes) {
779   DCHECK_EQ(base::MessageLoop::current(),
780             safe_browsing_thread_->message_loop());
781   if (chunk_deletes) {
782     GetDatabase()->DeleteChunks(*chunk_deletes);
783     delete chunk_deletes;
784   }
785 }
786
787 SBThreatType SafeBrowsingDatabaseManager::GetThreatTypeFromListname(
788     const std::string& list_name) {
789   if (safe_browsing_util::IsPhishingList(list_name)) {
790     return SB_THREAT_TYPE_URL_PHISHING;
791   }
792
793   if (safe_browsing_util::IsMalwareList(list_name)) {
794     return SB_THREAT_TYPE_URL_MALWARE;
795   }
796
797   if (safe_browsing_util::IsBadbinurlList(list_name)) {
798     return SB_THREAT_TYPE_BINARY_MALWARE_URL;
799   }
800
801   if (safe_browsing_util::IsExtensionList(list_name)) {
802     return SB_THREAT_TYPE_EXTENSION;
803   }
804
805   DVLOG(1) << "Unknown safe browsing list " << list_name;
806   return SB_THREAT_TYPE_SAFE;
807 }
808
809 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
810     bool update_succeeded) {
811   DCHECK_EQ(base::MessageLoop::current(),
812             safe_browsing_thread_->message_loop());
813   GetDatabase()->UpdateFinished(update_succeeded);
814   DCHECK(database_update_in_progress_);
815   database_update_in_progress_ = false;
816   BrowserThread::PostTask(
817       BrowserThread::UI, FROM_HERE,
818       base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
819                  this, update_succeeded));
820 }
821
822 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
823   DCHECK_EQ(base::MessageLoop::current(),
824             safe_browsing_thread_->message_loop());
825   DCHECK(closing_database_);
826
827   // Because |closing_database_| is true, nothing on the IO thread will be
828   // accessing the database, so it's safe to delete and then NULL the pointer.
829   delete database_;
830   database_ = NULL;
831
832   // Acquiring the lock here guarantees correct ordering between the resetting
833   // of |database_| above and of |closing_database_| below, which ensures there
834   // won't be a window during which the IO thread falsely believes the database
835   // is available.
836   base::AutoLock lock(database_lock_);
837   closing_database_ = false;
838 }
839
840 void SafeBrowsingDatabaseManager::OnResetDatabase() {
841   DCHECK_EQ(base::MessageLoop::current(),
842             safe_browsing_thread_->message_loop());
843   GetDatabase()->ResetDatabase();
844 }
845
846 void SafeBrowsingDatabaseManager::CacheHashResults(
847   const std::vector<SBPrefix>& prefixes,
848   const std::vector<SBFullHashResult>& full_hashes) {
849   DCHECK_EQ(base::MessageLoop::current(),
850             safe_browsing_thread_->message_loop());
851   GetDatabase()->CacheHashResults(prefixes, full_hashes);
852 }
853
854 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
855     SafeBrowsingCheck* check,
856     const std::vector<SBFullHashResult>& full_hashes) {
857   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
858   safe_browsing_util::ListType check_type = check->check_type;
859   SBPrefix prefix = check->prefix_hits[0];
860   GetHashRequests::iterator it = gethash_requests_.find(prefix);
861   if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
862     const bool hit = HandleOneCheck(check, full_hashes);
863     RecordGetHashCheckStatus(hit, check_type, full_hashes);
864     return;
865   }
866
867   // Call back all interested parties, noting if any has a hit.
868   GetHashRequestors& requestors = it->second;
869   bool hit = false;
870   for (GetHashRequestors::iterator r = requestors.begin();
871        r != requestors.end(); ++r) {
872     if (HandleOneCheck(*r, full_hashes))
873       hit = true;
874   }
875   RecordGetHashCheckStatus(hit, check_type, full_hashes);
876
877   gethash_requests_.erase(it);
878 }
879
880 bool SafeBrowsingDatabaseManager::HandleOneCheck(
881     SafeBrowsingCheck* check,
882     const std::vector<SBFullHashResult>& full_hashes) {
883   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
884   DCHECK(check);
885
886   bool is_threat = false;
887
888   for (size_t i = 0; i < check->urls.size(); ++i) {
889     int index =
890         safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
891     if (index == -1)
892       continue;
893     SBThreatType threat =
894         GetThreatTypeFromListname(full_hashes[index].list_name);
895     if (threat != SB_THREAT_TYPE_SAFE &&
896         IsExpectedThreat(threat, check->expected_threats)) {
897       check->url_results[i] = threat;
898       is_threat = true;
899     }
900   }
901
902   for (size_t i = 0; i < check->full_hashes.size(); ++i) {
903     int index =
904         safe_browsing_util::GetHashIndex(check->full_hashes[i], full_hashes);
905     if (index == -1)
906       continue;
907     SBThreatType threat =
908         GetThreatTypeFromListname(full_hashes[index].list_name);
909     if (threat != SB_THREAT_TYPE_SAFE &&
910         IsExpectedThreat(threat, check->expected_threats)) {
911       check->full_hash_results[i] = threat;
912       is_threat = true;
913     }
914   }
915
916   SafeBrowsingCheckDone(check);
917   return is_threat;
918 }
919
920 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
921     SafeBrowsingCheck* check) {
922   DCHECK_EQ(base::MessageLoop::current(),
923             safe_browsing_thread_->message_loop());
924   DCHECK(enable_download_protection_);
925
926   std::vector<SBPrefix> prefix_hits;
927
928   if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
929     // Good, we don't have hash for this url prefix.
930     BrowserThread::PostTask(
931         BrowserThread::IO, FROM_HERE,
932         base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this,
933                    check));
934     return;
935   }
936
937   check->need_get_hash = true;
938   check->prefix_hits.clear();
939   check->prefix_hits = prefix_hits;
940   BrowserThread::PostTask(
941       BrowserThread::IO, FROM_HERE,
942       base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
943 }
944
945 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
946     SafeBrowsingCheck* check) {
947   DCHECK_EQ(base::MessageLoop::current(),
948             safe_browsing_thread_->message_loop());
949
950   std::vector<SBPrefix> prefixes;
951   for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
952        it != check->full_hashes.end(); ++it) {
953     prefixes.push_back((*it).prefix);
954   }
955   database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
956
957   if (check->prefix_hits.empty()) {
958     // No matches for any extensions.
959     BrowserThread::PostTask(
960         BrowserThread::IO,
961         FROM_HERE,
962         base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
963                    check));
964   } else {
965     // Some prefixes matched, we need to ask Google whether they're legit.
966     check->need_get_hash = true;
967     BrowserThread::PostTask(
968         BrowserThread::IO,
969         FROM_HERE,
970         base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
971   }
972 }
973
974 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
975   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
976   DCHECK(check);
977
978   if (!enabled_)
979     return;
980
981   DCHECK(checks_.find(check) != checks_.end());
982   if (check->client) {
983     check->client->OnSafeBrowsingResult(*check);
984     check->client = NULL;
985   }
986 }
987
988 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
989     SafeBrowsingCheck* check) {
990   DCHECK(enable_download_protection_);
991   SafeBrowsingCheckDone(check);
992 }
993
994 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
995     SafeBrowsingCheck* check) {
996   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
997   DCHECK(check);
998
999   if (!enabled_)
1000     return;
1001
1002   VLOG(1) << "SafeBrowsingCheckDone";
1003   DCHECK(checks_.find(check) != checks_.end());
1004   if (check->client)
1005     check->client->OnSafeBrowsingResult(*check);
1006   checks_.erase(check);
1007   delete check;
1008 }
1009
1010 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1011     SafeBrowsingCheck* check,
1012     const base::Closure& task) {
1013   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1014   check->timeout_factory_.reset(
1015       new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
1016   checks_.insert(check);
1017
1018   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
1019
1020   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
1021       base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
1022                  check->timeout_factory_->GetWeakPtr(), check),
1023       check_timeout_);
1024 }