| Index: chrome/browser/safe_browsing/download_feedback_service.cc
|
| 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 0000000000000000000000000000000000000000..3e5b3788046ba99260bcab314f8ba3e0961cc13b
|
| --- /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
|
|
|