// 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); }