Add support for safebrowsing download protection. It is currently under flag --safebrowsing-download-protection.

TEST=safe_browsing_service_browsertest.cc
BUG=60822

Review URL: http://codereview.chromium.org/5141006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69979 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc
index 6e34a30..f8064060 100644
--- a/chrome/browser/renderer_host/download_resource_handler.cc
+++ b/chrome/browser/renderer_host/download_resource_handler.cc
@@ -7,6 +7,8 @@
 #include <string>
 
 #include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/stats_counters.h"
 #include "base/stringprintf.h"
 #include "chrome/browser/browser_thread.h"
 #include "chrome/browser/download/download_item.h"
@@ -41,7 +43,8 @@
       save_info_(save_info),
       buffer_(new DownloadBuffer),
       rdh_(rdh),
-      is_paused_(false) {
+      is_paused_(false),
+      url_check_pending_(false) {
 }
 
 bool DownloadResourceHandler::OnUploadProgress(int request_id,
@@ -59,11 +62,55 @@
   return true;
 }
 
+// Callback when the result of checking a download URL is known.
+// TODO(lzheng): We should create a information bar with buttons to ask
+// if users want to proceed when the download is malicious.
+void DownloadResourceHandler::OnDownloadUrlCheckResult(
+    const GURL& url, SafeBrowsingService::UrlCheckResult result) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK(url_check_pending_);
+
+  UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration",
+                      base::TimeTicks::Now() - download_start_time_);
+
+  if (result == SafeBrowsingService::BINARY_MALWARE) {
+    // TODO(lzheng): More UI work to show warnings properly on download shelf.
+    DLOG(WARNING) << "This url leads to a malware downloading: "
+                  << url.spec();
+    UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_MALWARE);
+  }
+
+  url_check_pending_ = false;
+  // Note: Release() should be the last line in this call. It is for
+  // the AddRef in CheckSafeBrowsing.
+  Release();
+}
+
+// Send the download creation information to the download thread.
+void DownloadResourceHandler::StartDownloadUrlCheck() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  AddRef();
+  if (!rdh_->safe_browsing_service()->CheckDownloadUrl(url_, this)) {
+    url_check_pending_ = true;
+    UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_TOTAL);
+    // Note: in this case, the AddRef will be balanced in
+    // "OnDownloadUrlCheckResult" or "OnRequestClosed".
+  } else {
+    // Immediately release the AddRef() at the beginning of this function
+    // since no more callbacks will happen.
+    Release();
+    DVLOG(1) << "url: " << url_.spec() << " is safe to download.";
+  }
+}
+
 // Send the download creation information to the download thread.
 bool DownloadResourceHandler::OnResponseStarted(int request_id,
                                                 ResourceResponse* response) {
   VLOG(20) << __FUNCTION__ << "()" << DebugString()
            << " request_id = " << request_id;
+  DCHECK(!url_check_pending_);
+  download_start_time_ = base::TimeTicks::Now();
+  StartDownloadUrlCheck();
   std::string content_disposition;
   request_->GetResponseHeaderByName("content-disposition",
                                     &content_disposition);
@@ -183,6 +230,17 @@
 }
 
 void DownloadResourceHandler::OnRequestClosed() {
+  UMA_HISTOGRAM_TIMES("SB2.DownloadDuration",
+                      base::TimeTicks::Now() - download_start_time_);
+  if (url_check_pending_) {
+    DVLOG(1) << "Cancel pending download url checking request: " << this;
+    rdh_->safe_browsing_service()->CancelCheck(this);
+    UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_CANCELED);
+    url_check_pending_ = false;
+    // Balance the AddRef() from StartDownloadUrlCheck() which would usually be
+    // balanced by OnDownloadUrlCheckResult().
+    Release();
+  }
 }
 
 // If the content-length header is not present (or contains something other
@@ -249,3 +307,10 @@
                             render_view_id_,
                             save_info_.file_path.value().c_str());
 }
+
+void DownloadResourceHandler::UpdateDownloadUrlCheckStats(
+    SBStatsType stat_type) {
+  UMA_HISTOGRAM_ENUMERATION("SB2.DownloadUrlChecks",
+                            stat_type,
+                            DOWNLOAD_URL_CHECKS_MAX);
+}
diff --git a/chrome/browser/renderer_host/download_resource_handler.h b/chrome/browser/renderer_host/download_resource_handler.h
index 3fb6961..5a66f662 100644
--- a/chrome/browser/renderer_host/download_resource_handler.h
+++ b/chrome/browser/renderer_host/download_resource_handler.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/download/download_file.h"
 #include "chrome/browser/renderer_host/global_request_id.h"
 #include "chrome/browser/renderer_host/resource_handler.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 
 class DownloadFileManager;
 class ResourceDispatcherHost;
@@ -22,7 +23,8 @@
 }  // namespace net
 
 // Forwards data to the download thread.
-class DownloadResourceHandler : public ResourceHandler {
+class DownloadResourceHandler : public ResourceHandler,
+                                public SafeBrowsingService::Client {
  public:
   DownloadResourceHandler(ResourceDispatcherHost* rdh,
                           int render_process_host_id,
@@ -70,10 +72,31 @@
   std::string DebugString() const;
 
  private:
+  // Enumerate for histogramming purposes.  DO NOT CHANGE THE
+  // ORDERING OF THESE VALUES.
+  enum SBStatsType {
+    DOWNLOAD_URL_CHECKS_TOTAL,
+    DOWNLOAD_URL_CHECKS_CANCELED,
+    DOWNLOAD_URL_CHECKS_MALWARE,
+
+    // Memory space for histograms is determined by the max.  ALWAYS
+    // ADD NEW VALUES BEFORE THIS ONE.
+    DOWNLOAD_URL_CHECKS_MAX
+  };
+
   ~DownloadResourceHandler();
 
   void StartPauseTimer();
 
+  void StartDownloadUrlCheck();
+
+  // Called when the result of checking a download URL is known.
+  void OnDownloadUrlCheckResult(const GURL& url,
+                                SafeBrowsingService::UrlCheckResult result);
+
+  // A helper function that updates UMA for download url checks.
+  static void UpdateDownloadUrlCheckStats(SBStatsType stat_type);
+
   int download_id_;
   GlobalRequestID global_id_;
   int render_view_id_;
@@ -89,6 +112,8 @@
   ResourceDispatcherHost* rdh_;
   bool is_paused_;
   base::OneShotTimer<DownloadResourceHandler> pause_timer_;
+  bool url_check_pending_;
+  base::TimeTicks download_start_time_;  // used to collect stats.
 
   static const int kReadBufSize = 32768;  // bytes
   static const size_t kLoadsToWrite = 100;  // number of data buffers queued