summaryrefslogtreecommitdiffstats
path: root/chrome/browser/safe_browsing/download_feedback_service.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/safe_browsing/download_feedback_service.cc')
-rw-r--r--chrome/browser/safe_browsing/download_feedback_service.cc216
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