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"
8 #include "base/files/file_util_proxy.h"
9 #include "base/metrics/histogram.h"
10 #include "base/task_runner.h"
11 #include "chrome/common/safe_browsing/csd.pb.h"
12 #include "net/base/net_errors.h"
14 namespace safe_browsing
{
18 // This enum is used by histograms. Do not change the ordering or remove items.
19 enum UploadResultType
{
22 UPLOAD_METADATA_NET_ERROR
,
23 UPLOAD_METADATA_RESPONSE_ERROR
,
24 UPLOAD_FILE_NET_ERROR
,
25 UPLOAD_FILE_RESPONSE_ERROR
,
26 UPLOAD_COMPLETE_RESPONSE_ERROR
,
27 // Memory space for histograms is determined by the max.
28 // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
32 // Handles the uploading of a single downloaded binary to the safebrowsing
33 // download feedback service.
34 class DownloadFeedbackImpl
: public DownloadFeedback
{
36 DownloadFeedbackImpl(net::URLRequestContextGetter
* request_context_getter
,
37 base::TaskRunner
* file_task_runner
,
38 const base::FilePath
& file_path
,
39 const std::string
& ping_request
,
40 const std::string
& ping_response
);
41 virtual ~DownloadFeedbackImpl();
43 virtual void Start(const base::Closure
& finish_callback
) OVERRIDE
;
45 virtual const std::string
& GetPingRequestForTesting() const OVERRIDE
{
49 virtual const std::string
& GetPingResponseForTesting() const OVERRIDE
{
50 return ping_response_
;
54 // Callback for TwoPhaseUploader completion. Relays the result to the
56 void FinishedUpload(base::Closure finish_callback
,
57 TwoPhaseUploader::State state
,
60 const std::string
& response
);
62 void RecordUploadResult(UploadResultType result
);
64 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter_
;
65 scoped_refptr
<base::TaskRunner
> file_task_runner_
;
66 const base::FilePath file_path_
;
69 // The safebrowsing request and response of checking that this binary is
71 std::string ping_request_
;
72 std::string ping_response_
;
74 scoped_ptr
<TwoPhaseUploader
> uploader_
;
76 DISALLOW_COPY_AND_ASSIGN(DownloadFeedbackImpl
);
79 DownloadFeedbackImpl::DownloadFeedbackImpl(
80 net::URLRequestContextGetter
* request_context_getter
,
81 base::TaskRunner
* file_task_runner
,
82 const base::FilePath
& file_path
,
83 const std::string
& ping_request
,
84 const std::string
& ping_response
)
85 : request_context_getter_(request_context_getter
),
86 file_task_runner_(file_task_runner
),
87 file_path_(file_path
),
89 ping_request_(ping_request
),
90 ping_response_(ping_response
) {
91 DVLOG(1) << "DownloadFeedback constructed " << this << " for "
92 << file_path
.AsUTF8Unsafe();
95 DownloadFeedbackImpl::~DownloadFeedbackImpl() {
96 DCHECK(CalledOnValidThread());
97 DVLOG(1) << "DownloadFeedback destructed " << this;
100 RecordUploadResult(UPLOAD_CANCELLED
);
101 // Destroy the uploader before attempting to delete the file.
105 base::FileUtilProxy::DeleteFile(file_task_runner_
.get(),
108 base::FileUtilProxy::StatusCallback());
111 void DownloadFeedbackImpl::Start(const base::Closure
& finish_callback
) {
112 DCHECK(CalledOnValidThread());
115 ClientDownloadReport report_metadata
;
117 bool r
= report_metadata
.mutable_download_request()->ParseFromString(
120 r
= report_metadata
.mutable_download_response()->ParseFromString(
123 file_size_
= report_metadata
.download_request().length();
125 std::string metadata_string
;
126 bool ok
= report_metadata
.SerializeToString(&metadata_string
);
129 TwoPhaseUploader::Create(request_context_getter_
.get(),
130 file_task_runner_
.get(),
131 GURL(kSbFeedbackURL
),
134 TwoPhaseUploader::ProgressCallback(),
135 base::Bind(&DownloadFeedbackImpl::FinishedUpload
,
136 base::Unretained(this),
141 void DownloadFeedbackImpl::FinishedUpload(base::Closure finish_callback
,
142 TwoPhaseUploader::State state
,
145 const std::string
& response_data
) {
146 DCHECK(CalledOnValidThread());
147 DVLOG(1) << __FUNCTION__
<< " " << state
<< " rlen=" << response_data
.size();
150 case TwoPhaseUploader::STATE_SUCCESS
: {
151 ClientUploadResponse response
;
152 if (!response
.ParseFromString(response_data
) ||
153 response
.status() != ClientUploadResponse::SUCCESS
)
154 RecordUploadResult(UPLOAD_COMPLETE_RESPONSE_ERROR
);
156 RecordUploadResult(UPLOAD_SUCCESS
);
159 case TwoPhaseUploader::UPLOAD_FILE
:
160 if (net_error
!= net::OK
)
161 RecordUploadResult(UPLOAD_FILE_NET_ERROR
);
163 RecordUploadResult(UPLOAD_FILE_RESPONSE_ERROR
);
165 case TwoPhaseUploader::UPLOAD_METADATA
:
166 if (net_error
!= net::OK
)
167 RecordUploadResult(UPLOAD_METADATA_NET_ERROR
);
169 RecordUploadResult(UPLOAD_METADATA_RESPONSE_ERROR
);
177 finish_callback
.Run();
178 // We may be deleted here.
181 void DownloadFeedbackImpl::RecordUploadResult(UploadResultType result
) {
182 if (result
== UPLOAD_SUCCESS
)
183 UMA_HISTOGRAM_CUSTOM_COUNTS(
184 "SBDownloadFeedback.SizeSuccess", file_size_
, 1, kMaxUploadSize
, 50);
186 UMA_HISTOGRAM_CUSTOM_COUNTS(
187 "SBDownloadFeedback.SizeFailure", file_size_
, 1, kMaxUploadSize
, 50);
188 UMA_HISTOGRAM_ENUMERATION(
189 "SBDownloadFeedback.UploadResult", result
, UPLOAD_RESULT_MAX
);
195 const int64
DownloadFeedback::kMaxUploadSize
= 50 * 1024 * 1024;
198 const char DownloadFeedback::kSbFeedbackURL
[] =
199 "https://safebrowsing.google.com/safebrowsing/uploads/chrome";
202 DownloadFeedbackFactory
* DownloadFeedback::factory_
= NULL
;
205 DownloadFeedback
* DownloadFeedback::Create(
206 net::URLRequestContextGetter
* request_context_getter
,
207 base::TaskRunner
* file_task_runner
,
208 const base::FilePath
& file_path
,
209 const std::string
& ping_request
,
210 const std::string
& ping_response
) {
211 if (!DownloadFeedback::factory_
)
212 return new DownloadFeedbackImpl(
213 request_context_getter
, file_task_runner
, file_path
, ping_request
,
215 return DownloadFeedback::factory_
->CreateDownloadFeedback(
216 request_context_getter
, file_task_runner
, file_path
, ping_request
,
220 } // namespace safe_browsing