| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| #include "chrome/browser/download/download_safe_browsing_client.h" |
| |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram.h" |
| #include "base/metrics/stats_counters.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/download/download_manager.h" |
| #include "chrome/browser/history/download_create_info.h" |
| #include "chrome/browser/safe_browsing/safe_browsing_util.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "content/browser/browser_thread.h" |
| #include "content/browser/renderer_host/resource_dispatcher_host.h" |
| |
| // TODO(lzheng): Get rid of the AddRef and Release after |
| // SafeBrowsingService::Client is changed to RefCountedThreadSafe<>. |
| |
| DownloadSBClient::DownloadSBClient(int32 download_id, |
| const std::vector<GURL>& url_chain, |
| const GURL& referrer_url) |
| : info_(NULL), |
| download_id_(download_id), |
| url_chain_(url_chain), |
| referrer_url_(referrer_url) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(!url_chain.empty()); |
| ResourceDispatcherHost* rdh = g_browser_process->resource_dispatcher_host(); |
| if (rdh) |
| sb_service_ = rdh->safe_browsing_service(); |
| } |
| |
| DownloadSBClient::~DownloadSBClient() {} |
| |
| void DownloadSBClient::CheckDownloadUrl(DownloadCreateInfo* info, |
| UrlDoneCallback* callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| // It is not allowed to call this method twice. |
| CHECK(!url_done_callback_.get() && !hash_done_callback_.get()); |
| CHECK(callback); |
| CHECK(info); |
| |
| info_ = info; |
| start_time_ = base::TimeTicks::Now(); |
| url_done_callback_.reset(callback); |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| NewRunnableMethod(this, |
| &DownloadSBClient::CheckDownloadUrlOnIOThread, |
| info->url_chain)); |
| } |
| |
| void DownloadSBClient::CheckDownloadHash(const std::string& hash, |
| HashDoneCallback* callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| // It is not allowed to call this method twice. |
| CHECK(!url_done_callback_.get() && !hash_done_callback_.get()); |
| CHECK(callback); |
| |
| start_time_ = base::TimeTicks::Now(); |
| hash_done_callback_.reset(callback); |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| NewRunnableMethod(this, |
| &DownloadSBClient::CheckDownloadHashOnIOThread, |
| hash)); |
| } |
| |
| void DownloadSBClient::CheckDownloadUrlOnIOThread( |
| const std::vector<GURL>& url_chain) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| |
| // Will be released in OnDownloadUrlCheckResult. |
| AddRef(); |
| if (sb_service_.get() && !sb_service_->CheckDownloadUrl(url_chain, this)) { |
| // Wait for SafeBrowsingService to call back OnDownloadUrlCheckResult. |
| return; |
| } |
| OnDownloadUrlCheckResult(url_chain, SafeBrowsingService::SAFE); |
| } |
| |
| // The callback interface for SafeBrowsingService::Client. |
| // Called when the result of checking a download URL is known. |
| void DownloadSBClient::OnDownloadUrlCheckResult( |
| const std::vector<GURL>& url_chain, |
| SafeBrowsingService::UrlCheckResult result) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| NewRunnableMethod(this, |
| &DownloadSBClient::SafeBrowsingCheckUrlDone, |
| result)); |
| Release(); |
| } |
| |
| void DownloadSBClient::CheckDownloadHashOnIOThread(const std::string& hash) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| // Will be released in OnDownloadUrlCheckResult. |
| AddRef(); |
| if (sb_service_.get() && !sb_service_->CheckDownloadHash(hash, this)) { |
| // Wait for SafeBrowsingService to call back OnDownloadUrlCheckResult. |
| return; |
| } |
| OnDownloadHashCheckResult(hash, SafeBrowsingService::SAFE); |
| } |
| |
| // The callback interface for SafeBrowsingService::Client. |
| // Called when the result of checking a download URL is known. |
| void DownloadSBClient::OnDownloadHashCheckResult( |
| const std::string& hash, SafeBrowsingService::UrlCheckResult result) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| NewRunnableMethod(this, |
| &DownloadSBClient::SafeBrowsingCheckHashDone, |
| result)); |
| Release(); |
| } |
| |
| void DownloadSBClient::SafeBrowsingCheckUrlDone( |
| SafeBrowsingService::UrlCheckResult result) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DVLOG(1) << "SafeBrowsingCheckUrlDone with result: " << result; |
| |
| bool is_dangerous = result != SafeBrowsingService::SAFE; |
| url_done_callback_->Run(info_, is_dangerous); |
| |
| if (sb_service_.get() && sb_service_->download_protection_enabled()) { |
| UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration", |
| base::TimeTicks::Now() - start_time_); |
| UpdateDownloadCheckStats(DOWNLOAD_URL_CHECKS_TOTAL); |
| if (is_dangerous) { |
| UpdateDownloadCheckStats(DOWNLOAD_URL_CHECKS_MALWARE); |
| ReportMalware(result); |
| } |
| } |
| } |
| |
| void DownloadSBClient::SafeBrowsingCheckHashDone( |
| SafeBrowsingService::UrlCheckResult result) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DVLOG(1) << "SafeBrowsingCheckHashDone with result: " << result; |
| |
| bool is_dangerous = result != SafeBrowsingService::SAFE; |
| hash_done_callback_->Run(download_id_, is_dangerous); |
| |
| if (sb_service_.get() && sb_service_->download_protection_enabled()) { |
| UMA_HISTOGRAM_TIMES("SB2.DownloadHashCheckDuration", |
| base::TimeTicks::Now() - start_time_); |
| UpdateDownloadCheckStats(DOWNLOAD_HASH_CHECKS_TOTAL); |
| if (is_dangerous) { |
| UpdateDownloadCheckStats(DOWNLOAD_HASH_CHECKS_MALWARE); |
| ReportMalware(result); |
| } |
| } |
| } |
| |
| void DownloadSBClient::ReportMalware( |
| SafeBrowsingService::UrlCheckResult result) { |
| std::string post_data; |
| for (size_t i = 0; i < url_chain_.size(); ++i) |
| post_data += url_chain_[i].spec() + "\n"; |
| |
| sb_service_->ReportSafeBrowsingHit(url_chain_.back(), // malicious_url |
| url_chain_.front(), // page_url |
| referrer_url_, |
| true, |
| result, |
| post_data); |
| } |
| |
| void DownloadSBClient::UpdateDownloadCheckStats(SBStatsType stat_type) { |
| UMA_HISTOGRAM_ENUMERATION("SB2.DownloadChecks", |
| stat_type, |
| DOWNLOAD_CHECKS_MAX); |
| } |