Index: chrome/browser/safe_browsing/download_feedback.cc |
diff --git a/chrome/browser/safe_browsing/download_feedback.cc b/chrome/browser/safe_browsing/download_feedback.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fef426ad7aeb686670e087af2e9812f79a2ac217 |
--- /dev/null |
+++ b/chrome/browser/safe_browsing/download_feedback.cc |
@@ -0,0 +1,226 @@ |
+// 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.h" |
+ |
+#include "base/bind.h" |
+#include "base/command_line.h" |
+#include "base/files/file_util_proxy.h" |
+#include "base/metrics/histogram.h" |
+#include "base/task_runner.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "chrome/common/safe_browsing/csd.pb.h" |
+#include "net/base/net_errors.h" |
+ |
+namespace safe_browsing { |
+ |
+namespace { |
+ |
+// The default URL where browser sends download feedback requests. |
+const char kSbDefaultFeedbackURL[] = |
+ "https://safebrowsing.google.com/safebrowsing/uploads/chrome"; |
+ |
+// This enum is used by histograms. Do not change the ordering or remove items. |
+enum UploadResultType { |
+ UPLOAD_SUCCESS, |
+ UPLOAD_CANCELLED, |
+ UPLOAD_METADATA_NET_ERROR, |
+ UPLOAD_METADATA_RESPONSE_ERROR, |
+ UPLOAD_FILE_NET_ERROR, |
+ UPLOAD_FILE_RESPONSE_ERROR, |
+ UPLOAD_COMPLETE_RESPONSE_ERROR, |
+ // Memory space for histograms is determined by the max. |
+ // ALWAYS ADD NEW VALUES BEFORE THIS ONE. |
+ UPLOAD_RESULT_MAX |
+}; |
+ |
+// Handles the uploading of a single downloaded binary to the safebrowsing |
+// download feedback service. |
+class DownloadFeedbackImpl : public DownloadFeedback { |
+ public: |
+ DownloadFeedbackImpl(net::URLRequestContextGetter* request_context_getter, |
+ base::TaskRunner* file_task_runner, |
+ const base::FilePath& file_path, |
+ const std::string& ping_request, |
+ const std::string& ping_response); |
+ virtual ~DownloadFeedbackImpl(); |
+ |
+ virtual void Start(const base::Closure& finish_callback) OVERRIDE; |
+ |
+ virtual const std::string& GetPingRequestForTesting() const OVERRIDE { |
+ return ping_request_; |
+ } |
+ |
+ virtual const std::string& GetPingResponseForTesting() const OVERRIDE { |
+ return ping_response_; |
+ } |
+ |
+ private: |
+ // Callback for TwoPhaseUploader completion. Relays the result to the |
+ // |finish_callback|. |
+ void FinishedUpload(base::Closure finish_callback, |
+ TwoPhaseUploader::State state, |
+ int net_error, |
+ int response_code, |
+ const std::string& response); |
+ |
+ void RecordUploadResult(UploadResultType result); |
+ |
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
+ scoped_refptr<base::TaskRunner> file_task_runner_; |
+ const base::FilePath file_path_; |
+ int64 file_size_; |
+ |
+ // The safebrowsing request and response of checking that this binary is |
+ // unsafe. |
+ std::string ping_request_; |
+ std::string ping_response_; |
+ |
+ scoped_ptr<TwoPhaseUploader> uploader_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DownloadFeedbackImpl); |
+}; |
+ |
+DownloadFeedbackImpl::DownloadFeedbackImpl( |
+ net::URLRequestContextGetter* request_context_getter, |
+ base::TaskRunner* file_task_runner, |
+ const base::FilePath& file_path, |
+ const std::string& ping_request, |
+ const std::string& ping_response) |
+ : request_context_getter_(request_context_getter), |
+ file_task_runner_(file_task_runner), |
+ file_path_(file_path), |
+ file_size_(-1), |
+ ping_request_(ping_request), |
+ ping_response_(ping_response) { |
+ DVLOG(1) << "DownloadFeedback constructed " << this << " for " |
+ << file_path.AsUTF8Unsafe(); |
+} |
+ |
+DownloadFeedbackImpl::~DownloadFeedbackImpl() { |
+ DCHECK(CalledOnValidThread()); |
+ DVLOG(1) << "DownloadFeedback destructed " << this; |
+ |
+ if (uploader_) { |
+ RecordUploadResult(UPLOAD_CANCELLED); |
+ // Destroy the uploader before attempting to delete the file. |
+ uploader_.reset(); |
+ } |
+ |
+ base::FileUtilProxy::Delete(file_task_runner_, file_path_, false, |
+ base::FileUtilProxy::StatusCallback()); |
+} |
+ |
+void DownloadFeedbackImpl::Start(const base::Closure& finish_callback) { |
+ DCHECK(CalledOnValidThread()); |
+ DCHECK(!uploader_); |
+ |
+ CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
+ |
+ ClientDownloadReport report_metadata; |
+ |
+ bool r = report_metadata.mutable_download_request()->ParseFromString( |
+ ping_request_); |
+ DCHECK(r); |
+ r = report_metadata.mutable_download_response()->ParseFromString( |
+ ping_response_); |
+ DCHECK(r); |
+ file_size_ = report_metadata.download_request().length(); |
+ |
+ GURL url = GURL(cmdline->HasSwitch(switches::kSbDownloadFeedbackURL) ? |
+ cmdline->GetSwitchValueASCII(switches::kSbDownloadFeedbackURL) : |
+ kSbDefaultFeedbackURL); |
+ |
+ std::string metadata_string; |
+ bool ok = report_metadata.SerializeToString(&metadata_string); |
+ DCHECK(ok); |
+ uploader_.reset(TwoPhaseUploader::Create( |
+ request_context_getter_, |
+ file_task_runner_, |
+ url, |
+ metadata_string, |
+ file_path_, |
+ TwoPhaseUploader::ProgressCallback(), |
+ base::Bind(&DownloadFeedbackImpl::FinishedUpload, base::Unretained(this), |
+ finish_callback))); |
+ uploader_->Start(); |
+} |
+ |
+void DownloadFeedbackImpl::FinishedUpload(base::Closure finish_callback, |
+ TwoPhaseUploader::State state, |
+ int net_error, |
+ int response_code, |
+ const std::string& response_data) { |
+ DCHECK(CalledOnValidThread()); |
+ DVLOG(1) << __FUNCTION__ << " " << state << " rlen=" << response_data.size(); |
+ |
+ switch (state) { |
+ case TwoPhaseUploader::STATE_SUCCESS: { |
+ ClientUploadResponse response; |
+ if (!response.ParseFromString(response_data) || |
+ response.status() != ClientUploadResponse::SUCCESS) |
+ RecordUploadResult(UPLOAD_COMPLETE_RESPONSE_ERROR); |
+ else |
+ RecordUploadResult(UPLOAD_SUCCESS); |
+ break; |
+ } |
+ case TwoPhaseUploader::UPLOAD_FILE: |
+ if (net_error != net::OK) |
+ RecordUploadResult(UPLOAD_FILE_NET_ERROR); |
+ else |
+ RecordUploadResult(UPLOAD_FILE_RESPONSE_ERROR); |
+ break; |
+ case TwoPhaseUploader::UPLOAD_METADATA: |
+ if (net_error != net::OK) |
+ RecordUploadResult(UPLOAD_METADATA_NET_ERROR); |
+ else |
+ RecordUploadResult(UPLOAD_METADATA_RESPONSE_ERROR); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ |
+ uploader_.reset(); |
+ |
+ finish_callback.Run(); |
+ // We may be deleted here. |
+} |
+ |
+void DownloadFeedbackImpl::RecordUploadResult(UploadResultType result) { |
+ if (result == UPLOAD_SUCCESS) |
+ UMA_HISTOGRAM_CUSTOM_COUNTS( |
+ "SBDownloadFeedback.SizeSuccess", file_size_, 1, kMaxUploadSize, 50); |
+ else |
+ UMA_HISTOGRAM_CUSTOM_COUNTS( |
+ "SBDownloadFeedback.SizeFailure", file_size_, 1, kMaxUploadSize, 50); |
+ UMA_HISTOGRAM_ENUMERATION( |
+ "SBDownloadFeedback.UploadResult", result, UPLOAD_RESULT_MAX); |
+} |
+ |
+} // namespace |
+ |
+// static |
+const int64 DownloadFeedback::kMaxUploadSize = 50 * 1024 * 1024; |
+ |
+// static |
+DownloadFeedbackFactory* DownloadFeedback::factory_ = NULL; |
+ |
+// static |
+DownloadFeedback* DownloadFeedback::Create( |
+ net::URLRequestContextGetter* request_context_getter, |
+ base::TaskRunner* file_task_runner, |
+ const base::FilePath& file_path, |
+ const std::string& ping_request, |
+ const std::string& ping_response) { |
+ if (!DownloadFeedback::factory_) |
+ return new DownloadFeedbackImpl( |
+ request_context_getter, file_task_runner, file_path, ping_request, |
+ ping_response); |
+ return DownloadFeedback::factory_->CreateDownloadFeedback( |
+ request_context_getter, file_task_runner, file_path, ping_request, |
+ ping_response); |
+} |
+ |
+} // namespace safe_browsing |
+ |