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/prerender/prerender_field_trial.h"
22 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
23 #include "chrome/browser/safe_browsing/download_protection_service.h"
24 #include "chrome/browser/safe_browsing/malware_details.h"
25 #include "chrome/browser/safe_browsing/protocol_manager.h"
26 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
27 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
28 #include "chrome/browser/safe_browsing/ui_manager.h"
29 #include "chrome/common/chrome_constants.h"
30 #include "chrome/common/chrome_paths.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "components/metrics/metrics_service.h"
33 #include "components/startup_metric_utils/startup_metric_utils.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/notification_service.h"
36 #include "url/url_constants.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(),
71 // Return the list id from the first result in |full_hashes| which matches
72 // |hash|, or INVALID if none match.
73 safe_browsing_util::ListType
GetHashThreatListType(
74 const SBFullHash
& hash
,
75 const std::vector
<SBFullHashResult
>& full_hashes
,
77 for (size_t i
= 0; i
< full_hashes
.size(); ++i
) {
78 if (SBFullHashEqual(hash
, full_hashes
[i
].hash
)) {
81 return static_cast<safe_browsing_util::ListType
>(full_hashes
[i
].list_id
);
84 return safe_browsing_util::INVALID
;
87 // Given a URL, compare all the possible host + path full hashes to the set of
88 // provided full hashes. Returns the list id of the a matching result from
89 // |full_hashes|, or INVALID if none match.
90 safe_browsing_util::ListType
GetUrlThreatListType(
92 const std::vector
<SBFullHashResult
>& full_hashes
,
94 if (full_hashes
.empty())
95 return safe_browsing_util::INVALID
;
97 std::vector
<std::string
> patterns
;
98 safe_browsing_util::GeneratePatternsToCheck(url
, &patterns
);
100 for (size_t i
= 0; i
< patterns
.size(); ++i
) {
101 safe_browsing_util::ListType threat
= GetHashThreatListType(
102 SBFullHashForString(patterns
[i
]), full_hashes
, index
);
103 if (threat
!= safe_browsing_util::INVALID
)
106 return safe_browsing_util::INVALID
;
109 SBThreatType
GetThreatTypeFromListType(safe_browsing_util::ListType list_type
) {
111 case safe_browsing_util::PHISH
:
112 return SB_THREAT_TYPE_URL_PHISHING
;
113 case safe_browsing_util::MALWARE
:
114 return SB_THREAT_TYPE_URL_MALWARE
;
115 case safe_browsing_util::BINURL
:
116 return SB_THREAT_TYPE_BINARY_MALWARE_URL
;
117 case safe_browsing_util::EXTENSIONBLACKLIST
:
118 return SB_THREAT_TYPE_EXTENSION
;
120 DVLOG(1) << "Unknown safe browsing list id " << list_type
;
121 return SB_THREAT_TYPE_SAFE
;
128 SBThreatType
SafeBrowsingDatabaseManager::GetHashThreatType(
129 const SBFullHash
& hash
,
130 const std::vector
<SBFullHashResult
>& full_hashes
) {
131 return GetThreatTypeFromListType(
132 GetHashThreatListType(hash
, full_hashes
, NULL
));
136 SBThreatType
SafeBrowsingDatabaseManager::GetUrlThreatType(
138 const std::vector
<SBFullHashResult
>& full_hashes
,
140 return GetThreatTypeFromListType(
141 GetUrlThreatListType(url
, full_hashes
, index
));
144 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
145 const std::vector
<GURL
>& urls
,
146 const std::vector
<SBFullHash
>& full_hashes
,
148 safe_browsing_util::ListType check_type
,
149 const std::vector
<SBThreatType
>& expected_threats
)
151 url_results(urls
.size(), SB_THREAT_TYPE_SAFE
),
152 url_metadata(urls
.size()),
153 full_hashes(full_hashes
),
154 full_hash_results(full_hashes
.size(), SB_THREAT_TYPE_SAFE
),
156 need_get_hash(false),
157 check_type(check_type
),
158 expected_threats(expected_threats
) {
159 DCHECK_EQ(urls
.empty(), !full_hashes
.empty())
160 << "Exactly one of urls and full_hashes must be set";
163 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
165 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
166 const SafeBrowsingCheck
& check
) {
167 DCHECK_EQ(check
.urls
.size(), check
.url_results
.size());
168 DCHECK_EQ(check
.full_hashes
.size(), check
.full_hash_results
.size());
169 if (!check
.urls
.empty()) {
170 DCHECK(check
.full_hashes
.empty());
171 switch (check
.check_type
) {
172 case safe_browsing_util::MALWARE
:
173 case safe_browsing_util::PHISH
:
174 DCHECK_EQ(1u, check
.urls
.size());
175 OnCheckBrowseUrlResult(
176 check
.urls
[0], check
.url_results
[0], check
.url_metadata
[0]);
178 case safe_browsing_util::BINURL
:
179 DCHECK_EQ(check
.urls
.size(), check
.url_results
.size());
180 OnCheckDownloadUrlResult(
182 *std::max_element(check
.url_results
.begin(),
183 check
.url_results
.end()));
188 } else if (!check
.full_hashes
.empty()) {
189 switch (check
.check_type
) {
190 case safe_browsing_util::EXTENSIONBLACKLIST
: {
191 std::set
<std::string
> unsafe_extension_ids
;
192 for (size_t i
= 0; i
< check
.full_hashes
.size(); ++i
) {
193 std::string extension_id
=
194 safe_browsing_util::SBFullHashToString(check
.full_hashes
[i
]);
195 if (check
.full_hash_results
[i
] == SB_THREAT_TYPE_EXTENSION
)
196 unsafe_extension_ids
.insert(extension_id
);
198 OnCheckExtensionsResult(unsafe_extension_ids
);
209 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
210 const scoped_refptr
<SafeBrowsingService
>& service
)
211 : sb_service_(service
),
214 enable_download_protection_(false),
215 enable_csd_whitelist_(false),
216 enable_download_whitelist_(false),
217 enable_extension_blacklist_(false),
218 enable_side_effect_free_whitelist_(false),
219 enable_ip_blacklist_(false),
220 update_in_progress_(false),
221 database_update_in_progress_(false),
222 closing_database_(false),
223 check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs
)) {
224 DCHECK(sb_service_
.get() != NULL
);
226 // Android only supports a subset of FULL_SAFE_BROWSING.
227 // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379>
228 #if !defined(OS_ANDROID)
229 CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
230 enable_download_protection_
=
231 !cmdline
->HasSwitch(switches::kSbDisableDownloadProtection
);
233 // We only download the csd-whitelist if client-side phishing detection is
235 enable_csd_whitelist_
=
236 !cmdline
->HasSwitch(switches::kDisableClientSidePhishingDetection
);
238 // TODO(noelutz): remove this boolean variable since it should always be true
239 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this
240 // list right now. This means that we need to be able to disable this list
241 // for the SafeBrowsing test to pass.
242 enable_download_whitelist_
= enable_csd_whitelist_
;
244 // TODO(kalman): there really shouldn't be a flag for this.
245 enable_extension_blacklist_
=
246 !cmdline
->HasSwitch(switches::kSbDisableExtensionBlacklist
);
248 enable_side_effect_free_whitelist_
=
249 prerender::IsSideEffectFreeWhitelistEnabled() &&
250 !cmdline
->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist
);
252 // The client-side IP blacklist feature is tightly integrated with client-side
253 // phishing protection for now.
254 enable_ip_blacklist_
= enable_csd_whitelist_
;
256 enum SideEffectFreeWhitelistStatus
{
257 SIDE_EFFECT_FREE_WHITELIST_ENABLED
,
258 SIDE_EFFECT_FREE_WHITELIST_DISABLED
,
259 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
262 SideEffectFreeWhitelistStatus side_effect_free_whitelist_status
=
263 enable_side_effect_free_whitelist_
? SIDE_EFFECT_FREE_WHITELIST_ENABLED
:
264 SIDE_EFFECT_FREE_WHITELIST_DISABLED
;
266 UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
267 side_effect_free_whitelist_status
,
268 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
);
272 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
273 // We should have already been shut down. If we're still enabled, then the
274 // database isn't going to be closed properly, which could lead to corruption.
278 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL
& url
) const {
279 return url
.SchemeIs(url::kFtpScheme
) ||
280 url
.SchemeIs(url::kHttpScheme
) ||
281 url
.SchemeIs(url::kHttpsScheme
);
284 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
285 const std::vector
<GURL
>& url_chain
,
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
288 if (!enabled_
|| !enable_download_protection_
)
291 // We need to check the database for url prefix, and later may fetch the url
292 // from the safebrowsing backends. These need to be asynchronous.
293 SafeBrowsingCheck
* check
=
294 new SafeBrowsingCheck(url_chain
,
295 std::vector
<SBFullHash
>(),
297 safe_browsing_util::BINURL
,
298 std::vector
<SBThreatType
>(1,
299 SB_THREAT_TYPE_BINARY_MALWARE_URL
));
300 StartSafeBrowsingCheck(
302 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread
, this,
307 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
308 const std::set
<std::string
>& extension_ids
,
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
312 if (!enabled_
|| !enable_extension_blacklist_
)
315 std::vector
<SBFullHash
> extension_id_hashes
;
316 std::transform(extension_ids
.begin(), extension_ids
.end(),
317 std::back_inserter(extension_id_hashes
),
318 safe_browsing_util::StringToSBFullHash
);
320 SafeBrowsingCheck
* check
= new SafeBrowsingCheck(
324 safe_browsing_util::EXTENSIONBLACKLIST
,
325 std::vector
<SBThreatType
>(1, SB_THREAT_TYPE_EXTENSION
));
327 StartSafeBrowsingCheck(
329 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread
,
335 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
340 if (!CanCheckUrl(url
))
343 return database_
->ContainsSideEffectFreeWhitelistUrl(url
);
346 bool SafeBrowsingDatabaseManager::MatchMalwareIP(
347 const std::string
& ip_address
) {
348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
349 if (!enabled_
|| !enable_ip_blacklist_
|| !MakeDatabaseAvailable()) {
350 return false; // Fail open.
352 return database_
->ContainsMalwareIP(ip_address
);
355 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL
& url
) {
356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
357 if (!enabled_
|| !enable_csd_whitelist_
|| !MakeDatabaseAvailable()) {
358 // There is something funky going on here -- for example, perhaps the user
359 // has not restarted since enabling metrics reporting, so we haven't
360 // enabled the csd whitelist yet. Just to be safe we return true in this
364 return database_
->ContainsCsdWhitelistedUrl(url
);
367 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL
& url
) {
368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
369 if (!enabled_
|| !enable_download_whitelist_
|| !MakeDatabaseAvailable()) {
372 return database_
->ContainsDownloadWhitelistedUrl(url
);
375 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
376 const std::string
& str
) {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
378 if (!enabled_
|| !enable_download_whitelist_
|| !MakeDatabaseAvailable()) {
381 return database_
->ContainsDownloadWhitelistedString(str
);
384 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
386 if (!enabled_
|| !MakeDatabaseAvailable()) {
389 return database_
->IsMalwareIPMatchKillSwitchOn();
392 bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
393 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
394 if (!enabled_
|| !MakeDatabaseAvailable()) {
397 return database_
->IsCsdWhitelistKillSwitchOn();
400 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL
& url
,
402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
406 if (!CanCheckUrl(url
))
409 std::vector
<SBThreatType
> expected_threats
;
410 expected_threats
.push_back(SB_THREAT_TYPE_URL_MALWARE
);
411 expected_threats
.push_back(SB_THREAT_TYPE_URL_PHISHING
);
413 const base::TimeTicks start
= base::TimeTicks::Now();
414 if (!MakeDatabaseAvailable()) {
415 QueuedCheck
queued_check(safe_browsing_util::MALWARE
, // or PHISH
420 queued_checks_
.push_back(queued_check
);
424 std::vector
<SBPrefix
> prefix_hits
;
425 std::vector
<SBFullHashResult
> cache_hits
;
428 database_
->ContainsBrowseUrl(url
, &prefix_hits
, &cache_hits
);
430 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start
);
433 return true; // URL is okay.
435 // Needs to be asynchronous, since we could be in the constructor of a
436 // ResourceDispatcherHost event handler which can't pause there.
437 SafeBrowsingCheck
* check
= new SafeBrowsingCheck(std::vector
<GURL
>(1, url
),
438 std::vector
<SBFullHash
>(),
440 safe_browsing_util::MALWARE
,
442 check
->need_get_hash
= cache_hits
.empty();
443 check
->prefix_hits
.swap(prefix_hits
);
444 check
->cache_hits
.swap(cache_hits
);
445 checks_
.insert(check
);
447 BrowserThread::PostTask(
448 BrowserThread::IO
, FROM_HERE
,
449 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
454 void SafeBrowsingDatabaseManager::CancelCheck(Client
* client
) {
455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
456 for (CurrentChecks::iterator i
= checks_
.begin(); i
!= checks_
.end(); ++i
) {
457 // We can't delete matching checks here because the db thread has a copy of
458 // the pointer. Instead, we simply NULL out the client, and when the db
459 // thread calls us back, we'll clean up the check.
460 if ((*i
)->client
== client
)
464 // Scan the queued clients store. Clients may be here if they requested a URL
465 // check before the database has finished loading.
466 for (std::deque
<QueuedCheck
>::iterator
it(queued_checks_
.begin());
467 it
!= queued_checks_
.end(); ) {
468 // In this case it's safe to delete matches entirely since nothing has a
470 if (it
->client
== client
)
471 it
= queued_checks_
.erase(it
);
477 void SafeBrowsingDatabaseManager::HandleGetHashResults(
478 SafeBrowsingCheck
* check
,
479 const std::vector
<SBFullHashResult
>& full_hashes
,
480 const base::TimeDelta
& cache_lifetime
) {
481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
486 // If the service has been shut down, |check| should have been deleted.
487 DCHECK(checks_
.find(check
) != checks_
.end());
489 // |start| is set before calling |GetFullHash()|, which should be
490 // the only path which gets to here.
491 DCHECK(!check
->start
.is_null());
492 UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
493 base::TimeTicks::Now() - check
->start
);
495 std::vector
<SBPrefix
> prefixes
= check
->prefix_hits
;
496 OnHandleGetHashResults(check
, full_hashes
); // 'check' is deleted here.
498 // Cache the GetHash results.
499 if (cache_lifetime
!= base::TimeDelta() && MakeDatabaseAvailable())
500 database_
->CacheHashResults(prefixes
, full_hashes
, cache_lifetime
);
503 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback
) {
504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
506 DCHECK(!callback
.is_null());
507 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
508 &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase
, this, callback
));
511 void SafeBrowsingDatabaseManager::AddChunks(
512 const std::string
& list
,
513 scoped_ptr
<ScopedVector
<SBChunkData
> > chunks
,
514 AddChunksCallback callback
) {
515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
517 DCHECK(!callback
.is_null());
518 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
519 &SafeBrowsingDatabaseManager::AddDatabaseChunks
, this, list
,
520 base::Passed(&chunks
), callback
));
523 void SafeBrowsingDatabaseManager::DeleteChunks(
524 scoped_ptr
<std::vector
<SBChunkDelete
> > chunk_deletes
) {
525 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
527 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
528 &SafeBrowsingDatabaseManager::DeleteDatabaseChunks
, this,
529 base::Passed(&chunk_deletes
)));
532 void SafeBrowsingDatabaseManager::UpdateStarted() {
533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
535 DCHECK(!update_in_progress_
);
536 update_in_progress_
= true;
539 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded
) {
540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
542 if (update_in_progress_
) {
543 update_in_progress_
= false;
544 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
,
545 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished
,
546 this, update_succeeded
));
550 void SafeBrowsingDatabaseManager::ResetDatabase() {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
553 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, base::Bind(
554 &SafeBrowsingDatabaseManager::OnResetDatabase
, this));
557 void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time
) {
558 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time
);
561 void SafeBrowsingDatabaseManager::StartOnIOThread() {
562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
566 DCHECK(!safe_browsing_thread_
.get());
567 safe_browsing_thread_
.reset(new base::Thread("Chrome_SafeBrowsingThread"));
568 if (!safe_browsing_thread_
->Start())
572 MakeDatabaseAvailable();
575 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown
) {
576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
584 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
585 bool update_succeeded
) {
586 content::NotificationService::current()->Notify(
587 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE
,
588 content::Source
<SafeBrowsingDatabaseManager
>(this),
589 content::Details
<bool>(&update_succeeded
));
592 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
593 const safe_browsing_util::ListType check_type
,
596 const std::vector
<SBThreatType
>& expected_threats
,
597 const base::TimeTicks
& start
)
598 : check_type(check_type
),
601 expected_threats(expected_threats
),
605 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
608 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
614 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
615 while (!queued_checks_
.empty()) {
616 QueuedCheck queued
= queued_checks_
.front();
618 SafeBrowsingCheck
sb_check(std::vector
<GURL
>(1, queued
.url
),
619 std::vector
<SBFullHash
>(),
622 queued
.expected_threats
);
623 queued
.client
->OnSafeBrowsingResult(sb_check
);
625 queued_checks_
.pop_front();
628 // Close the database. Cases to avoid:
629 // * If |closing_database_| is true, continuing will queue up a second
630 // request, |closing_database_| will be reset after handling the first
631 // request, and if any functions on the db thread recreate the database, we
632 // could start using it on the IO thread and then have the second request
633 // handler delete it out from under us.
634 // * If |database_| is NULL, then either no creation request is in flight, in
635 // which case we don't need to do anything, or one is in flight, in which
636 // case the database will be recreated before our deletion request is
637 // handled, and could be used on the IO thread in that time period, leading
638 // to the same problem as above.
639 // Checking DatabaseAvailable() avoids both of these.
640 if (DatabaseAvailable()) {
641 closing_database_
= true;
642 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
,
643 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase
, this));
646 // Flush the database thread. Any in-progress database check results will be
647 // ignored and cleaned up below.
649 // Note that to avoid leaking the database, we rely on the fact that no new
650 // tasks will be added to the db thread between the call above and this one.
651 // See comments on the declaration of |safe_browsing_thread_|.
653 // A ScopedAllowIO object is required to join the thread when calling Stop.
654 // See http://crbug.com/72696. Note that we call Stop() first to clear out
655 // any remaining tasks before clearing safe_browsing_thread_.
656 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join
;
657 safe_browsing_thread_
->Stop();
658 safe_browsing_thread_
.reset();
661 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
662 // We have to do this after the db thread returns because methods on it can
663 // have copies of these pointers, so deleting them might lead to accessing
665 for (CurrentChecks::iterator it
= checks_
.begin();
666 it
!= checks_
.end(); ++it
) {
667 SafeBrowsingCheck
* check
= *it
;
669 check
->client
->OnSafeBrowsingResult(*check
);
671 STLDeleteElements(&checks_
);
673 gethash_requests_
.clear();
676 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
677 base::AutoLock
lock(database_lock_
);
678 return !closing_database_
&& (database_
!= NULL
);
681 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
682 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
684 if (DatabaseAvailable())
686 safe_browsing_thread_
->message_loop()->PostTask(
688 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase
),
693 SafeBrowsingDatabase
* SafeBrowsingDatabaseManager::GetDatabase() {
694 DCHECK_EQ(base::MessageLoop::current(),
695 safe_browsing_thread_
->message_loop());
698 startup_metric_utils::ScopedSlowStartupUMA
699 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
700 const base::TimeTicks before
= base::TimeTicks::Now();
702 SafeBrowsingDatabase
* database
=
703 SafeBrowsingDatabase::Create(enable_download_protection_
,
704 enable_csd_whitelist_
,
705 enable_download_whitelist_
,
706 enable_extension_blacklist_
,
707 enable_side_effect_free_whitelist_
,
708 enable_ip_blacklist_
);
710 database
->Init(SafeBrowsingService::GetBaseFilename());
712 // Acquiring the lock here guarantees correct ordering between the writes to
713 // the new database object above, and the setting of |databse_| below.
714 base::AutoLock
lock(database_lock_
);
715 database_
= database
;
718 BrowserThread::PostTask(
719 BrowserThread::IO
, FROM_HERE
,
720 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete
, this));
722 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before
);
726 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck
* check
) {
727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
732 // If the service has been shut down, |check| should have been deleted.
733 DCHECK(checks_
.find(check
) != checks_
.end());
735 if (check
->client
&& check
->need_get_hash
) {
736 // We have a partial match so we need to query Google for the full hash.
737 // Clean up will happen in HandleGetHashResults.
739 // See if we have a GetHash request already in progress for this particular
740 // prefix. If so, we just append ourselves to the list of interested parties
741 // when the results arrive. We only do this for checks involving one prefix,
742 // since that is the common case (multiple prefixes will issue the request
744 if (check
->prefix_hits
.size() == 1) {
745 SBPrefix prefix
= check
->prefix_hits
[0];
746 GetHashRequests::iterator it
= gethash_requests_
.find(prefix
);
747 if (it
!= gethash_requests_
.end()) {
748 // There's already a request in progress.
749 it
->second
.push_back(check
);
753 // No request in progress, so we're the first for this prefix.
754 GetHashRequestors requestors
;
755 requestors
.push_back(check
);
756 gethash_requests_
[prefix
] = requestors
;
759 // Reset the start time so that we can measure the network time without the
761 check
->start
= base::TimeTicks::Now();
762 // Note: If |this| is deleted or stopped, the protocol_manager will
763 // be destroyed as well - hence it's OK to do unretained in this case.
764 bool is_download
= check
->check_type
== safe_browsing_util::BINURL
;
765 sb_service_
->protocol_manager()->GetFullHash(
767 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults
,
768 base::Unretained(this),
772 // We may have cached results for previous GetHash queries. Since
773 // this data comes from cache, don't histogram hits.
774 bool is_threat
= HandleOneCheck(check
, check
->cache_hits
);
775 // cache_hits should only contain hits for a fullhash we searched for, so if
776 // we got to this point it should always result in a threat match.
781 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
782 GetChunksCallback callback
) {
783 DCHECK_EQ(base::MessageLoop::current(),
784 safe_browsing_thread_
->message_loop());
786 bool database_error
= true;
787 std::vector
<SBListChunkRanges
> lists
;
788 DCHECK(!database_update_in_progress_
);
789 database_update_in_progress_
= true;
790 GetDatabase(); // This guarantees that |database_| is non-NULL.
791 if (database_
->UpdateStarted(&lists
)) {
792 database_error
= false;
794 database_
->UpdateFinished(false);
797 BrowserThread::PostTask(
798 BrowserThread::IO
, FROM_HERE
,
799 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase
,
800 this, lists
, database_error
, callback
));
803 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
804 const std::vector
<SBListChunkRanges
>& lists
, bool database_error
,
805 GetChunksCallback callback
) {
806 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
808 callback
.Run(lists
, database_error
);
811 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
812 AddChunksCallback callback
) {
813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
818 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
819 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
823 LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_
.size());
824 if (queued_checks_
.empty())
827 // If the database isn't already available, calling CheckUrl() in the loop
828 // below will add the check back to the queue, and we'll infinite-loop.
829 DCHECK(DatabaseAvailable());
830 while (!queued_checks_
.empty()) {
831 QueuedCheck check
= queued_checks_
.front();
832 DCHECK(!check
.start
.is_null());
833 LOCAL_HISTOGRAM_TIMES("SB.QueueDelay",
834 base::TimeTicks::Now() - check
.start
);
835 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
836 // client's handler function (because normally it's being directly called by
837 // the client). Since we're not the client, we have to convey this result.
838 if (check
.client
&& CheckBrowseUrl(check
.url
, check
.client
)) {
839 SafeBrowsingCheck
sb_check(std::vector
<GURL
>(1, check
.url
),
840 std::vector
<SBFullHash
>(),
843 check
.expected_threats
);
844 check
.client
->OnSafeBrowsingResult(sb_check
);
846 queued_checks_
.pop_front();
850 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
851 const std::string
& list_name
,
852 scoped_ptr
<ScopedVector
<SBChunkData
> > chunks
,
853 AddChunksCallback callback
) {
854 DCHECK_EQ(base::MessageLoop::current(),
855 safe_browsing_thread_
->message_loop());
857 GetDatabase()->InsertChunks(list_name
, chunks
->get());
858 BrowserThread::PostTask(
859 BrowserThread::IO
, FROM_HERE
,
860 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete
, this,
864 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
865 scoped_ptr
<std::vector
<SBChunkDelete
> > chunk_deletes
) {
866 DCHECK_EQ(base::MessageLoop::current(),
867 safe_browsing_thread_
->message_loop());
869 GetDatabase()->DeleteChunks(*chunk_deletes
);
872 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
873 bool update_succeeded
) {
874 DCHECK_EQ(base::MessageLoop::current(),
875 safe_browsing_thread_
->message_loop());
876 GetDatabase()->UpdateFinished(update_succeeded
);
877 DCHECK(database_update_in_progress_
);
878 database_update_in_progress_
= false;
879 BrowserThread::PostTask(
880 BrowserThread::UI
, FROM_HERE
,
881 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished
,
882 this, update_succeeded
));
885 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
886 DCHECK_EQ(base::MessageLoop::current(),
887 safe_browsing_thread_
->message_loop());
888 DCHECK(closing_database_
);
890 // Because |closing_database_| is true, nothing on the IO thread will be
891 // accessing the database, so it's safe to delete and then NULL the pointer.
895 // Acquiring the lock here guarantees correct ordering between the resetting
896 // of |database_| above and of |closing_database_| below, which ensures there
897 // won't be a window during which the IO thread falsely believes the database
899 base::AutoLock
lock(database_lock_
);
900 closing_database_
= false;
903 void SafeBrowsingDatabaseManager::OnResetDatabase() {
904 DCHECK_EQ(base::MessageLoop::current(),
905 safe_browsing_thread_
->message_loop());
906 GetDatabase()->ResetDatabase();
909 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
910 SafeBrowsingCheck
* check
,
911 const std::vector
<SBFullHashResult
>& full_hashes
) {
912 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
913 safe_browsing_util::ListType check_type
= check
->check_type
;
914 SBPrefix prefix
= check
->prefix_hits
[0];
915 GetHashRequests::iterator it
= gethash_requests_
.find(prefix
);
916 if (check
->prefix_hits
.size() > 1 || it
== gethash_requests_
.end()) {
917 const bool hit
= HandleOneCheck(check
, full_hashes
);
918 RecordGetHashCheckStatus(hit
, check_type
, full_hashes
);
922 // Call back all interested parties, noting if any has a hit.
923 GetHashRequestors
& requestors
= it
->second
;
925 for (GetHashRequestors::iterator r
= requestors
.begin();
926 r
!= requestors
.end(); ++r
) {
927 if (HandleOneCheck(*r
, full_hashes
))
930 RecordGetHashCheckStatus(hit
, check_type
, full_hashes
);
932 gethash_requests_
.erase(it
);
935 bool SafeBrowsingDatabaseManager::HandleOneCheck(
936 SafeBrowsingCheck
* check
,
937 const std::vector
<SBFullHashResult
>& full_hashes
) {
938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
941 bool is_threat
= false;
943 // TODO(shess): GetHashThreadListType() contains a loop,
944 // GetUrlThreatListType() a loop around that loop. Having another loop out
945 // here concerns me. It is likely that SAFE is an expected outcome, which
946 // means all of those loops run to completion. Refactoring this to generate a
947 // set of sorted items to compare in sequence would probably improve things.
949 // Additionally, the set of patterns generated from the urls is very similar
950 // to the patterns generated in ContainsBrowseUrl() and other database checks,
951 // which are called from this code. Refactoring that across the checks could
952 // interact well with batching the checks here.
954 for (size_t i
= 0; i
< check
->urls
.size(); ++i
) {
956 SBThreatType threat
=
957 GetUrlThreatType(check
->urls
[i
], full_hashes
, &threat_index
);
958 if (threat
!= SB_THREAT_TYPE_SAFE
&&
959 IsExpectedThreat(threat
, check
->expected_threats
)) {
960 check
->url_results
[i
] = threat
;
961 check
->url_metadata
[i
] = full_hashes
[threat_index
].metadata
;
966 for (size_t i
= 0; i
< check
->full_hashes
.size(); ++i
) {
967 SBThreatType threat
= GetHashThreatType(check
->full_hashes
[i
], full_hashes
);
968 if (threat
!= SB_THREAT_TYPE_SAFE
&&
969 IsExpectedThreat(threat
, check
->expected_threats
)) {
970 check
->full_hash_results
[i
] = threat
;
975 SafeBrowsingCheckDone(check
);
979 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
980 SafeBrowsingCheck
* check
) {
981 DCHECK_EQ(base::MessageLoop::current(),
982 safe_browsing_thread_
->message_loop());
983 DCHECK(enable_download_protection_
);
985 std::vector
<SBPrefix
> prefix_hits
;
987 if (!database_
->ContainsDownloadUrl(check
->urls
, &prefix_hits
)) {
988 // Good, we don't have hash for this url prefix.
989 BrowserThread::PostTask(
990 BrowserThread::IO
, FROM_HERE
,
991 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone
, this,
996 check
->need_get_hash
= true;
997 check
->prefix_hits
.clear();
998 check
->prefix_hits
= prefix_hits
;
999 BrowserThread::PostTask(
1000 BrowserThread::IO
, FROM_HERE
,
1001 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
1004 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
1005 SafeBrowsingCheck
* check
) {
1006 DCHECK_EQ(base::MessageLoop::current(),
1007 safe_browsing_thread_
->message_loop());
1009 std::vector
<SBPrefix
> prefixes
;
1010 for (std::vector
<SBFullHash
>::iterator it
= check
->full_hashes
.begin();
1011 it
!= check
->full_hashes
.end(); ++it
) {
1012 prefixes
.push_back((*it
).prefix
);
1014 database_
->ContainsExtensionPrefixes(prefixes
, &check
->prefix_hits
);
1016 if (check
->prefix_hits
.empty()) {
1017 // No matches for any extensions.
1018 BrowserThread::PostTask(
1021 base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone
, this,
1024 // Some prefixes matched, we need to ask Google whether they're legit.
1025 check
->need_get_hash
= true;
1026 BrowserThread::PostTask(
1029 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone
, this, check
));
1033 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck
* check
) {
1034 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1040 DCHECK(checks_
.find(check
) != checks_
.end());
1041 if (check
->client
) {
1042 check
->client
->OnSafeBrowsingResult(*check
);
1043 check
->client
= NULL
;
1047 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
1048 SafeBrowsingCheck
* check
) {
1049 DCHECK(enable_download_protection_
);
1050 SafeBrowsingCheckDone(check
);
1053 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
1054 SafeBrowsingCheck
* check
) {
1055 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1061 VLOG(1) << "SafeBrowsingCheckDone";
1062 DCHECK(checks_
.find(check
) != checks_
.end());
1064 check
->client
->OnSafeBrowsingResult(*check
);
1065 checks_
.erase(check
);
1069 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1070 SafeBrowsingCheck
* check
,
1071 const base::Closure
& task
) {
1072 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1073 check
->timeout_factory_
.reset(
1074 new base::WeakPtrFactory
<SafeBrowsingDatabaseManager
>(this));
1075 checks_
.insert(check
);
1077 safe_browsing_thread_
->message_loop()->PostTask(FROM_HERE
, task
);
1079 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
1080 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback
,
1081 check
->timeout_factory_
->GetWeakPtr(), check
),