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.
5 #include "chrome/browser/safe_browsing/database_manager.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"
38 using content::BrowserThread
;
42 // Timeout for match checks, e.g. download URLs, hashes.
43 const int kCheckTimeoutMs
= 10000;
45 // Records disposition information about the check. |hit| should be
46 // |true| if there were any prefix hits in |full_hashes|.
47 void RecordGetHashCheckStatus(
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
;
55 result
= SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT
;
57 result
= SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS
;
59 bool is_download
= check_type
== safe_browsing_util::BINURL
;
60 SafeBrowsingProtocolManager::RecordGetHashResult(is_download
, result
);
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(),
73 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
74 const std::vector
<GURL
>& urls
,
75 const std::vector
<SBFullHash
>& full_hashes
,
77 safe_browsing_util::ListType check_type
,
78 const std::vector
<SBThreatType
>& expected_threats
)
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
),
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";
91 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
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]);
105 case safe_browsing_util::BINURL
:
106 DCHECK_EQ(check
.urls
.size(), check
.url_results
.size());
107 OnCheckDownloadUrlResult(
109 *std::max_element(check
.url_results
.begin(),
110 check
.url_results
.end()));
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
);
125 OnCheckExtensionsResult(unsafe_extension_ids
);
136 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
137 const scoped_refptr
<SafeBrowsingService
>& service
)
138 : sb_service_(service
),
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
);
153 CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
154 enable_download_protection_
=
155 !cmdline
->HasSwitch(switches::kSbDisableDownloadProtection
);
157 // We only download the csd-whitelist if client-side phishing detection is
159 enable_csd_whitelist_
=
160 !cmdline
->HasSwitch(switches::kDisableClientSidePhishingDetection
);
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_
;
168 // TODO(kalman): there really shouldn't be a flag for this.
169 enable_extension_blacklist_
=
170 !cmdline
->HasSwitch(switches::kSbDisableExtensionBlacklist
);
172 enable_side_effect_free_whitelist_
=
173 prerender::IsSideEffectFreeWhitelistEnabled() &&
174 !cmdline
->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist
);
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_
;
180 enum SideEffectFreeWhitelistStatus
{
181 SIDE_EFFECT_FREE_WHITELIST_ENABLED
,
182 SIDE_EFFECT_FREE_WHITELIST_DISABLED
,
183 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
186 SideEffectFreeWhitelistStatus side_effect_free_whitelist_status
=
187 enable_side_effect_free_whitelist_
? SIDE_EFFECT_FREE_WHITELIST_ENABLED
:
188 SIDE_EFFECT_FREE_WHITELIST_DISABLED
;
190 UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
191 side_effect_free_whitelist_status
,
192 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
);
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.
201 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL
& url
) const {
202 return url
.SchemeIs(content::kFtpScheme
) ||
203 url
.SchemeIs(content::kHttpScheme
) ||
204 url
.SchemeIs(content::kHttpsScheme
);
207 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
208 const std::vector
<GURL
>& url_chain
,
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
211 if (!enabled_
|| !enable_download_protection_
)
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
>(),
220 safe_browsing_util::BINURL
,
221 std::vector
<SBThreatType
>(1,
222 SB_THREAT_TYPE_BINARY_MALWARE_URL
));
223 StartSafeBrowsingCheck(
225 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread
, this,
230 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
231 const std::set
<std::string
>& extension_ids
,
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
235 if (!enabled_
|| !enable_extension_blacklist_
)
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
);
243 SafeBrowsingCheck
* check
= new SafeBrowsingCheck(
247 safe_browsing_util::EXTENSIONBLACKLIST
,
248 std::vector
<SBThreatType
>(1, SB_THREAT_TYPE_EXTENSION
));
250 StartSafeBrowsingCheck(
252 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread
,
258 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
263 if (!CanCheckUrl(url
))
266 return database_
->ContainsSideEffectFreeWhitelistUrl(url
);
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.
275 return database_
->ContainsMalwareIP(ip_address
);
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
287 return database_
->ContainsCsdWhitelistedUrl(url
);
290 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL
& url
) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
292 if (!enabled_
|| !enable_download_whitelist_
|| !MakeDatabaseAvailable()) {
295 return database_
->ContainsDownloadWhitelistedUrl(url
);
298 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
299 const std::string
& str
) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
301 if (!enabled_
|| !enable_download_whitelist_
|| !MakeDatabaseAvailable()) {
304 return database_
->ContainsDownloadWhitelistedString(str
);
307 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
309 if (!enabled_
|| !MakeDatabaseAvailable()) {
312 return database_
->IsMalwareIPMatchKillSwitchOn();
315 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL
& url
,
317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
321 if (!CanCheckUrl(url
))
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
);
328 const base::TimeTicks start
= base::TimeTicks::Now();
329 if (!MakeDatabaseAvailable()) {
330 QueuedCheck
queued_check(safe_browsing_util::MALWARE
, // or PHISH
335 queued_checks_
.push_back(queued_check
);
340 std::vector
<SBPrefix
> prefix_hits
;
341 std::vector
<SBFullHashResult
> full_hits
;
344 database_
->ContainsBrowseUrl(url
, &list
, &prefix_hits
, &full_hits
,
345 sb_service_
->protocol_manager()->last_update());
347 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start
);
350 return true; // URL is okay.
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
>(),
357 safe_browsing_util::MALWARE
,
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
);
364 BrowserThread::PostTask(
365 BrowserThread::IO
, FROM_HERE
,
366 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
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
)
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
387 if (it
->client
== client
)
388 it
= queued_checks_
.erase(it
);
394 void SafeBrowsingDatabaseManager::HandleGetHashResults(
395 SafeBrowsingCheck
* check
,
396 const std::vector
<SBFullHashResult
>& full_hashes
,
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
403 // If the service has been shut down, |check| should have been deleted.
404 DCHECK(checks_
.find(check
) != checks_
.end());
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
);
412 std::vector
<SBPrefix
> prefixes
= check
->prefix_hits
;
413 OnHandleGetHashResults(check
, full_hashes
); // 'check' is deleted here.
415 if (can_cache
&& MakeDatabaseAvailable()) {
416 // Cache the GetHash results in memory:
417 database_
->CacheHashResults(prefixes
, full_hashes
);
421 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback
) {
422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
424 DCHECK(!callback
.is_null());
425 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
426 &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase
, this, callback
));
429 void SafeBrowsingDatabaseManager::AddChunks(const std::string
& list
,
431 AddChunksCallback callback
) {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
434 DCHECK(!callback
.is_null());
435 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
436 &SafeBrowsingDatabaseManager::AddDatabaseChunks
, this, list
,
440 void SafeBrowsingDatabaseManager::DeleteChunks(
441 std::vector
<SBChunkDelete
>* chunk_deletes
) {
442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
444 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
445 &SafeBrowsingDatabaseManager::DeleteDatabaseChunks
, this, chunk_deletes
));
448 void SafeBrowsingDatabaseManager::UpdateStarted() {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
451 DCHECK(!update_in_progress_
);
452 update_in_progress_
= true;
455 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded
) {
456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
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
));
466 void SafeBrowsingDatabaseManager::ResetDatabase() {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
469 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
470 &SafeBrowsingDatabaseManager::OnResetDatabase
, this));
473 void SafeBrowsingDatabaseManager::PurgeMemory() {
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
478 void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time
) {
479 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time
);
482 void SafeBrowsingDatabaseManager::StartOnIOThread() {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
487 DCHECK(!safe_browsing_thread_
.get());
488 safe_browsing_thread_
.reset(new base::Thread("Chrome_SafeBrowsingThread"));
489 if (!safe_browsing_thread_
->Start())
493 MakeDatabaseAvailable();
496 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown
) {
497 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
505 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
506 bool update_succeeded
) {
507 content::NotificationService::current()->Notify(
508 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE
,
509 content::Source
<SafeBrowsingDatabaseManager
>(this),
510 content::Details
<bool>(&update_succeeded
));
513 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
514 const safe_browsing_util::ListType check_type
,
517 const std::vector
<SBThreatType
>& expected_threats
,
518 const base::TimeTicks
& start
)
519 : check_type(check_type
),
522 expected_threats(expected_threats
),
526 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
529 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
535 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
536 // If we don't do this here we may fail to close the database below.
537 while (!queued_checks_
.empty()) {
538 QueuedCheck queued
= queued_checks_
.front();
540 SafeBrowsingCheck
sb_check(std::vector
<GURL
>(1, queued
.url
),
541 std::vector
<SBFullHash
>(),
544 queued
.expected_threats
);
545 queued
.client
->OnSafeBrowsingResult(sb_check
);
547 queued_checks_
.pop_front();
550 // Close the database. We don't simply DeleteSoon() because if a close is
551 // already pending, we'll double-free, and we don't set |database_| to NULL
552 // because if there is still anything running on the db thread, it could
553 // create a new database object (via GetDatabase()) that would then leak.
556 // Flush the database thread. Any in-progress database check results will be
557 // ignored and cleaned up below.
559 // Note that to avoid leaking the database, we rely on the fact that no new
560 // tasks will be added to the db thread between the call above and this one.
561 // See comments on the declaration of |safe_browsing_thread_|.
563 // A ScopedAllowIO object is required to join the thread when calling Stop.
564 // See http://crbug.com/72696. Note that we call Stop() first to clear out
565 // any remaining tasks before clearing safe_browsing_thread_.
566 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join
;
567 safe_browsing_thread_
->Stop();
568 safe_browsing_thread_
.reset();
571 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
572 // We have to do this after the db thread returns because methods on it can
573 // have copies of these pointers, so deleting them might lead to accessing
575 for (CurrentChecks::iterator it
= checks_
.begin();
576 it
!= checks_
.end(); ++it
) {
577 SafeBrowsingCheck
* check
= *it
;
579 check
->client
->OnSafeBrowsingResult(*check
);
581 STLDeleteElements(&checks_
);
583 gethash_requests_
.clear();
586 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
587 base::AutoLock
lock(database_lock_
);
588 return !closing_database_
&& (database_
!= NULL
);
591 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
594 if (DatabaseAvailable())
596 safe_browsing_thread_
->message_loop()->PostTask(
598 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase
),
603 void SafeBrowsingDatabaseManager::CloseDatabase() {
604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
607 // * If |closing_database_| is true, continuing will queue up a second
608 // request, |closing_database_| will be reset after handling the first
609 // request, and if any functions on the db thread recreate the database, we
610 // could start using it on the IO thread and then have the second request
611 // handler delete it out from under us.
612 // * If |database_| is NULL, then either no creation request is in flight, in
613 // which case we don't need to do anything, or one is in flight, in which
614 // case the database will be recreated before our deletion request is
615 // handled, and could be used on the IO thread in that time period, leading
616 // to the same problem as above.
617 // * If |queued_checks_| is non-empty and |database_| is non-NULL, we're
618 // about to be called back (in DatabaseLoadComplete()). This will call
619 // CheckUrl(), which will want the database. Closing the database here
620 // would lead to an infinite loop in DatabaseLoadComplete(), and even if it
621 // didn't, it would be pointless since we'd just want to recreate.
623 // The first two cases above are handled by checking DatabaseAvailable().
624 if (!DatabaseAvailable() || !queued_checks_
.empty())
627 closing_database_
= true;
628 if (safe_browsing_thread_
.get()) {
629 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
,
630 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase
, this));
634 SafeBrowsingDatabase
* SafeBrowsingDatabaseManager::GetDatabase() {
635 DCHECK_EQ(base::MessageLoop::current(),
636 safe_browsing_thread_
->message_loop());
639 startup_metric_utils::ScopedSlowStartupUMA
640 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
641 const base::TimeTicks before
= base::TimeTicks::Now();
643 SafeBrowsingDatabase
* database
=
644 SafeBrowsingDatabase::Create(enable_download_protection_
,
645 enable_csd_whitelist_
,
646 enable_download_whitelist_
,
647 enable_extension_blacklist_
,
648 enable_side_effect_free_whitelist_
,
649 enable_ip_blacklist_
);
651 database
->Init(SafeBrowsingService::GetBaseFilename());
653 // Acquiring the lock here guarantees correct ordering between the writes to
654 // the new database object above, and the setting of |databse_| below.
655 base::AutoLock
lock(database_lock_
);
656 database_
= database
;
659 BrowserThread::PostTask(
660 BrowserThread::IO
, FROM_HERE
,
661 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete
, this));
663 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before
);
667 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck
* check
) {
668 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
673 // If the service has been shut down, |check| should have been deleted.
674 DCHECK(checks_
.find(check
) != checks_
.end());
676 if (check
->client
&& check
->need_get_hash
) {
677 // We have a partial match so we need to query Google for the full hash.
678 // Clean up will happen in HandleGetHashResults.
680 // See if we have a GetHash request already in progress for this particular
681 // prefix. If so, we just append ourselves to the list of interested parties
682 // when the results arrive. We only do this for checks involving one prefix,
683 // since that is the common case (multiple prefixes will issue the request
685 if (check
->prefix_hits
.size() == 1) {
686 SBPrefix prefix
= check
->prefix_hits
[0];
687 GetHashRequests::iterator it
= gethash_requests_
.find(prefix
);
688 if (it
!= gethash_requests_
.end()) {
689 // There's already a request in progress.
690 it
->second
.push_back(check
);
694 // No request in progress, so we're the first for this prefix.
695 GetHashRequestors requestors
;
696 requestors
.push_back(check
);
697 gethash_requests_
[prefix
] = requestors
;
700 // Reset the start time so that we can measure the network time without the
702 check
->start
= base::TimeTicks::Now();
703 // Note: If |this| is deleted or stopped, the protocol_manager will
704 // be destroyed as well - hence it's OK to do unretained in this case.
705 bool is_download
= check
->check_type
== safe_browsing_util::BINURL
;
706 sb_service_
->protocol_manager()->GetFullHash(
708 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults
,
709 base::Unretained(this),
713 // We may have cached results for previous GetHash queries. Since
714 // this data comes from cache, don't histogram hits.
715 HandleOneCheck(check
, check
->full_hits
);
719 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
720 GetChunksCallback callback
) {
721 DCHECK_EQ(base::MessageLoop::current(),
722 safe_browsing_thread_
->message_loop());
724 bool database_error
= true;
725 std::vector
<SBListChunkRanges
> lists
;
726 DCHECK(!database_update_in_progress_
);
727 database_update_in_progress_
= true;
728 GetDatabase(); // This guarantees that |database_| is non-NULL.
729 if (database_
->UpdateStarted(&lists
)) {
730 database_error
= false;
732 database_
->UpdateFinished(false);
735 BrowserThread::PostTask(
736 BrowserThread::IO
, FROM_HERE
,
737 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase
,
738 this, lists
, database_error
, callback
));
741 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
742 const std::vector
<SBListChunkRanges
>& lists
, bool database_error
,
743 GetChunksCallback callback
) {
744 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
746 callback
.Run(lists
, database_error
);
749 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
750 AddChunksCallback callback
) {
751 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
756 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
757 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
761 HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_
.size());
762 if (queued_checks_
.empty())
765 // If the database isn't already available, calling CheckUrl() in the loop
766 // below will add the check back to the queue, and we'll infinite-loop.
767 DCHECK(DatabaseAvailable());
768 while (!queued_checks_
.empty()) {
769 QueuedCheck check
= queued_checks_
.front();
770 DCHECK(!check
.start
.is_null());
771 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check
.start
);
772 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
773 // client's handler function (because normally it's being directly called by
774 // the client). Since we're not the client, we have to convey this result.
775 if (check
.client
&& CheckBrowseUrl(check
.url
, check
.client
)) {
776 SafeBrowsingCheck
sb_check(std::vector
<GURL
>(1, check
.url
),
777 std::vector
<SBFullHash
>(),
780 check
.expected_threats
);
781 check
.client
->OnSafeBrowsingResult(sb_check
);
783 queued_checks_
.pop_front();
787 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
788 const std::string
& list_name
, SBChunkList
* chunks
,
789 AddChunksCallback callback
) {
790 DCHECK_EQ(base::MessageLoop::current(),
791 safe_browsing_thread_
->message_loop());
793 GetDatabase()->InsertChunks(list_name
, *chunks
);
796 BrowserThread::PostTask(
797 BrowserThread::IO
, FROM_HERE
,
798 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete
, this,
802 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
803 std::vector
<SBChunkDelete
>* chunk_deletes
) {
804 DCHECK_EQ(base::MessageLoop::current(),
805 safe_browsing_thread_
->message_loop());
807 GetDatabase()->DeleteChunks(*chunk_deletes
);
808 delete chunk_deletes
;
812 SBThreatType
SafeBrowsingDatabaseManager::GetThreatTypeFromListname(
813 const std::string
& list_name
) {
814 if (safe_browsing_util::IsPhishingList(list_name
)) {
815 return SB_THREAT_TYPE_URL_PHISHING
;
818 if (safe_browsing_util::IsMalwareList(list_name
)) {
819 return SB_THREAT_TYPE_URL_MALWARE
;
822 if (safe_browsing_util::IsBadbinurlList(list_name
)) {
823 return SB_THREAT_TYPE_BINARY_MALWARE_URL
;
826 if (safe_browsing_util::IsExtensionList(list_name
)) {
827 return SB_THREAT_TYPE_EXTENSION
;
830 DVLOG(1) << "Unknown safe browsing list " << list_name
;
831 return SB_THREAT_TYPE_SAFE
;
834 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
835 bool update_succeeded
) {
836 DCHECK_EQ(base::MessageLoop::current(),
837 safe_browsing_thread_
->message_loop());
838 GetDatabase()->UpdateFinished(update_succeeded
);
839 DCHECK(database_update_in_progress_
);
840 database_update_in_progress_
= false;
841 BrowserThread::PostTask(
842 BrowserThread::UI
, FROM_HERE
,
843 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished
,
844 this, update_succeeded
));
847 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
848 DCHECK_EQ(base::MessageLoop::current(),
849 safe_browsing_thread_
->message_loop());
850 DCHECK(closing_database_
);
852 // Because |closing_database_| is true, nothing on the IO thread will be
853 // accessing the database, so it's safe to delete and then NULL the pointer.
857 // Acquiring the lock here guarantees correct ordering between the resetting
858 // of |database_| above and of |closing_database_| below, which ensures there
859 // won't be a window during which the IO thread falsely believes the database
861 base::AutoLock
lock(database_lock_
);
862 closing_database_
= false;
865 void SafeBrowsingDatabaseManager::OnResetDatabase() {
866 DCHECK_EQ(base::MessageLoop::current(),
867 safe_browsing_thread_
->message_loop());
868 GetDatabase()->ResetDatabase();
871 void SafeBrowsingDatabaseManager::CacheHashResults(
872 const std::vector
<SBPrefix
>& prefixes
,
873 const std::vector
<SBFullHashResult
>& full_hashes
) {
874 DCHECK_EQ(base::MessageLoop::current(),
875 safe_browsing_thread_
->message_loop());
876 GetDatabase()->CacheHashResults(prefixes
, full_hashes
);
879 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
880 SafeBrowsingCheck
* check
,
881 const std::vector
<SBFullHashResult
>& full_hashes
) {
882 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
883 safe_browsing_util::ListType check_type
= check
->check_type
;
884 SBPrefix prefix
= check
->prefix_hits
[0];
885 GetHashRequests::iterator it
= gethash_requests_
.find(prefix
);
886 if (check
->prefix_hits
.size() > 1 || it
== gethash_requests_
.end()) {
887 const bool hit
= HandleOneCheck(check
, full_hashes
);
888 RecordGetHashCheckStatus(hit
, check_type
, full_hashes
);
892 // Call back all interested parties, noting if any has a hit.
893 GetHashRequestors
& requestors
= it
->second
;
895 for (GetHashRequestors::iterator r
= requestors
.begin();
896 r
!= requestors
.end(); ++r
) {
897 if (HandleOneCheck(*r
, full_hashes
))
900 RecordGetHashCheckStatus(hit
, check_type
, full_hashes
);
902 gethash_requests_
.erase(it
);
905 bool SafeBrowsingDatabaseManager::HandleOneCheck(
906 SafeBrowsingCheck
* check
,
907 const std::vector
<SBFullHashResult
>& full_hashes
) {
908 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
911 bool is_threat
= false;
913 for (size_t i
= 0; i
< check
->urls
.size(); ++i
) {
915 safe_browsing_util::GetUrlHashIndex(check
->urls
[i
], full_hashes
);
918 SBThreatType threat
=
919 GetThreatTypeFromListname(full_hashes
[index
].list_name
);
920 if (threat
!= SB_THREAT_TYPE_SAFE
&&
921 IsExpectedThreat(threat
, check
->expected_threats
)) {
922 check
->url_results
[i
] = threat
;
927 for (size_t i
= 0; i
< check
->full_hashes
.size(); ++i
) {
929 safe_browsing_util::GetHashIndex(check
->full_hashes
[i
], full_hashes
);
932 SBThreatType threat
=
933 GetThreatTypeFromListname(full_hashes
[index
].list_name
);
934 if (threat
!= SB_THREAT_TYPE_SAFE
&&
935 IsExpectedThreat(threat
, check
->expected_threats
)) {
936 check
->full_hash_results
[i
] = threat
;
941 SafeBrowsingCheckDone(check
);
945 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
946 SafeBrowsingCheck
* check
) {
947 DCHECK_EQ(base::MessageLoop::current(),
948 safe_browsing_thread_
->message_loop());
949 DCHECK(enable_download_protection_
);
951 std::vector
<SBPrefix
> prefix_hits
;
953 if (!database_
->ContainsDownloadUrl(check
->urls
, &prefix_hits
)) {
954 // Good, we don't have hash for this url prefix.
955 BrowserThread::PostTask(
956 BrowserThread::IO
, FROM_HERE
,
957 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone
, this,
962 check
->need_get_hash
= true;
963 check
->prefix_hits
.clear();
964 check
->prefix_hits
= prefix_hits
;
965 BrowserThread::PostTask(
966 BrowserThread::IO
, FROM_HERE
,
967 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
970 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
971 SafeBrowsingCheck
* check
) {
972 DCHECK_EQ(base::MessageLoop::current(),
973 safe_browsing_thread_
->message_loop());
975 std::vector
<SBPrefix
> prefixes
;
976 for (std::vector
<SBFullHash
>::iterator it
= check
->full_hashes
.begin();
977 it
!= check
->full_hashes
.end(); ++it
) {
978 prefixes
.push_back((*it
).prefix
);
980 database_
->ContainsExtensionPrefixes(prefixes
, &check
->prefix_hits
);
982 if (check
->prefix_hits
.empty()) {
983 // No matches for any extensions.
984 BrowserThread::PostTask(
987 base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone
, this,
990 // Some prefixes matched, we need to ask Google whether they're legit.
991 check
->need_get_hash
= true;
992 BrowserThread::PostTask(
995 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
999 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck
* check
) {
1000 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1006 DCHECK(checks_
.find(check
) != checks_
.end());
1007 if (check
->client
) {
1008 check
->client
->OnSafeBrowsingResult(*check
);
1009 check
->client
= NULL
;
1013 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
1014 SafeBrowsingCheck
* check
) {
1015 DCHECK(enable_download_protection_
);
1016 SafeBrowsingCheckDone(check
);
1019 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
1020 SafeBrowsingCheck
* check
) {
1021 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1027 VLOG(1) << "SafeBrowsingCheckDone";
1028 DCHECK(checks_
.find(check
) != checks_
.end());
1030 check
->client
->OnSafeBrowsingResult(*check
);
1031 checks_
.erase(check
);
1035 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1036 SafeBrowsingCheck
* check
,
1037 const base::Closure
& task
) {
1038 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1039 check
->timeout_factory_
.reset(
1040 new base::WeakPtrFactory
<SafeBrowsingDatabaseManager
>(this));
1041 checks_
.insert(check
);
1043 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, task
);
1045 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
1046 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback
,
1047 check
->timeout_factory_
->GetWeakPtr(), check
),