Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / download_feedback.cc
blobb23a3136d07ef0a92ccf7ecb07ec691229ad44c7
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/safe_browsing/download_feedback.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_util_proxy.h"
10 #include "base/metrics/histogram.h"
11 #include "base/task_runner.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/safe_browsing/csd.pb.h"
14 #include "net/base/net_errors.h"
16 namespace safe_browsing {
18 namespace {
20 // The default URL where browser sends download feedback requests.
21 const char kSbDefaultFeedbackURL[] =
22 "https://safebrowsing.google.com/safebrowsing/uploads/chrome";
24 // This enum is used by histograms. Do not change the ordering or remove items.
25 enum UploadResultType {
26 UPLOAD_SUCCESS,
27 UPLOAD_CANCELLED,
28 UPLOAD_METADATA_NET_ERROR,
29 UPLOAD_METADATA_RESPONSE_ERROR,
30 UPLOAD_FILE_NET_ERROR,
31 UPLOAD_FILE_RESPONSE_ERROR,
32 UPLOAD_COMPLETE_RESPONSE_ERROR,
33 // Memory space for histograms is determined by the max.
34 // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
35 UPLOAD_RESULT_MAX
38 // Handles the uploading of a single downloaded binary to the safebrowsing
39 // download feedback service.
40 class DownloadFeedbackImpl : public DownloadFeedback {
41 public:
42 DownloadFeedbackImpl(net::URLRequestContextGetter* request_context_getter,
43 base::TaskRunner* file_task_runner,
44 const base::FilePath& file_path,
45 const std::string& ping_request,
46 const std::string& ping_response);
47 virtual ~DownloadFeedbackImpl();
49 virtual void Start(const base::Closure& finish_callback) OVERRIDE;
51 virtual const std::string& GetPingRequestForTesting() const OVERRIDE {
52 return ping_request_;
55 virtual const std::string& GetPingResponseForTesting() const OVERRIDE {
56 return ping_response_;
59 private:
60 // Callback for TwoPhaseUploader completion. Relays the result to the
61 // |finish_callback|.
62 void FinishedUpload(base::Closure finish_callback,
63 TwoPhaseUploader::State state,
64 int net_error,
65 int response_code,
66 const std::string& response);
68 void RecordUploadResult(UploadResultType result);
70 scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
71 scoped_refptr<base::TaskRunner> file_task_runner_;
72 const base::FilePath file_path_;
73 int64 file_size_;
75 // The safebrowsing request and response of checking that this binary is
76 // unsafe.
77 std::string ping_request_;
78 std::string ping_response_;
80 scoped_ptr<TwoPhaseUploader> uploader_;
82 DISALLOW_COPY_AND_ASSIGN(DownloadFeedbackImpl);
85 DownloadFeedbackImpl::DownloadFeedbackImpl(
86 net::URLRequestContextGetter* request_context_getter,
87 base::TaskRunner* file_task_runner,
88 const base::FilePath& file_path,
89 const std::string& ping_request,
90 const std::string& ping_response)
91 : request_context_getter_(request_context_getter),
92 file_task_runner_(file_task_runner),
93 file_path_(file_path),
94 file_size_(-1),
95 ping_request_(ping_request),
96 ping_response_(ping_response) {
97 DVLOG(1) << "DownloadFeedback constructed " << this << " for "
98 << file_path.AsUTF8Unsafe();
101 DownloadFeedbackImpl::~DownloadFeedbackImpl() {
102 DCHECK(CalledOnValidThread());
103 DVLOG(1) << "DownloadFeedback destructed " << this;
105 if (uploader_) {
106 RecordUploadResult(UPLOAD_CANCELLED);
107 // Destroy the uploader before attempting to delete the file.
108 uploader_.reset();
111 base::FileUtilProxy::DeleteFile(file_task_runner_.get(),
112 file_path_,
113 false,
114 base::FileUtilProxy::StatusCallback());
117 void DownloadFeedbackImpl::Start(const base::Closure& finish_callback) {
118 DCHECK(CalledOnValidThread());
119 DCHECK(!uploader_);
121 CommandLine* cmdline = CommandLine::ForCurrentProcess();
123 ClientDownloadReport report_metadata;
125 bool r = report_metadata.mutable_download_request()->ParseFromString(
126 ping_request_);
127 DCHECK(r);
128 r = report_metadata.mutable_download_response()->ParseFromString(
129 ping_response_);
130 DCHECK(r);
131 file_size_ = report_metadata.download_request().length();
133 GURL url = GURL(cmdline->HasSwitch(switches::kSbDownloadFeedbackURL) ?
134 cmdline->GetSwitchValueASCII(switches::kSbDownloadFeedbackURL) :
135 kSbDefaultFeedbackURL);
137 std::string metadata_string;
138 bool ok = report_metadata.SerializeToString(&metadata_string);
139 DCHECK(ok);
140 uploader_.reset(
141 TwoPhaseUploader::Create(request_context_getter_.get(),
142 file_task_runner_.get(),
143 url,
144 metadata_string,
145 file_path_,
146 TwoPhaseUploader::ProgressCallback(),
147 base::Bind(&DownloadFeedbackImpl::FinishedUpload,
148 base::Unretained(this),
149 finish_callback)));
150 uploader_->Start();
153 void DownloadFeedbackImpl::FinishedUpload(base::Closure finish_callback,
154 TwoPhaseUploader::State state,
155 int net_error,
156 int response_code,
157 const std::string& response_data) {
158 DCHECK(CalledOnValidThread());
159 DVLOG(1) << __FUNCTION__ << " " << state << " rlen=" << response_data.size();
161 switch (state) {
162 case TwoPhaseUploader::STATE_SUCCESS: {
163 ClientUploadResponse response;
164 if (!response.ParseFromString(response_data) ||
165 response.status() != ClientUploadResponse::SUCCESS)
166 RecordUploadResult(UPLOAD_COMPLETE_RESPONSE_ERROR);
167 else
168 RecordUploadResult(UPLOAD_SUCCESS);
169 break;
171 case TwoPhaseUploader::UPLOAD_FILE:
172 if (net_error != net::OK)
173 RecordUploadResult(UPLOAD_FILE_NET_ERROR);
174 else
175 RecordUploadResult(UPLOAD_FILE_RESPONSE_ERROR);
176 break;
177 case TwoPhaseUploader::UPLOAD_METADATA:
178 if (net_error != net::OK)
179 RecordUploadResult(UPLOAD_METADATA_NET_ERROR);
180 else
181 RecordUploadResult(UPLOAD_METADATA_RESPONSE_ERROR);
182 break;
183 default:
184 NOTREACHED();
187 uploader_.reset();
189 finish_callback.Run();
190 // We may be deleted here.
193 void DownloadFeedbackImpl::RecordUploadResult(UploadResultType result) {
194 if (result == UPLOAD_SUCCESS)
195 UMA_HISTOGRAM_CUSTOM_COUNTS(
196 "SBDownloadFeedback.SizeSuccess", file_size_, 1, kMaxUploadSize, 50);
197 else
198 UMA_HISTOGRAM_CUSTOM_COUNTS(
199 "SBDownloadFeedback.SizeFailure", file_size_, 1, kMaxUploadSize, 50);
200 UMA_HISTOGRAM_ENUMERATION(
201 "SBDownloadFeedback.UploadResult", result, UPLOAD_RESULT_MAX);
204 } // namespace
206 // static
207 const int64 DownloadFeedback::kMaxUploadSize = 50 * 1024 * 1024;
209 // static
210 DownloadFeedbackFactory* DownloadFeedback::factory_ = NULL;
212 // static
213 DownloadFeedback* DownloadFeedback::Create(
214 net::URLRequestContextGetter* request_context_getter,
215 base::TaskRunner* file_task_runner,
216 const base::FilePath& file_path,
217 const std::string& ping_request,
218 const std::string& ping_response) {
219 if (!DownloadFeedback::factory_)
220 return new DownloadFeedbackImpl(
221 request_context_getter, file_task_runner, file_path, ping_request,
222 ping_response);
223 return DownloadFeedback::factory_->CreateDownloadFeedback(
224 request_context_getter, file_task_runner, file_path, ping_request,
225 ping_response);
228 } // namespace safe_browsing