root/chrome/browser/safe_browsing/download_feedback_service.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ping_request
  2. ping_response
  3. ping_response_
  4. CreateForDownload
  5. FromDownload
  6. weak_ptr_factory_
  7. MaybeStorePingsForDownload
  8. IsEnabledForDownload
  9. GetPingsForDownloadForTesting
  10. RecordEligibleDownloadShown
  11. BeginFeedbackForDownload
  12. BeginFeedbackOrDeleteFile
  13. StartPendingFeedback
  14. BeginFeedback
  15. FeedbackComplete

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/safe_browsing/download_feedback_service.h"

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util_proxy.h"
#include "base/metrics/histogram.h"
#include "base/supports_user_data.h"
#include "base/task_runner.h"
#include "chrome/browser/safe_browsing/download_feedback.h"
#include "content/public/browser/download_danger_type.h"
#include "content/public/browser/download_item.h"

namespace safe_browsing {

namespace {

const void* kPingKey = &kPingKey;

class DownloadFeedbackPings : public base::SupportsUserData::Data {
 public:
  DownloadFeedbackPings(const std::string& ping_request,
                        const std::string& ping_response);

  // Stores the ping data in the given |download|.
  static void CreateForDownload(content::DownloadItem* download,
                                const std::string& ping_request,
                                const std::string& ping_response);

  // Returns the DownloadFeedbackPings object associated with |download|.  May
  // return NULL.
  static DownloadFeedbackPings* FromDownload(
      const content::DownloadItem& download);


  const std::string& ping_request() const {
    return ping_request_;
  }

  const std::string& ping_response() const {
    return ping_response_;
  }

 private:
  std::string ping_request_;
  std::string ping_response_;
};

DownloadFeedbackPings::DownloadFeedbackPings(const std::string& ping_request,
                                             const std::string& ping_response)
    : ping_request_(ping_request),
      ping_response_(ping_response) {
}

// static
void DownloadFeedbackPings::CreateForDownload(
    content::DownloadItem* download,
    const std::string& ping_request,
    const std::string& ping_response) {
  DownloadFeedbackPings* pings = new DownloadFeedbackPings(ping_request,
                                                           ping_response);
  download->SetUserData(kPingKey, pings);
}

// static
DownloadFeedbackPings* DownloadFeedbackPings::FromDownload(
    const content::DownloadItem& download) {
  return static_cast<DownloadFeedbackPings*>(download.GetUserData(kPingKey));
}

}  // namespace

DownloadFeedbackService::DownloadFeedbackService(
    net::URLRequestContextGetter* request_context_getter,
    base::TaskRunner* file_task_runner)
    : request_context_getter_(request_context_getter),
      file_task_runner_(file_task_runner),
      weak_ptr_factory_(this) {
}

DownloadFeedbackService::~DownloadFeedbackService() {
  DCHECK(CalledOnValidThread());
}

// static
void DownloadFeedbackService::MaybeStorePingsForDownload(
    DownloadProtectionService::DownloadCheckResult result,
    content::DownloadItem* download,
    const std::string& ping,
    const std::string& response) {
  if (result != DownloadProtectionService::UNCOMMON &&
      result != DownloadProtectionService::DANGEROUS_HOST)
    return;
  UMA_HISTOGRAM_COUNTS("SBDownloadFeedback.SizeEligibleKB",
                       download->GetReceivedBytes() / 1024);
  if (download->GetReceivedBytes() > DownloadFeedback::kMaxUploadSize)
    return;

  DownloadFeedbackPings::CreateForDownload(download, ping, response);
}

// static
bool DownloadFeedbackService::IsEnabledForDownload(
    const content::DownloadItem& download) {
  return !!DownloadFeedbackPings::FromDownload(download);
}

// static
bool DownloadFeedbackService::GetPingsForDownloadForTesting(
    const content::DownloadItem& download,
    std::string* ping,
    std::string* response) {
  DownloadFeedbackPings* pings = DownloadFeedbackPings::FromDownload(download);
  if (!pings)
    return false;

  *ping = pings->ping_request();
  *response = pings->ping_response();
  return true;
}

// static
void DownloadFeedbackService::RecordEligibleDownloadShown(
    content::DownloadDangerType danger_type) {
  UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Eligible",
                            danger_type,
                            content::DOWNLOAD_DANGER_TYPE_MAX);
}


void DownloadFeedbackService::BeginFeedbackForDownload(
    content::DownloadItem* download) {
  DCHECK(CalledOnValidThread());

  UMA_HISTOGRAM_ENUMERATION("SBDownloadFeedback.Activations",
                            download->GetDangerType(),
                            content::DOWNLOAD_DANGER_TYPE_MAX);

  DownloadFeedbackPings* pings = DownloadFeedbackPings::FromDownload(*download);
  DCHECK(pings);

  download->StealDangerousDownload(
      base::Bind(&DownloadFeedbackService::BeginFeedbackOrDeleteFile,
                 file_task_runner_,
                 weak_ptr_factory_.GetWeakPtr(),
                 pings->ping_request(),
                 pings->ping_response()));
}

// static
void DownloadFeedbackService::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) {
  if (service) {
    service->BeginFeedback(ping_request, ping_response, path);
  } else {
    base::FileUtilProxy::DeleteFile(file_task_runner.get(),
                                    path,
                                    false,
                                    base::FileUtilProxy::StatusCallback());
  }
}

void DownloadFeedbackService::StartPendingFeedback() {
  DCHECK(!active_feedback_.empty());
  active_feedback_.front()->Start(base::Bind(
      &DownloadFeedbackService::FeedbackComplete, base::Unretained(this)));
}

void DownloadFeedbackService::BeginFeedback(
    const std::string& ping_request,
    const std::string& ping_response,
    const base::FilePath& path) {
  DCHECK(CalledOnValidThread());
  DownloadFeedback* feedback =
      DownloadFeedback::Create(request_context_getter_.get(),
                               file_task_runner_.get(),
                               path,
                               ping_request,
                               ping_response);
  active_feedback_.push_back(feedback);
  UMA_HISTOGRAM_COUNTS_100("SBDownloadFeedback.ActiveFeedbacks",
                           active_feedback_.size());

  if (active_feedback_.size() == 1)
    StartPendingFeedback();
}

void DownloadFeedbackService::FeedbackComplete() {
  DVLOG(1) << __FUNCTION__;
  DCHECK(CalledOnValidThread());
  DCHECK(!active_feedback_.empty());
  active_feedback_.erase(active_feedback_.begin());
  if (!active_feedback_.empty())
    StartPendingFeedback();
}

}  // namespace safe_browsing

/* [<][>][^][v][top][bottom][index][help] */