Home | History | Annotate | Download | only in safe_browsing
      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.h"
      6 
      7 #include "base/bind.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"
     13 
     14 namespace safe_browsing {
     15 
     16 namespace {
     17 
     18 // This enum is used by histograms.  Do not change the ordering or remove items.
     19 enum UploadResultType {
     20   UPLOAD_SUCCESS,
     21   UPLOAD_CANCELLED,
     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.
     29   UPLOAD_RESULT_MAX
     30 };
     31 
     32 // Handles the uploading of a single downloaded binary to the safebrowsing
     33 // download feedback service.
     34 class DownloadFeedbackImpl : public DownloadFeedback {
     35  public:
     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();
     42 
     43   virtual void Start(const base::Closure& finish_callback) OVERRIDE;
     44 
     45   virtual const std::string& GetPingRequestForTesting() const OVERRIDE {
     46     return ping_request_;
     47   }
     48 
     49   virtual const std::string& GetPingResponseForTesting() const OVERRIDE {
     50     return ping_response_;
     51   }
     52 
     53  private:
     54   // Callback for TwoPhaseUploader completion.  Relays the result to the
     55   // |finish_callback|.
     56   void FinishedUpload(base::Closure finish_callback,
     57                       TwoPhaseUploader::State state,
     58                       int net_error,
     59                       int response_code,
     60                       const std::string& response);
     61 
     62   void RecordUploadResult(UploadResultType result);
     63 
     64   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
     65   scoped_refptr<base::TaskRunner> file_task_runner_;
     66   const base::FilePath file_path_;
     67   int64 file_size_;
     68 
     69   // The safebrowsing request and response of checking that this binary is
     70   // unsafe.
     71   std::string ping_request_;
     72   std::string ping_response_;
     73 
     74   scoped_ptr<TwoPhaseUploader> uploader_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(DownloadFeedbackImpl);
     77 };
     78 
     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),
     88       file_size_(-1),
     89       ping_request_(ping_request),
     90       ping_response_(ping_response) {
     91   DVLOG(1) << "DownloadFeedback constructed " << this << " for "
     92            << file_path.AsUTF8Unsafe();
     93 }
     94 
     95 DownloadFeedbackImpl::~DownloadFeedbackImpl() {
     96   DCHECK(CalledOnValidThread());
     97   DVLOG(1) << "DownloadFeedback destructed " << this;
     98 
     99   if (uploader_) {
    100     RecordUploadResult(UPLOAD_CANCELLED);
    101     // Destroy the uploader before attempting to delete the file.
    102     uploader_.reset();
    103   }
    104 
    105   base::FileUtilProxy::DeleteFile(file_task_runner_.get(),
    106                                   file_path_,
    107                                   false,
    108                                   base::FileUtilProxy::StatusCallback());
    109 }
    110 
    111 void DownloadFeedbackImpl::Start(const base::Closure& finish_callback) {
    112   DCHECK(CalledOnValidThread());
    113   DCHECK(!uploader_);
    114 
    115   ClientDownloadReport report_metadata;
    116 
    117   bool r = report_metadata.mutable_download_request()->ParseFromString(
    118       ping_request_);
    119   DCHECK(r);
    120   r = report_metadata.mutable_download_response()->ParseFromString(
    121       ping_response_);
    122   DCHECK(r);
    123   file_size_ = report_metadata.download_request().length();
    124 
    125   std::string metadata_string;
    126   bool ok = report_metadata.SerializeToString(&metadata_string);
    127   DCHECK(ok);
    128   uploader_.reset(
    129       TwoPhaseUploader::Create(request_context_getter_.get(),
    130                                file_task_runner_.get(),
    131                                GURL(kSbFeedbackURL),
    132                                metadata_string,
    133                                file_path_,
    134                                TwoPhaseUploader::ProgressCallback(),
    135                                base::Bind(&DownloadFeedbackImpl::FinishedUpload,
    136                                           base::Unretained(this),
    137                                           finish_callback)));
    138   uploader_->Start();
    139 }
    140 
    141 void DownloadFeedbackImpl::FinishedUpload(base::Closure finish_callback,
    142                                           TwoPhaseUploader::State state,
    143                                           int net_error,
    144                                           int response_code,
    145                                           const std::string& response_data) {
    146   DCHECK(CalledOnValidThread());
    147   DVLOG(1) << __FUNCTION__ << " " << state << " rlen=" << response_data.size();
    148 
    149   switch (state) {
    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);
    155       else
    156         RecordUploadResult(UPLOAD_SUCCESS);
    157       break;
    158     }
    159     case TwoPhaseUploader::UPLOAD_FILE:
    160       if (net_error != net::OK)
    161         RecordUploadResult(UPLOAD_FILE_NET_ERROR);
    162       else
    163         RecordUploadResult(UPLOAD_FILE_RESPONSE_ERROR);
    164       break;
    165     case TwoPhaseUploader::UPLOAD_METADATA:
    166       if (net_error != net::OK)
    167         RecordUploadResult(UPLOAD_METADATA_NET_ERROR);
    168       else
    169         RecordUploadResult(UPLOAD_METADATA_RESPONSE_ERROR);
    170       break;
    171     default:
    172       NOTREACHED();
    173   }
    174 
    175   uploader_.reset();
    176 
    177   finish_callback.Run();
    178   // We may be deleted here.
    179 }
    180 
    181 void DownloadFeedbackImpl::RecordUploadResult(UploadResultType result) {
    182   if (result == UPLOAD_SUCCESS)
    183     UMA_HISTOGRAM_CUSTOM_COUNTS(
    184         "SBDownloadFeedback.SizeSuccess", file_size_, 1, kMaxUploadSize, 50);
    185   else
    186     UMA_HISTOGRAM_CUSTOM_COUNTS(
    187         "SBDownloadFeedback.SizeFailure", file_size_, 1, kMaxUploadSize, 50);
    188   UMA_HISTOGRAM_ENUMERATION(
    189       "SBDownloadFeedback.UploadResult", result, UPLOAD_RESULT_MAX);
    190 }
    191 
    192 }  // namespace
    193 
    194 // static
    195 const int64 DownloadFeedback::kMaxUploadSize = 50 * 1024 * 1024;
    196 
    197 // static
    198 const char DownloadFeedback::kSbFeedbackURL[] =
    199     "https://safebrowsing.google.com/safebrowsing/uploads/chrome";
    200 
    201 // static
    202 DownloadFeedbackFactory* DownloadFeedback::factory_ = NULL;
    203 
    204 // static
    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,
    214         ping_response);
    215   return DownloadFeedback::factory_->CreateDownloadFeedback(
    216         request_context_getter, file_task_runner, file_path, ping_request,
    217         ping_response);
    218 }
    219 
    220 }  // namespace safe_browsing
    221 
    222