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_service.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util_proxy.h"
10 #include "base/metrics/histogram.h"
11 #include "base/supports_user_data.h"
12 #include "base/task_runner.h"
13 #include "chrome/browser/safe_browsing/download_feedback.h"
14 #include "content/public/browser/download_danger_type.h"
15 #include "content/public/browser/download_item.h"
17 namespace safe_browsing
{
21 const void* kPingKey
= &kPingKey
;
23 class DownloadFeedbackPings
: public base::SupportsUserData::Data
{
25 DownloadFeedbackPings(const std::string
& ping_request
,
26 const std::string
& ping_response
);
28 // Stores the ping data in the given |download|.
29 static void CreateForDownload(content::DownloadItem
* download
,
30 const std::string
& ping_request
,
31 const std::string
& ping_response
);
33 // Returns the DownloadFeedbackPings object associated with |download|. May
35 static DownloadFeedbackPings
* FromDownload(
36 const content::DownloadItem
& download
);
39 const std::string
& ping_request() const {
43 const std::string
& ping_response() const {
44 return ping_response_
;
48 std::string ping_request_
;
49 std::string ping_response_
;
52 DownloadFeedbackPings::DownloadFeedbackPings(const std::string
& ping_request
,
53 const std::string
& ping_response
)
54 : ping_request_(ping_request
),
55 ping_response_(ping_response
) {
59 void DownloadFeedbackPings::CreateForDownload(
60 content::DownloadItem
* download
,
61 const std::string
& ping_request
,
62 const std::string
& ping_response
) {
63 DownloadFeedbackPings
* pings
= new DownloadFeedbackPings(ping_request
,
65 download
->SetUserData(kPingKey
, pings
);
69 DownloadFeedbackPings
* DownloadFeedbackPings::FromDownload(
70 const content::DownloadItem
& download
) {
71 return static_cast<DownloadFeedbackPings
*>(download
.GetUserData(kPingKey
));
76 DownloadFeedbackService::DownloadFeedbackService(
77 net::URLRequestContextGetter
* request_context_getter
,
78 base::TaskRunner
* file_task_runner
)
79 : request_context_getter_(request_context_getter
),
80 file_task_runner_(file_task_runner
),
81 weak_ptr_factory_(this) {
84 DownloadFeedbackService::~DownloadFeedbackService() {
85 DCHECK(CalledOnValidThread());
89 void DownloadFeedbackService::MaybeStorePingsForDownload(
90 DownloadProtectionService::DownloadCheckResult result
,
91 content::DownloadItem
* download
,
92 const std::string
& ping
,
93 const std::string
& response
) {
94 if (result
!= DownloadProtectionService::UNCOMMON
&&
95 result
!= DownloadProtectionService::DANGEROUS_HOST
)
97 UMA_HISTOGRAM_COUNTS("SBDownloadFeedback.SizeEligibleKB",
98 download
->GetReceivedBytes() / 1024);
99 if (download
->GetReceivedBytes() > DownloadFeedback::kMaxUploadSize
)
102 DownloadFeedbackPings::CreateForDownload(download
, ping
, response
);
106 bool DownloadFeedbackService::IsEnabledForDownload(
107 const content::DownloadItem
& download
) {
108 return !!DownloadFeedbackPings::FromDownload(download
);
112 bool DownloadFeedbackService::GetPingsForDownloadForTesting(
113 const content::DownloadItem
& download
,
115 std::string
* response
) {
116 DownloadFeedbackPings
* pings
= DownloadFeedbackPings::FromDownload(download
);
120 *ping
= pings
->ping_request();
121 *response
= pings
->ping_response();
126 void DownloadFeedbackService::RecordEligibleDownloadShown(
127 content::DownloadDangerType danger_type
) {
128 UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Eligible",
130 content::DOWNLOAD_DANGER_TYPE_MAX
);
134 void DownloadFeedbackService::BeginFeedbackForDownload(
135 content::DownloadItem
* download
) {
136 DCHECK(CalledOnValidThread());
138 UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Activations",
139 download
->GetDangerType(),
140 content::DOWNLOAD_DANGER_TYPE_MAX
);
142 DownloadFeedbackPings
* pings
= DownloadFeedbackPings::FromDownload(*download
);
145 download
->StealDangerousDownload(
146 base::Bind(&DownloadFeedbackService::BeginFeedbackOrDeleteFile
,
148 weak_ptr_factory_
.GetWeakPtr(),
149 pings
->ping_request(),
150 pings
->ping_response()));
154 void DownloadFeedbackService::BeginFeedbackOrDeleteFile(
155 const scoped_refptr
<base::TaskRunner
>& file_task_runner
,
156 const base::WeakPtr
<DownloadFeedbackService
>& service
,
157 const std::string
& ping_request
,
158 const std::string
& ping_response
,
159 const base::FilePath
& path
) {
161 service
->BeginFeedback(ping_request
, ping_response
, path
);
163 base::FileUtilProxy::DeleteFile(file_task_runner
.get(),
166 base::FileUtilProxy::StatusCallback());
170 void DownloadFeedbackService::StartPendingFeedback() {
171 DCHECK(!active_feedback_
.empty());
172 active_feedback_
.front()->Start(base::Bind(
173 &DownloadFeedbackService::FeedbackComplete
, base::Unretained(this)));
176 void DownloadFeedbackService::BeginFeedback(
177 const std::string
& ping_request
,
178 const std::string
& ping_response
,
179 const base::FilePath
& path
) {
180 DCHECK(CalledOnValidThread());
181 DownloadFeedback
* feedback
=
182 DownloadFeedback::Create(request_context_getter_
.get(),
183 file_task_runner_
.get(),
187 active_feedback_
.push_back(feedback
);
188 UMA_HISTOGRAM_COUNTS_100("SBDownloadFeedback.ActiveFeedbacks",
189 active_feedback_
.size());
191 if (active_feedback_
.size() == 1)
192 StartPendingFeedback();
195 void DownloadFeedbackService::FeedbackComplete() {
196 DVLOG(1) << __FUNCTION__
;
197 DCHECK(CalledOnValidThread());
198 DCHECK(!active_feedback_
.empty());
199 active_feedback_
.erase(active_feedback_
.begin());
200 if (!active_feedback_
.empty())
201 StartPendingFeedback();
204 } // namespace safe_browsing