diff options
Diffstat (limited to 'chrome/browser/safe_browsing/download_feedback_service.cc')
-rw-r--r-- | chrome/browser/safe_browsing/download_feedback_service.cc | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/chrome/browser/safe_browsing/download_feedback_service.cc b/chrome/browser/safe_browsing/download_feedback_service.cc new file mode 100644 index 0000000..3e5b378 --- /dev/null +++ b/chrome/browser/safe_browsing/download_feedback_service.cc @@ -0,0 +1,216 @@ +// Copyright 2013 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/safe_browsing/download_feedback_service.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util_proxy.h" +#include "base/metrics/histogram.h" +#include "base/supports_user_data.h" +#include "base/task_runner.h" +#include "chrome/browser/safe_browsing/download_feedback.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_version_info.h" +#include "content/public/browser/download_danger_type.h" +#include "content/public/browser/download_item.h" + +namespace safe_browsing { + +namespace { + +const void* kPingKey = &kPingKey; + +bool IsEnabled() { + CommandLine* cmdline = CommandLine::ForCurrentProcess(); + if (cmdline->HasSwitch(switches::kSbEnableDownloadFeedback)) + return true; + + chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); + if (channel == chrome::VersionInfo::CHANNEL_UNKNOWN || + channel == chrome::VersionInfo::CHANNEL_CANARY || + channel == chrome::VersionInfo::CHANNEL_DEV) + return true; + + return false; +} + +class DownloadFeedbackPings : public base::SupportsUserData::Data { + public: + DownloadFeedbackPings(const std::string& ping_request, + const std::string& ping_response); + + // Stores the ping data in the given |download|. + static void CreateForDownload(content::DownloadItem* download, + const std::string& ping_request, + const std::string& ping_response); + + // Returns the DownloadFeedbackPings object associated with |download|. May + // return NULL. + static DownloadFeedbackPings* FromDownload( + const content::DownloadItem& download); + + + const std::string& ping_request() const { + return ping_request_; + } + + const std::string& ping_response() const { + return ping_response_; + } + + private: + std::string ping_request_; + std::string ping_response_; +}; + +DownloadFeedbackPings::DownloadFeedbackPings(const std::string& ping_request, + const std::string& ping_response) + : ping_request_(ping_request), + ping_response_(ping_response) { +} + +// static +void DownloadFeedbackPings::CreateForDownload( + content::DownloadItem* download, + const std::string& ping_request, + const std::string& ping_response) { + DownloadFeedbackPings* pings = new DownloadFeedbackPings(ping_request, + ping_response); + download->SetUserData(kPingKey, pings); +} + +// static +DownloadFeedbackPings* DownloadFeedbackPings::FromDownload( + const content::DownloadItem& download) { + return static_cast<DownloadFeedbackPings*>(download.GetUserData(kPingKey)); +} + +} // namespace + +DownloadFeedbackService::DownloadFeedbackService( + net::URLRequestContextGetter* request_context_getter, + base::TaskRunner* file_task_runner) + : request_context_getter_(request_context_getter), + file_task_runner_(file_task_runner), + weak_ptr_factory_(this) { +} + +DownloadFeedbackService::~DownloadFeedbackService() { + DCHECK(CalledOnValidThread()); +} + +// static +void DownloadFeedbackService::MaybeStorePingsForDownload( + DownloadProtectionService::DownloadCheckResult result, + content::DownloadItem* download, + const std::string& ping, + const std::string& response) { + if (!IsEnabled() || !(result == DownloadProtectionService::UNCOMMON || + result == DownloadProtectionService::DANGEROUS_HOST)) + return; + UMA_HISTOGRAM_COUNTS("SBDownloadFeedback.SizeEligibleKB", + download->GetReceivedBytes() / 1024); + if (download->GetReceivedBytes() > DownloadFeedback::kMaxUploadSize) + return; + + DownloadFeedbackPings::CreateForDownload(download, ping, response); +} + +// static +bool DownloadFeedbackService::IsEnabledForDownload( + const content::DownloadItem& download) { + return !!DownloadFeedbackPings::FromDownload(download); +} + +// static +bool DownloadFeedbackService::GetPingsForDownloadForTesting( + const content::DownloadItem& download, + std::string* ping, + std::string* response) { + DownloadFeedbackPings* pings = DownloadFeedbackPings::FromDownload(download); + if (!pings) + return false; + + *ping = pings->ping_request(); + *response = pings->ping_response(); + return true; +} + +// static +void DownloadFeedbackService::RecordFeedbackButtonShown( + content::DownloadDangerType danger_type) { + UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Shown", + danger_type, + content::DOWNLOAD_DANGER_TYPE_MAX); +} + + +void DownloadFeedbackService::BeginFeedbackForDownload( + content::DownloadItem* download) { + DCHECK(CalledOnValidThread()); + + UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Activations", + download->GetDangerType(), + content::DOWNLOAD_DANGER_TYPE_MAX); + + DownloadFeedbackPings* pings = DownloadFeedbackPings::FromDownload(*download); + DCHECK(pings); + + download->StealDangerousDownload( + base::Bind(&DownloadFeedbackService::BeginFeedbackOrDeleteFile, + file_task_runner_, + weak_ptr_factory_.GetWeakPtr(), + pings->ping_request(), + pings->ping_response())); +} + +// static +void DownloadFeedbackService::BeginFeedbackOrDeleteFile( + const scoped_refptr<base::TaskRunner>& file_task_runner, + const base::WeakPtr<DownloadFeedbackService>& service, + const std::string& ping_request, + const std::string& ping_response, + const base::FilePath& path) { + if (service) { + service->BeginFeedback(ping_request, ping_response, path); + } else { + base::FileUtilProxy::Delete(file_task_runner, path, false, + base::FileUtilProxy::StatusCallback()); + } +} + +void DownloadFeedbackService::StartPendingFeedback() { + DCHECK(!active_feedback_.empty()); + active_feedback_.front()->Start(base::Bind( + &DownloadFeedbackService::FeedbackComplete, base::Unretained(this))); +} + +void DownloadFeedbackService::BeginFeedback( + const std::string& ping_request, + const std::string& ping_response, + const base::FilePath& path) { + DCHECK(CalledOnValidThread()); + DownloadFeedback* feedback = DownloadFeedback::Create( + request_context_getter_, file_task_runner_, path, + ping_request, ping_response); + active_feedback_.push_back(feedback); + UMA_HISTOGRAM_COUNTS_100("SBDownloadFeedback.ActiveFeedbacks", + active_feedback_.size()); + + if (active_feedback_.size() == 1) + StartPendingFeedback(); +} + +void DownloadFeedbackService::FeedbackComplete() { + DVLOG(1) << __FUNCTION__; + DCHECK(CalledOnValidThread()); + DCHECK(!active_feedback_.empty()); + active_feedback_.erase(active_feedback_.begin()); + if (!active_feedback_.empty()) + StartPendingFeedback(); +} + +} // namespace safe_browsing |