• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/safe_browsing/download_feedback_service.h"
6 
7 #include "base/bind.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"
16 
17 namespace safe_browsing {
18 
19 namespace {
20 
21 const void* kPingKey = &kPingKey;
22 
23 class DownloadFeedbackPings : public base::SupportsUserData::Data {
24  public:
25   DownloadFeedbackPings(const std::string& ping_request,
26                         const std::string& ping_response);
27 
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);
32 
33   // Returns the DownloadFeedbackPings object associated with |download|.  May
34   // return NULL.
35   static DownloadFeedbackPings* FromDownload(
36       const content::DownloadItem& download);
37 
38 
ping_request() const39   const std::string& ping_request() const {
40     return ping_request_;
41   }
42 
ping_response() const43   const std::string& ping_response() const {
44     return ping_response_;
45   }
46 
47  private:
48   std::string ping_request_;
49   std::string ping_response_;
50 };
51 
DownloadFeedbackPings(const std::string & ping_request,const 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) {
56 }
57 
58 // static
CreateForDownload(content::DownloadItem * download,const std::string & ping_request,const std::string & 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,
64                                                            ping_response);
65   download->SetUserData(kPingKey, pings);
66 }
67 
68 // static
FromDownload(const content::DownloadItem & download)69 DownloadFeedbackPings* DownloadFeedbackPings::FromDownload(
70     const content::DownloadItem& download) {
71   return static_cast<DownloadFeedbackPings*>(download.GetUserData(kPingKey));
72 }
73 
74 }  // namespace
75 
DownloadFeedbackService(net::URLRequestContextGetter * request_context_getter,base::TaskRunner * file_task_runner)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) {
82 }
83 
~DownloadFeedbackService()84 DownloadFeedbackService::~DownloadFeedbackService() {
85   DCHECK(CalledOnValidThread());
86 }
87 
88 // static
MaybeStorePingsForDownload(DownloadProtectionService::DownloadCheckResult result,content::DownloadItem * download,const std::string & ping,const std::string & response)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)
96     return;
97   UMA_HISTOGRAM_COUNTS("SBDownloadFeedback.SizeEligibleKB",
98                        download->GetReceivedBytes() / 1024);
99   if (download->GetReceivedBytes() > DownloadFeedback::kMaxUploadSize)
100     return;
101 
102   DownloadFeedbackPings::CreateForDownload(download, ping, response);
103 }
104 
105 // static
IsEnabledForDownload(const content::DownloadItem & download)106 bool DownloadFeedbackService::IsEnabledForDownload(
107     const content::DownloadItem& download) {
108   return !!DownloadFeedbackPings::FromDownload(download);
109 }
110 
111 // static
GetPingsForDownloadForTesting(const content::DownloadItem & download,std::string * ping,std::string * response)112 bool DownloadFeedbackService::GetPingsForDownloadForTesting(
113     const content::DownloadItem& download,
114     std::string* ping,
115     std::string* response) {
116   DownloadFeedbackPings* pings = DownloadFeedbackPings::FromDownload(download);
117   if (!pings)
118     return false;
119 
120   *ping = pings->ping_request();
121   *response = pings->ping_response();
122   return true;
123 }
124 
125 // static
RecordEligibleDownloadShown(content::DownloadDangerType danger_type)126 void DownloadFeedbackService::RecordEligibleDownloadShown(
127     content::DownloadDangerType danger_type) {
128   UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Eligible",
129                             danger_type,
130                             content::DOWNLOAD_DANGER_TYPE_MAX);
131 }
132 
133 
BeginFeedbackForDownload(content::DownloadItem * download)134 void DownloadFeedbackService::BeginFeedbackForDownload(
135     content::DownloadItem* download) {
136   DCHECK(CalledOnValidThread());
137 
138   UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Activations",
139                             download->GetDangerType(),
140                             content::DOWNLOAD_DANGER_TYPE_MAX);
141 
142   DownloadFeedbackPings* pings = DownloadFeedbackPings::FromDownload(*download);
143   DCHECK(pings);
144 
145   download->StealDangerousDownload(
146       base::Bind(&DownloadFeedbackService::BeginFeedbackOrDeleteFile,
147                  file_task_runner_,
148                  weak_ptr_factory_.GetWeakPtr(),
149                  pings->ping_request(),
150                  pings->ping_response()));
151 }
152 
153 // static
BeginFeedbackOrDeleteFile(const scoped_refptr<base::TaskRunner> & file_task_runner,const base::WeakPtr<DownloadFeedbackService> & service,const std::string & ping_request,const std::string & ping_response,const base::FilePath & path)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) {
160   if (service) {
161     service->BeginFeedback(ping_request, ping_response, path);
162   } else {
163     base::FileUtilProxy::DeleteFile(file_task_runner.get(),
164                                     path,
165                                     false,
166                                     base::FileUtilProxy::StatusCallback());
167   }
168 }
169 
StartPendingFeedback()170 void DownloadFeedbackService::StartPendingFeedback() {
171   DCHECK(!active_feedback_.empty());
172   active_feedback_.front()->Start(base::Bind(
173       &DownloadFeedbackService::FeedbackComplete, base::Unretained(this)));
174 }
175 
BeginFeedback(const std::string & ping_request,const std::string & ping_response,const base::FilePath & path)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(),
184                                path,
185                                ping_request,
186                                ping_response);
187   active_feedback_.push_back(feedback);
188   UMA_HISTOGRAM_COUNTS_100("SBDownloadFeedback.ActiveFeedbacks",
189                            active_feedback_.size());
190 
191   if (active_feedback_.size() == 1)
192     StartPendingFeedback();
193 }
194 
FeedbackComplete()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();
202 }
203 
204 }  // namespace safe_browsing
205