• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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