1 // Copyright (c) 2011 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/safe_browsing_service.h"
6
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/lazy_instance.h"
10 #include "base/path_service.h"
11 #include "base/stl_util-inl.h"
12 #include "base/string_util.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/metrics/metrics_service.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/safe_browsing/malware_details.h"
19 #include "chrome/browser/safe_browsing/protocol_manager.h"
20 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
21 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
22 #include "chrome/browser/tab_contents/tab_util.h"
23 #include "chrome/common/chrome_constants.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/common/url_constants.h"
28 #include "content/browser/browser_thread.h"
29 #include "content/browser/tab_contents/tab_contents.h"
30 #include "net/base/registry_controlled_domain.h"
31 #include "net/url_request/url_request_context_getter.h"
32
33 #if defined(OS_WIN)
34 #include "chrome/installer/util/browser_distribution.h"
35 #endif
36
37 namespace {
38
39 // The default URL prefix where browser fetches chunk updates, hashes,
40 // and reports safe browsing hits.
41 const char* const kSbDefaultInfoURLPrefix =
42 "http://safebrowsing.clients.google.com/safebrowsing";
43
44 // The default URL prefix where browser fetches MAC client key and reports
45 // malware details.
46 const char* const kSbDefaultMacKeyURLPrefix =
47 "https://sb-ssl.google.com/safebrowsing";
48
49 // When download url check takes this long, client's callback will be called
50 // without waiting for the result.
51 const int64 kDownloadUrlCheckTimeoutMs = 10000;
52
53 // Similar to kDownloadUrlCheckTimeoutMs, but for download hash checks.
54 const int64 kDownloadHashCheckTimeoutMs = 10000;
55
56 // TODO(lzheng): Replace this with Profile* ProfileManager::GetDefaultProfile().
GetDefaultProfile()57 Profile* GetDefaultProfile() {
58 FilePath user_data_dir;
59 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
60 ProfileManager* profile_manager = g_browser_process->profile_manager();
61 return profile_manager->GetDefaultProfile(user_data_dir);
62 }
63
64 // Records disposition information about the check. |hit| should be
65 // |true| if there were any prefix hits in |full_hashes|.
RecordGetHashCheckStatus(bool hit,bool is_download,const std::vector<SBFullHashResult> & full_hashes)66 void RecordGetHashCheckStatus(
67 bool hit,
68 bool is_download,
69 const std::vector<SBFullHashResult>& full_hashes) {
70 SafeBrowsingProtocolManager::ResultType result;
71 if (full_hashes.empty()) {
72 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
73 } else if (hit) {
74 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
75 } else {
76 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
77 }
78 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
79 }
80
81 } // namespace
82
83 // static
84 SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
85
86 // The default SafeBrowsingServiceFactory. Global, made a singleton so we
87 // don't leak it.
88 class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
89 public:
CreateSafeBrowsingService()90 virtual SafeBrowsingService* CreateSafeBrowsingService() {
91 return new SafeBrowsingService();
92 }
93
94 private:
95 friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
96
SafeBrowsingServiceFactoryImpl()97 SafeBrowsingServiceFactoryImpl() { }
98
99 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
100 };
101
102 static base::LazyInstance<SafeBrowsingServiceFactoryImpl>
103 g_safe_browsing_service_factory_impl(base::LINKER_INITIALIZED);
104
105 struct SafeBrowsingService::WhiteListedEntry {
106 int render_process_host_id;
107 int render_view_id;
108 std::string domain;
109 UrlCheckResult result;
110 };
111
UnsafeResource()112 SafeBrowsingService::UnsafeResource::UnsafeResource()
113 : resource_type(ResourceType::MAIN_FRAME),
114 threat_type(SAFE),
115 client(NULL),
116 render_process_host_id(-1),
117 render_view_id(-1) {
118 }
119
~UnsafeResource()120 SafeBrowsingService::UnsafeResource::~UnsafeResource() {}
121
SafeBrowsingCheck()122 SafeBrowsingService::SafeBrowsingCheck::SafeBrowsingCheck()
123 : full_hash(NULL),
124 client(NULL),
125 need_get_hash(false),
126 result(SAFE),
127 is_download(false),
128 timeout_task(NULL) {
129 }
130
~SafeBrowsingCheck()131 SafeBrowsingService::SafeBrowsingCheck::~SafeBrowsingCheck() {}
132
OnSafeBrowsingResult(const SafeBrowsingCheck & check)133 void SafeBrowsingService::Client::OnSafeBrowsingResult(
134 const SafeBrowsingCheck& check) {
135 if (!check.urls.empty()) {
136
137 DCHECK(!check.full_hash.get());
138 if (!check.is_download) {
139 DCHECK_EQ(1U, check.urls.size());
140 OnBrowseUrlCheckResult(check.urls[0], check.result);
141 } else {
142 OnDownloadUrlCheckResult(check.urls, check.result);
143 }
144 } else if (check.full_hash.get()) {
145 OnDownloadHashCheckResult(
146 safe_browsing_util::SBFullHashToString(*check.full_hash),
147 check.result);
148 } else {
149 NOTREACHED();
150 }
151 }
152
153 /* static */
CreateSafeBrowsingService()154 SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
155 if (!factory_)
156 factory_ = g_safe_browsing_service_factory_impl.Pointer();
157 return factory_->CreateSafeBrowsingService();
158 }
159
SafeBrowsingService()160 SafeBrowsingService::SafeBrowsingService()
161 : database_(NULL),
162 protocol_manager_(NULL),
163 enabled_(false),
164 enable_download_protection_(false),
165 enable_csd_whitelist_(false),
166 update_in_progress_(false),
167 database_update_in_progress_(false),
168 closing_database_(false),
169 download_urlcheck_timeout_ms_(kDownloadUrlCheckTimeoutMs),
170 download_hashcheck_timeout_ms_(kDownloadHashCheckTimeoutMs) {
171 }
172
Initialize()173 void SafeBrowsingService::Initialize() {
174 // Get the profile's preference for SafeBrowsing.
175 PrefService* pref_service = GetDefaultProfile()->GetPrefs();
176 if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled))
177 Start();
178 }
179
ShutDown()180 void SafeBrowsingService::ShutDown() {
181 BrowserThread::PostTask(
182 BrowserThread::IO, FROM_HERE,
183 NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown));
184 }
185
CanCheckUrl(const GURL & url) const186 bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
187 return url.SchemeIs(chrome::kFtpScheme) ||
188 url.SchemeIs(chrome::kHttpScheme) ||
189 url.SchemeIs(chrome::kHttpsScheme);
190 }
191
192 // Only report SafeBrowsing related stats when UMA is enabled and
193 // safe browsing is enabled.
CanReportStats() const194 bool SafeBrowsingService::CanReportStats() const {
195 const MetricsService* metrics = g_browser_process->metrics_service();
196 const PrefService* pref_service = GetDefaultProfile()->GetPrefs();
197 return metrics && metrics->reporting_active() &&
198 pref_service && pref_service->GetBoolean(prefs::kSafeBrowsingEnabled);
199 }
200
201 // Binhash verification is only enabled for UMA users for now.
DownloadBinHashNeeded() const202 bool SafeBrowsingService::DownloadBinHashNeeded() const {
203 return enable_download_protection_ && CanReportStats();
204 }
205
CheckDownloadUrl(const std::vector<GURL> & url_chain,Client * client)206 bool SafeBrowsingService::CheckDownloadUrl(const std::vector<GURL>& url_chain,
207 Client* client) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209 if (!enabled_ || !enable_download_protection_)
210 return true;
211
212 // We need to check the database for url prefix, and later may fetch the url
213 // from the safebrowsing backends. These need to be asynchronous.
214 SafeBrowsingCheck* check = new SafeBrowsingCheck();
215 check->urls = url_chain;
216 StartDownloadCheck(
217 check,
218 client,
219 NewRunnableMethod(this,
220 &SafeBrowsingService::CheckDownloadUrlOnSBThread,
221 check),
222 download_urlcheck_timeout_ms_);
223 return false;
224 }
225
CheckDownloadHash(const std::string & full_hash,Client * client)226 bool SafeBrowsingService::CheckDownloadHash(const std::string& full_hash,
227 Client* client) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
229 DCHECK(!full_hash.empty());
230 if (!enabled_ || !enable_download_protection_ || full_hash.empty())
231 return true;
232
233 // We need to check the database for url prefix, and later may fetch the url
234 // from the safebrowsing backends. These need to be asynchronous.
235 SafeBrowsingCheck* check = new SafeBrowsingCheck();
236 check->full_hash.reset(new SBFullHash);
237 safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get());
238 StartDownloadCheck(
239 check,
240 client,
241 NewRunnableMethod(this,
242 &SafeBrowsingService::CheckDownloadHashOnSBThread,
243 check),
244 download_hashcheck_timeout_ms_);
245 return false;
246 }
247
MatchCsdWhitelistUrl(const GURL & url)248 bool SafeBrowsingService::MatchCsdWhitelistUrl(const GURL& url) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
250 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
251 // There is something funky going on here -- for example, perhaps the user
252 // has not restarted since enabling metrics reporting, so we haven't
253 // enabled the csd whitelist yet. Just to be safe we return true in this
254 // case.
255 return true;
256 }
257 return database_->ContainsCsdWhitelistedUrl(url);
258 }
259
CheckBrowseUrl(const GURL & url,Client * client)260 bool SafeBrowsingService::CheckBrowseUrl(const GURL& url,
261 Client* client) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263 if (!enabled_)
264 return true;
265
266 if (!CanCheckUrl(url))
267 return true;
268
269 const base::TimeTicks start = base::TimeTicks::Now();
270 if (!MakeDatabaseAvailable()) {
271 QueuedCheck check;
272 check.client = client;
273 check.url = url;
274 check.start = start;
275 queued_checks_.push_back(check);
276 return false;
277 }
278
279 std::string list;
280 std::vector<SBPrefix> prefix_hits;
281 std::vector<SBFullHashResult> full_hits;
282 bool prefix_match =
283 database_->ContainsBrowseUrl(url, &list, &prefix_hits,
284 &full_hits,
285 protocol_manager_->last_update());
286
287 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
288
289 if (!prefix_match)
290 return true; // URL is okay.
291
292 // Needs to be asynchronous, since we could be in the constructor of a
293 // ResourceDispatcherHost event handler which can't pause there.
294 SafeBrowsingCheck* check = new SafeBrowsingCheck();
295 check->urls.push_back(url);
296 check->client = client;
297 check->result = SAFE;
298 check->is_download = false;
299 check->need_get_hash = full_hits.empty();
300 check->prefix_hits.swap(prefix_hits);
301 check->full_hits.swap(full_hits);
302 checks_.insert(check);
303
304 BrowserThread::PostTask(
305 BrowserThread::IO, FROM_HERE,
306 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
307
308 return false;
309 }
310
CancelCheck(Client * client)311 void SafeBrowsingService::CancelCheck(Client* client) {
312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
313 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
314 // We can't delete matching checks here because the db thread has a copy of
315 // the pointer. Instead, we simply NULL out the client, and when the db
316 // thread calls us back, we'll clean up the check.
317 if ((*i)->client == client)
318 (*i)->client = NULL;
319 }
320
321 // Scan the queued clients store. Clients may be here if they requested a URL
322 // check before the database has finished loading.
323 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
324 it != queued_checks_.end(); ) {
325 // In this case it's safe to delete matches entirely since nothing has a
326 // pointer to them.
327 if (it->client == client)
328 it = queued_checks_.erase(it);
329 else
330 ++it;
331 }
332 }
333
DisplayBlockingPage(const GURL & url,const GURL & original_url,const std::vector<GURL> & redirect_urls,ResourceType::Type resource_type,UrlCheckResult result,Client * client,int render_process_host_id,int render_view_id)334 void SafeBrowsingService::DisplayBlockingPage(
335 const GURL& url,
336 const GURL& original_url,
337 const std::vector<GURL>& redirect_urls,
338 ResourceType::Type resource_type,
339 UrlCheckResult result,
340 Client* client,
341 int render_process_host_id,
342 int render_view_id) {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344
345 // Check if the user has already ignored our warning for this render_view
346 // and domain.
347 for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
348 const WhiteListedEntry& entry = white_listed_entries_[i];
349 if (entry.render_process_host_id == render_process_host_id &&
350 entry.render_view_id == render_view_id &&
351 entry.result == result &&
352 entry.domain ==
353 net::RegistryControlledDomainService::GetDomainAndRegistry(url)) {
354 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
355 this, &SafeBrowsingService::NotifyClientBlockingComplete,
356 client, true));
357 return;
358 }
359 }
360
361 UnsafeResource resource;
362 resource.url = url;
363 resource.original_url = original_url;
364 resource.redirect_urls = redirect_urls;
365 resource.resource_type = resource_type;
366 resource.threat_type= result;
367 resource.client = client;
368 resource.render_process_host_id = render_process_host_id;
369 resource.render_view_id = render_view_id;
370
371 // The blocking page must be created from the UI thread.
372 BrowserThread::PostTask(
373 BrowserThread::UI, FROM_HERE,
374 NewRunnableMethod(
375 this, &SafeBrowsingService::DoDisplayBlockingPage, resource));
376 }
377
HandleGetHashResults(SafeBrowsingCheck * check,const std::vector<SBFullHashResult> & full_hashes,bool can_cache)378 void SafeBrowsingService::HandleGetHashResults(
379 SafeBrowsingCheck* check,
380 const std::vector<SBFullHashResult>& full_hashes,
381 bool can_cache) {
382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
383
384 if (!enabled_)
385 return;
386
387 // If the service has been shut down, |check| should have been deleted.
388 DCHECK(checks_.find(check) != checks_.end());
389
390 // |start| is set before calling |GetFullHash()|, which should be
391 // the only path which gets to here.
392 DCHECK(!check->start.is_null());
393 UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
394 base::TimeTicks::Now() - check->start);
395
396 std::vector<SBPrefix> prefixes = check->prefix_hits;
397 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
398
399 if (can_cache && MakeDatabaseAvailable()) {
400 // Cache the GetHash results in memory:
401 database_->CacheHashResults(prefixes, full_hashes);
402 }
403 }
404
HandleChunk(const std::string & list,SBChunkList * chunks)405 void SafeBrowsingService::HandleChunk(const std::string& list,
406 SBChunkList* chunks) {
407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
408 DCHECK(enabled_);
409 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
410 this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks));
411 }
412
HandleChunkDelete(std::vector<SBChunkDelete> * chunk_deletes)413 void SafeBrowsingService::HandleChunkDelete(
414 std::vector<SBChunkDelete>* chunk_deletes) {
415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
416 DCHECK(enabled_);
417 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
418 this, &SafeBrowsingService::DeleteChunks, chunk_deletes));
419 }
420
UpdateStarted()421 void SafeBrowsingService::UpdateStarted() {
422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
423 DCHECK(enabled_);
424 DCHECK(!update_in_progress_);
425 update_in_progress_ = true;
426 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
427 this, &SafeBrowsingService::GetAllChunksFromDatabase));
428 }
429
UpdateFinished(bool update_succeeded)430 void SafeBrowsingService::UpdateFinished(bool update_succeeded) {
431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
432 DCHECK(enabled_);
433 if (update_in_progress_) {
434 update_in_progress_ = false;
435 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
436 NewRunnableMethod(this,
437 &SafeBrowsingService::DatabaseUpdateFinished,
438 update_succeeded));
439 }
440 }
441
IsUpdateInProgress() const442 bool SafeBrowsingService::IsUpdateInProgress() const {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444 return update_in_progress_;
445 }
446
OnBlockingPageDone(const std::vector<UnsafeResource> & resources,bool proceed)447 void SafeBrowsingService::OnBlockingPageDone(
448 const std::vector<UnsafeResource>& resources,
449 bool proceed) {
450 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
451 iter != resources.end(); ++iter) {
452 const UnsafeResource& resource = *iter;
453 NotifyClientBlockingComplete(resource.client, proceed);
454
455 if (proceed) {
456 // Whitelist this domain and warning type for the given tab.
457 WhiteListedEntry entry;
458 entry.render_process_host_id = resource.render_process_host_id;
459 entry.render_view_id = resource.render_view_id;
460 entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry(
461 resource.url);
462 entry.result = resource.threat_type;
463 white_listed_entries_.push_back(entry);
464 }
465 }
466 }
467
OnNewMacKeys(const std::string & client_key,const std::string & wrapped_key)468 void SafeBrowsingService::OnNewMacKeys(const std::string& client_key,
469 const std::string& wrapped_key) {
470 PrefService* prefs = g_browser_process->local_state();
471 if (prefs) {
472 prefs->SetString(prefs::kSafeBrowsingClientKey, client_key);
473 prefs->SetString(prefs::kSafeBrowsingWrappedKey, wrapped_key);
474 }
475 }
476
OnEnable(bool enabled)477 void SafeBrowsingService::OnEnable(bool enabled) {
478 if (enabled)
479 Start();
480 else
481 ShutDown();
482 }
483
484 // static
RegisterPrefs(PrefService * prefs)485 void SafeBrowsingService::RegisterPrefs(PrefService* prefs) {
486 prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, "");
487 prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, "");
488 }
489
CloseDatabase()490 void SafeBrowsingService::CloseDatabase() {
491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
492
493 // Cases to avoid:
494 // * If |closing_database_| is true, continuing will queue up a second
495 // request, |closing_database_| will be reset after handling the first
496 // request, and if any functions on the db thread recreate the database, we
497 // could start using it on the IO thread and then have the second request
498 // handler delete it out from under us.
499 // * If |database_| is NULL, then either no creation request is in flight, in
500 // which case we don't need to do anything, or one is in flight, in which
501 // case the database will be recreated before our deletion request is
502 // handled, and could be used on the IO thread in that time period, leading
503 // to the same problem as above.
504 // * If |queued_checks_| is non-empty and |database_| is non-NULL, we're
505 // about to be called back (in DatabaseLoadComplete()). This will call
506 // CheckUrl(), which will want the database. Closing the database here
507 // would lead to an infinite loop in DatabaseLoadComplete(), and even if it
508 // didn't, it would be pointless since we'd just want to recreate.
509 //
510 // The first two cases above are handled by checking DatabaseAvailable().
511 if (!DatabaseAvailable() || !queued_checks_.empty())
512 return;
513
514 closing_database_ = true;
515 if (safe_browsing_thread_.get()) {
516 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
517 NewRunnableMethod(this, &SafeBrowsingService::OnCloseDatabase));
518 }
519 }
520
ResetDatabase()521 void SafeBrowsingService::ResetDatabase() {
522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
523 DCHECK(enabled_);
524 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
525 this, &SafeBrowsingService::OnResetDatabase));
526 }
527
LogPauseDelay(base::TimeDelta time)528 void SafeBrowsingService::LogPauseDelay(base::TimeDelta time) {
529 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
530 }
531
~SafeBrowsingService()532 SafeBrowsingService::~SafeBrowsingService() {
533 // We should have already been shut down. If we're still enabled, then the
534 // database isn't going to be closed properly, which could lead to corruption.
535 DCHECK(!enabled_);
536 }
537
OnIOInitialize(const std::string & client_key,const std::string & wrapped_key,net::URLRequestContextGetter * request_context_getter)538 void SafeBrowsingService::OnIOInitialize(
539 const std::string& client_key,
540 const std::string& wrapped_key,
541 net::URLRequestContextGetter* request_context_getter) {
542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
543 enabled_ = true;
544
545 MakeDatabaseAvailable();
546
547 // On Windows, get the safe browsing client name from the browser
548 // distribution classes in installer util. These classes don't yet have
549 // an analog on non-Windows builds so just keep the name specified here.
550 #if defined(OS_WIN)
551 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
552 std::string client_name(dist->GetSafeBrowsingName());
553 #else
554 #if defined(GOOGLE_CHROME_BUILD)
555 std::string client_name("googlechrome");
556 #else
557 std::string client_name("chromium");
558 #endif
559 #endif
560 CommandLine* cmdline = CommandLine::ForCurrentProcess();
561 bool disable_auto_update =
562 cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
563 cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
564 std::string info_url_prefix =
565 cmdline->HasSwitch(switches::kSbInfoURLPrefix) ?
566 cmdline->GetSwitchValueASCII(switches::kSbInfoURLPrefix) :
567 kSbDefaultInfoURLPrefix;
568 std::string mackey_url_prefix =
569 cmdline->HasSwitch(switches::kSbMacKeyURLPrefix) ?
570 cmdline->GetSwitchValueASCII(switches::kSbMacKeyURLPrefix) :
571 kSbDefaultMacKeyURLPrefix;
572
573 DCHECK(!protocol_manager_);
574 protocol_manager_ =
575 SafeBrowsingProtocolManager::Create(this,
576 client_name,
577 client_key,
578 wrapped_key,
579 request_context_getter,
580 info_url_prefix,
581 mackey_url_prefix,
582 disable_auto_update);
583
584 protocol_manager_->Initialize();
585 }
586
OnIOShutdown()587 void SafeBrowsingService::OnIOShutdown() {
588 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
589 if (!enabled_)
590 return;
591
592 enabled_ = false;
593
594 // This cancels all in-flight GetHash requests.
595 delete protocol_manager_;
596 protocol_manager_ = NULL;
597
598 // Delete queued checks, calling back any clients with 'SAFE'.
599 // If we don't do this here we may fail to close the database below.
600 while (!queued_checks_.empty()) {
601 QueuedCheck queued = queued_checks_.front();
602 if (queued.client) {
603 SafeBrowsingCheck sb_check;
604 sb_check.urls.push_back(queued.url);
605 sb_check.client = queued.client;
606 sb_check.result = SAFE;
607 queued.client->OnSafeBrowsingResult(sb_check);
608 }
609 queued_checks_.pop_front();
610 }
611
612 // Close the database. We don't simply DeleteSoon() because if a close is
613 // already pending, we'll double-free, and we don't set |database_| to NULL
614 // because if there is still anything running on the db thread, it could
615 // create a new database object (via GetDatabase()) that would then leak.
616 CloseDatabase();
617
618 // Flush the database thread. Any in-progress database check results will be
619 // ignored and cleaned up below.
620 //
621 // Note that to avoid leaking the database, we rely on the fact that no new
622 // tasks will be added to the db thread between the call above and this one.
623 // See comments on the declaration of |safe_browsing_thread_|.
624 {
625 // A ScopedAllowIO object is required to join the thread when calling Stop.
626 // See http://crbug.com/72696.
627 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
628 safe_browsing_thread_.reset();
629 }
630
631 // Delete pending checks, calling back any clients with 'SAFE'. We have
632 // to do this after the db thread returns because methods on it can have
633 // copies of these pointers, so deleting them might lead to accessing garbage.
634 for (CurrentChecks::iterator it = checks_.begin();
635 it != checks_.end(); ++it) {
636 SafeBrowsingCheck* check = *it;
637 if (check->client) {
638 check->result = SAFE;
639 check->client->OnSafeBrowsingResult(*check);
640 }
641 if (check->timeout_task)
642 check->timeout_task->Cancel();
643 }
644 STLDeleteElements(&checks_);
645
646 gethash_requests_.clear();
647 }
648
DatabaseAvailable() const649 bool SafeBrowsingService::DatabaseAvailable() const {
650 base::AutoLock lock(database_lock_);
651 return !closing_database_ && (database_ != NULL);
652 }
653
MakeDatabaseAvailable()654 bool SafeBrowsingService::MakeDatabaseAvailable() {
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
656 DCHECK(enabled_);
657 if (DatabaseAvailable())
658 return true;
659 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
660 NewRunnableMethod(this, &SafeBrowsingService::GetDatabase));
661 return false;
662 }
663
GetDatabase()664 SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
665 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
666 if (database_)
667 return database_;
668
669 FilePath path;
670 bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
671 DCHECK(result);
672 path = path.Append(chrome::kSafeBrowsingBaseFilename);
673
674 const base::TimeTicks before = base::TimeTicks::Now();
675
676 SafeBrowsingDatabase* database =
677 SafeBrowsingDatabase::Create(enable_download_protection_,
678 enable_csd_whitelist_);
679
680 database->Init(path);
681 {
682 // Acquiring the lock here guarantees correct ordering between the writes to
683 // the new database object above, and the setting of |databse_| below.
684 base::AutoLock lock(database_lock_);
685 database_ = database;
686 }
687
688 BrowserThread::PostTask(
689 BrowserThread::IO, FROM_HERE,
690 NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete));
691
692 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
693 return database_;
694 }
695
OnCheckDone(SafeBrowsingCheck * check)696 void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
698
699 if (!enabled_)
700 return;
701
702 // If the service has been shut down, |check| should have been deleted.
703 DCHECK(checks_.find(check) != checks_.end());
704
705 if (check->client && check->need_get_hash) {
706 // We have a partial match so we need to query Google for the full hash.
707 // Clean up will happen in HandleGetHashResults.
708
709 // See if we have a GetHash request already in progress for this particular
710 // prefix. If so, we just append ourselves to the list of interested parties
711 // when the results arrive. We only do this for checks involving one prefix,
712 // since that is the common case (multiple prefixes will issue the request
713 // as normal).
714 if (check->prefix_hits.size() == 1) {
715 SBPrefix prefix = check->prefix_hits[0];
716 GetHashRequests::iterator it = gethash_requests_.find(prefix);
717 if (it != gethash_requests_.end()) {
718 // There's already a request in progress.
719 it->second.push_back(check);
720 return;
721 }
722
723 // No request in progress, so we're the first for this prefix.
724 GetHashRequestors requestors;
725 requestors.push_back(check);
726 gethash_requests_[prefix] = requestors;
727 }
728
729 // Reset the start time so that we can measure the network time without the
730 // database time.
731 check->start = base::TimeTicks::Now();
732 protocol_manager_->GetFullHash(check, check->prefix_hits);
733 } else {
734 // We may have cached results for previous GetHash queries. Since
735 // this data comes from cache, don't histogram hits.
736 HandleOneCheck(check, check->full_hits);
737 }
738 }
739
GetAllChunksFromDatabase()740 void SafeBrowsingService::GetAllChunksFromDatabase() {
741 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
742
743 bool database_error = true;
744 std::vector<SBListChunkRanges> lists;
745 DCHECK(!database_update_in_progress_);
746 database_update_in_progress_ = true;
747 GetDatabase(); // This guarantees that |database_| is non-NULL.
748 if (database_->UpdateStarted(&lists)) {
749 database_error = false;
750 } else {
751 database_->UpdateFinished(false);
752 }
753
754 BrowserThread::PostTask(
755 BrowserThread::IO, FROM_HERE,
756 NewRunnableMethod(
757 this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists,
758 database_error));
759 }
760
OnGetAllChunksFromDatabase(const std::vector<SBListChunkRanges> & lists,bool database_error)761 void SafeBrowsingService::OnGetAllChunksFromDatabase(
762 const std::vector<SBListChunkRanges>& lists, bool database_error) {
763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
764 if (enabled_)
765 protocol_manager_->OnGetChunksComplete(lists, database_error);
766 }
767
OnChunkInserted()768 void SafeBrowsingService::OnChunkInserted() {
769 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
770 if (enabled_)
771 protocol_manager_->OnChunkInserted();
772 }
773
DatabaseLoadComplete()774 void SafeBrowsingService::DatabaseLoadComplete() {
775 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
776 if (!enabled_)
777 return;
778
779 HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
780 if (queued_checks_.empty())
781 return;
782
783 // If the database isn't already available, calling CheckUrl() in the loop
784 // below will add the check back to the queue, and we'll infinite-loop.
785 DCHECK(DatabaseAvailable());
786 while (!queued_checks_.empty()) {
787 QueuedCheck check = queued_checks_.front();
788 DCHECK(!check.start.is_null());
789 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
790 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
791 // client's handler function (because normally it's being directly called by
792 // the client). Since we're not the client, we have to convey this result.
793 if (check.client && CheckBrowseUrl(check.url, check.client)) {
794 SafeBrowsingCheck sb_check;
795 sb_check.urls.push_back(check.url);
796 sb_check.client = check.client;
797 sb_check.result = SAFE;
798 check.client->OnSafeBrowsingResult(sb_check);
799 }
800 queued_checks_.pop_front();
801 }
802 }
803
HandleChunkForDatabase(const std::string & list_name,SBChunkList * chunks)804 void SafeBrowsingService::HandleChunkForDatabase(
805 const std::string& list_name, SBChunkList* chunks) {
806 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
807 if (chunks) {
808 GetDatabase()->InsertChunks(list_name, *chunks);
809 delete chunks;
810 }
811 BrowserThread::PostTask(
812 BrowserThread::IO, FROM_HERE,
813 NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted));
814 }
815
DeleteChunks(std::vector<SBChunkDelete> * chunk_deletes)816 void SafeBrowsingService::DeleteChunks(
817 std::vector<SBChunkDelete>* chunk_deletes) {
818 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
819 if (chunk_deletes) {
820 GetDatabase()->DeleteChunks(*chunk_deletes);
821 delete chunk_deletes;
822 }
823 }
824
GetResultFromListname(const std::string & list_name)825 SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
826 const std::string& list_name) {
827 if (safe_browsing_util::IsPhishingList(list_name)) {
828 return URL_PHISHING;
829 }
830
831 if (safe_browsing_util::IsMalwareList(list_name)) {
832 return URL_MALWARE;
833 }
834
835 if (safe_browsing_util::IsBadbinurlList(list_name)) {
836 return BINARY_MALWARE_URL;
837 }
838
839 if (safe_browsing_util::IsBadbinhashList(list_name)) {
840 return BINARY_MALWARE_HASH;
841 }
842
843 DVLOG(1) << "Unknown safe browsing list " << list_name;
844 return SAFE;
845 }
846
NotifyClientBlockingComplete(Client * client,bool proceed)847 void SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
848 bool proceed) {
849 client->OnBlockingPageComplete(proceed);
850 }
851
DatabaseUpdateFinished(bool update_succeeded)852 void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
853 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
854 GetDatabase()->UpdateFinished(update_succeeded);
855 DCHECK(database_update_in_progress_);
856 database_update_in_progress_ = false;
857 }
858
Start()859 void SafeBrowsingService::Start() {
860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
861 DCHECK(!safe_browsing_thread_.get());
862 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
863 if (!safe_browsing_thread_->Start())
864 return;
865
866 // Retrieve client MAC keys.
867 PrefService* local_state = g_browser_process->local_state();
868 DCHECK(local_state);
869 std::string client_key, wrapped_key;
870 if (local_state) {
871 client_key =
872 local_state->GetString(prefs::kSafeBrowsingClientKey);
873 wrapped_key =
874 local_state->GetString(prefs::kSafeBrowsingWrappedKey);
875 }
876
877 // We will issue network fetches using the default profile's request context.
878 scoped_refptr<net::URLRequestContextGetter> request_context_getter(
879 GetDefaultProfile()->GetRequestContext());
880
881 CommandLine* cmdline = CommandLine::ForCurrentProcess();
882 enable_download_protection_ =
883 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
884
885 // We only download the csd-whitelist if client-side phishing detection is
886 // enabled and if the user has opted in with stats collection. Note: we
887 // cannot check whether the metrics_service() object is created because it
888 // may be initialized after this method is called.
889 #ifdef OS_CHROMEOS
890 // Client-side detection is disabled on ChromeOS for now, so don't bother
891 // downloading the whitelist.
892 enable_csd_whitelist_ = false;
893 #else
894 enable_csd_whitelist_ =
895 (!cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection) &&
896 local_state && local_state->GetBoolean(prefs::kMetricsReportingEnabled));
897 #endif
898
899 BrowserThread::PostTask(
900 BrowserThread::IO, FROM_HERE,
901 NewRunnableMethod(
902 this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key,
903 request_context_getter));
904 }
905
OnCloseDatabase()906 void SafeBrowsingService::OnCloseDatabase() {
907 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
908 DCHECK(closing_database_);
909
910 // Because |closing_database_| is true, nothing on the IO thread will be
911 // accessing the database, so it's safe to delete and then NULL the pointer.
912 delete database_;
913 database_ = NULL;
914
915 // Acquiring the lock here guarantees correct ordering between the resetting
916 // of |database_| above and of |closing_database_| below, which ensures there
917 // won't be a window during which the IO thread falsely believes the database
918 // is available.
919 base::AutoLock lock(database_lock_);
920 closing_database_ = false;
921 }
922
OnResetDatabase()923 void SafeBrowsingService::OnResetDatabase() {
924 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
925 GetDatabase()->ResetDatabase();
926 }
927
CacheHashResults(const std::vector<SBPrefix> & prefixes,const std::vector<SBFullHashResult> & full_hashes)928 void SafeBrowsingService::CacheHashResults(
929 const std::vector<SBPrefix>& prefixes,
930 const std::vector<SBFullHashResult>& full_hashes) {
931 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
932 GetDatabase()->CacheHashResults(prefixes, full_hashes);
933 }
934
OnHandleGetHashResults(SafeBrowsingCheck * check,const std::vector<SBFullHashResult> & full_hashes)935 void SafeBrowsingService::OnHandleGetHashResults(
936 SafeBrowsingCheck* check,
937 const std::vector<SBFullHashResult>& full_hashes) {
938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
939 bool is_download = check->is_download;
940 SBPrefix prefix = check->prefix_hits[0];
941 GetHashRequests::iterator it = gethash_requests_.find(prefix);
942 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
943 const bool hit = HandleOneCheck(check, full_hashes);
944 RecordGetHashCheckStatus(hit, is_download, full_hashes);
945 return;
946 }
947
948 // Call back all interested parties, noting if any has a hit.
949 GetHashRequestors& requestors = it->second;
950 bool hit = false;
951 for (GetHashRequestors::iterator r = requestors.begin();
952 r != requestors.end(); ++r) {
953 if (HandleOneCheck(*r, full_hashes))
954 hit = true;
955 }
956 RecordGetHashCheckStatus(hit, is_download, full_hashes);
957
958 gethash_requests_.erase(it);
959 }
960
HandleOneCheck(SafeBrowsingCheck * check,const std::vector<SBFullHashResult> & full_hashes)961 bool SafeBrowsingService::HandleOneCheck(
962 SafeBrowsingCheck* check,
963 const std::vector<SBFullHashResult>& full_hashes) {
964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
965 DCHECK(check);
966
967 // Always calculate the index, for recording hits.
968 int index = -1;
969 if (!check->urls.empty()) {
970 for (size_t i = 0; i < check->urls.size(); ++i) {
971 index = safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
972 if (index != -1)
973 break;
974 }
975 } else {
976 index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes);
977 }
978
979 // |client| is NULL if the request was cancelled.
980 if (check->client) {
981 check->result = SAFE;
982 if (index != -1)
983 check->result = GetResultFromListname(full_hashes[index].list_name);
984 }
985 SafeBrowsingCheckDone(check);
986 return (index != -1);
987 }
988
DoDisplayBlockingPage(const UnsafeResource & resource)989 void SafeBrowsingService::DoDisplayBlockingPage(
990 const UnsafeResource& resource) {
991 // The tab might have been closed.
992 TabContents* wc =
993 tab_util::GetTabContentsByID(resource.render_process_host_id,
994 resource.render_view_id);
995
996 if (!wc) {
997 // The tab is gone and we did not have a chance at showing the interstitial.
998 // Just act as "Don't Proceed" was chosen.
999 std::vector<UnsafeResource> resources;
1000 resources.push_back(resource);
1001 BrowserThread::PostTask(
1002 BrowserThread::IO, FROM_HERE,
1003 NewRunnableMethod(
1004 this, &SafeBrowsingService::OnBlockingPageDone, resources, false));
1005 return;
1006 }
1007
1008 if (resource.threat_type != SafeBrowsingService::SAFE && CanReportStats()) {
1009 GURL page_url = wc->GetURL();
1010 GURL referrer_url;
1011 NavigationEntry* entry = wc->controller().GetActiveEntry();
1012 if (entry)
1013 referrer_url = entry->referrer();
1014 bool is_subresource = resource.resource_type != ResourceType::MAIN_FRAME;
1015
1016 // When the malicious url is on the main frame, and resource.original_url
1017 // is not the same as the resource.url, that means we have a redirect from
1018 // resource.original_url to resource.url.
1019 // Also, at this point, page_url points to the _previous_ page that we
1020 // were on. We replace page_url with resource.original_url and referrer
1021 // with page_url.
1022 if (!is_subresource &&
1023 !resource.original_url.is_empty() &&
1024 resource.original_url != resource.url) {
1025 referrer_url = page_url;
1026 page_url = resource.original_url;
1027 }
1028 ReportSafeBrowsingHit(resource.url, page_url, referrer_url, is_subresource,
1029 resource.threat_type, std::string() /* post_data */);
1030 }
1031
1032 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
1033 }
1034
1035 // A safebrowsing hit is sent after a blocking page for malware/phishing
1036 // or after the warning dialog for download urls, only for UMA users.
ReportSafeBrowsingHit(const GURL & malicious_url,const GURL & page_url,const GURL & referrer_url,bool is_subresource,SafeBrowsingService::UrlCheckResult threat_type,const std::string & post_data)1037 void SafeBrowsingService::ReportSafeBrowsingHit(
1038 const GURL& malicious_url,
1039 const GURL& page_url,
1040 const GURL& referrer_url,
1041 bool is_subresource,
1042 SafeBrowsingService::UrlCheckResult threat_type,
1043 const std::string& post_data) {
1044 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1045 if (!CanReportStats())
1046 return;
1047
1048 BrowserThread::PostTask(
1049 BrowserThread::IO, FROM_HERE,
1050 NewRunnableMethod(
1051 this,
1052 &SafeBrowsingService::ReportSafeBrowsingHitOnIOThread,
1053 malicious_url,
1054 page_url,
1055 referrer_url,
1056 is_subresource,
1057 threat_type,
1058 post_data));
1059 }
1060
ReportSafeBrowsingHitOnIOThread(const GURL & malicious_url,const GURL & page_url,const GURL & referrer_url,bool is_subresource,SafeBrowsingService::UrlCheckResult threat_type,const std::string & post_data)1061 void SafeBrowsingService::ReportSafeBrowsingHitOnIOThread(
1062 const GURL& malicious_url,
1063 const GURL& page_url,
1064 const GURL& referrer_url,
1065 bool is_subresource,
1066 SafeBrowsingService::UrlCheckResult threat_type,
1067 const std::string& post_data) {
1068 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1069 if (!enabled_)
1070 return;
1071
1072 DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
1073 << " " << referrer_url << " " << is_subresource << " "
1074 << threat_type;
1075 protocol_manager_->ReportSafeBrowsingHit(malicious_url, page_url,
1076 referrer_url, is_subresource,
1077 threat_type, post_data);
1078 }
1079
1080 // If the user had opted-in to send MalwareDetails, this gets called
1081 // when the report is ready.
SendSerializedMalwareDetails(const std::string & serialized)1082 void SafeBrowsingService::SendSerializedMalwareDetails(
1083 const std::string& serialized) {
1084 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1085 if (!serialized.empty()) {
1086 DVLOG(1) << "Sending serialized malware details.";
1087 protocol_manager_->ReportMalwareDetails(serialized);
1088 }
1089 }
1090
CheckDownloadHashOnSBThread(SafeBrowsingCheck * check)1091 void SafeBrowsingService::CheckDownloadHashOnSBThread(
1092 SafeBrowsingCheck* check) {
1093 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
1094 DCHECK(enable_download_protection_);
1095
1096 if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) {
1097 // Good, we don't have hash for this url prefix.
1098 check->result = SAFE;
1099 BrowserThread::PostTask(
1100 BrowserThread::IO, FROM_HERE,
1101 NewRunnableMethod(this,
1102 &SafeBrowsingService::CheckDownloadHashDone,
1103 check));
1104 return;
1105 }
1106
1107 check->need_get_hash = true;
1108 check->prefix_hits.push_back(check->full_hash->prefix);
1109 BrowserThread::PostTask(
1110 BrowserThread::IO, FROM_HERE,
1111 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
1112 }
1113
CheckDownloadUrlOnSBThread(SafeBrowsingCheck * check)1114 void SafeBrowsingService::CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check) {
1115 DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
1116 DCHECK(enable_download_protection_);
1117
1118 std::vector<SBPrefix> prefix_hits;
1119
1120 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
1121 // Good, we don't have hash for this url prefix.
1122 check->result = SAFE;
1123 BrowserThread::PostTask(
1124 BrowserThread::IO, FROM_HERE,
1125 NewRunnableMethod(this,
1126 &SafeBrowsingService::CheckDownloadUrlDone,
1127 check));
1128 return;
1129 }
1130
1131 check->need_get_hash = true;
1132 check->prefix_hits.clear();
1133 check->prefix_hits = prefix_hits;
1134 BrowserThread::PostTask(
1135 BrowserThread::IO, FROM_HERE,
1136 NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
1137 }
1138
TimeoutCallback(SafeBrowsingCheck * check)1139 void SafeBrowsingService::TimeoutCallback(SafeBrowsingCheck* check) {
1140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1141 DCHECK(check);
1142
1143 if (!enabled_)
1144 return;
1145
1146 DCHECK(checks_.find(check) != checks_.end());
1147 DCHECK_EQ(check->result, SAFE);
1148 if (check->client) {
1149 check->client->OnSafeBrowsingResult(*check);
1150 check->client = NULL;
1151 }
1152 check->timeout_task = NULL;
1153 }
1154
CheckDownloadUrlDone(SafeBrowsingCheck * check)1155 void SafeBrowsingService::CheckDownloadUrlDone(SafeBrowsingCheck* check) {
1156 DCHECK(enable_download_protection_);
1157 SafeBrowsingCheckDone(check);
1158 }
1159
CheckDownloadHashDone(SafeBrowsingCheck * check)1160 void SafeBrowsingService::CheckDownloadHashDone(SafeBrowsingCheck* check) {
1161 DCHECK(enable_download_protection_);
1162 SafeBrowsingCheckDone(check);
1163 }
1164
SafeBrowsingCheckDone(SafeBrowsingCheck * check)1165 void SafeBrowsingService::SafeBrowsingCheckDone(SafeBrowsingCheck* check) {
1166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1167 DCHECK(check);
1168
1169 if (!enabled_)
1170 return;
1171
1172 VLOG(1) << "SafeBrowsingCheckDone: " << check->result;
1173 DCHECK(checks_.find(check) != checks_.end());
1174 if (check->client)
1175 check->client->OnSafeBrowsingResult(*check);
1176 if (check->timeout_task)
1177 check->timeout_task->Cancel();
1178 checks_.erase(check);
1179 delete check;
1180 }
1181
StartDownloadCheck(SafeBrowsingCheck * check,Client * client,CancelableTask * task,int64 timeout_ms)1182 void SafeBrowsingService::StartDownloadCheck(SafeBrowsingCheck* check,
1183 Client* client,
1184 CancelableTask* task,
1185 int64 timeout_ms) {
1186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1187 check->client = client;
1188 check->result = SAFE;
1189 check->is_download = true;
1190 check->timeout_task =
1191 NewRunnableMethod(this, &SafeBrowsingService::TimeoutCallback, check);
1192 checks_.insert(check);
1193
1194 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
1195
1196 MessageLoop::current()->PostDelayedTask(
1197 FROM_HERE, check->timeout_task, timeout_ms);
1198 }
1199