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 |