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/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
{
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
{
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.
38 // Handles the uploading of a single downloaded binary to the safebrowsing
39 // download feedback service.
40 class DownloadFeedbackImpl
: public DownloadFeedback
{
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
{
55 virtual const std::string
& GetPingResponseForTesting() const OVERRIDE
{
56 return ping_response_
;
60 // Callback for TwoPhaseUploader completion. Relays the result to the
62 void FinishedUpload(base::Closure finish_callback
,
63 TwoPhaseUploader::State state
,
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_
;
75 // The safebrowsing request and response of checking that this binary is
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
),
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;
106 RecordUploadResult(UPLOAD_CANCELLED
);
107 // Destroy the uploader before attempting to delete the file.
111 base::FileUtilProxy::DeleteFile(file_task_runner_
.get(),
114 base::FileUtilProxy::StatusCallback());
117 void DownloadFeedbackImpl::Start(const base::Closure
& finish_callback
) {
118 DCHECK(CalledOnValidThread());
121 CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
123 ClientDownloadReport report_metadata
;
125 bool r
= report_metadata
.mutable_download_request()->ParseFromString(
128 r
= report_metadata
.mutable_download_response()->ParseFromString(
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
);
141 TwoPhaseUploader::Create(request_context_getter_
.get(),
142 file_task_runner_
.get(),
146 TwoPhaseUploader::ProgressCallback(),
147 base::Bind(&DownloadFeedbackImpl::FinishedUpload
,
148 base::Unretained(this),
153 void DownloadFeedbackImpl::FinishedUpload(base::Closure finish_callback
,
154 TwoPhaseUploader::State state
,
157 const std::string
& response_data
) {
158 DCHECK(CalledOnValidThread());
159 DVLOG(1) << __FUNCTION__
<< " " << state
<< " rlen=" << response_data
.size();
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
);
168 RecordUploadResult(UPLOAD_SUCCESS
);
171 case TwoPhaseUploader::UPLOAD_FILE
:
172 if (net_error
!= net::OK
)
173 RecordUploadResult(UPLOAD_FILE_NET_ERROR
);
175 RecordUploadResult(UPLOAD_FILE_RESPONSE_ERROR
);
177 case TwoPhaseUploader::UPLOAD_METADATA
:
178 if (net_error
!= net::OK
)
179 RecordUploadResult(UPLOAD_METADATA_NET_ERROR
);
181 RecordUploadResult(UPLOAD_METADATA_RESPONSE_ERROR
);
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);
198 UMA_HISTOGRAM_CUSTOM_COUNTS(
199 "SBDownloadFeedback.SizeFailure", file_size_
, 1, kMaxUploadSize
, 50);
200 UMA_HISTOGRAM_ENUMERATION(
201 "SBDownloadFeedback.UploadResult", result
, UPLOAD_RESULT_MAX
);
207 const int64
DownloadFeedback::kMaxUploadSize
= 50 * 1024 * 1024;
210 DownloadFeedbackFactory
* DownloadFeedback::factory_
= NULL
;
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
,
223 return DownloadFeedback::factory_
->CreateDownloadFeedback(
224 request_context_getter
, file_task_runner
, file_path
, ping_request
,
228 } // namespace safe_browsing