15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/download_protection_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/format_macros.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
1358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/metrics/sparse_histogram.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sequenced_task_runner_helpers.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/history/history_service.h"
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/history/history_service_factory.h"
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/safe_browsing/binary_feature_extractor.h"
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/safe_browsing/download_feedback_service.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/safe_browsing/csd.pb.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/safe_browsing/download_protection_util.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/safe_browsing/zip_analyzer.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_item.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/page_navigator.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/google_api_keys.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_cert_types.h"
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_status_code.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static const int64 kDownloadRequestTimeoutMs = 7000;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace safe_browsing {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char DownloadProtectionService::kDownloadRequestUrl[] =
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "https://sb-ssl.google.com/safebrowsing/clientreport/download";
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// List of extensions for which we track some UMA stats.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum MaliciousExtensionType {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_EXE,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_MSI,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_CAB,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_SYS,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_SCR,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_DRV,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_BAT,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_ZIP,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_RAR,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_DLL,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_PIF,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_COM,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_JAR,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_CLASS,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_PDF,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_VB,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_REG,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_GRP,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_OTHER,  // Groups all other extensions into one bucket.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_CRX,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_APK,
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXTENSION_DMG,
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXTENSION_PKG,
846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  EXTENSION_TORRENT,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_MAX,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MaliciousExtensionType GetExtensionType(const base::FilePath& f) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".exe"))) return EXTENSION_EXE;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".msi"))) return EXTENSION_MSI;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".cab"))) return EXTENSION_CAB;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".sys"))) return EXTENSION_SYS;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".scr"))) return EXTENSION_SCR;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".drv"))) return EXTENSION_DRV;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".bat"))) return EXTENSION_BAT;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".zip"))) return EXTENSION_ZIP;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".rar"))) return EXTENSION_RAR;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".dll"))) return EXTENSION_DLL;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".pif"))) return EXTENSION_PIF;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".com"))) return EXTENSION_COM;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".jar"))) return EXTENSION_JAR;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".class"))) return EXTENSION_CLASS;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".pdf"))) return EXTENSION_PDF;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".vb"))) return EXTENSION_VB;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".reg"))) return EXTENSION_REG;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".grp"))) return EXTENSION_GRP;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".crx"))) return EXTENSION_CRX;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".apk"))) return EXTENSION_APK;
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".dmg"))) return EXTENSION_DMG;
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".pkg"))) return EXTENSION_PKG;
1116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (f.MatchesExtension(FILE_PATH_LITERAL(".torrent")))
1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return EXTENSION_TORRENT;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EXTENSION_OTHER;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RecordFileExtensionType(const base::FilePath& file) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("SBClientDownload.DownloadExtensions",
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            GetExtensionType(file),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            EXTENSION_MAX);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Enumerate for histogramming purposes.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DO NOT CHANGE THE ORDERING OF THESE VALUES (different histogram data will
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be mixed together based on their values).
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum SBStatsType {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOWNLOAD_URL_CHECKS_TOTAL,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOWNLOAD_URL_CHECKS_CANCELED,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOWNLOAD_URL_CHECKS_MALWARE,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOWNLOAD_HASH_CHECKS_TOTAL,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOWNLOAD_HASH_CHECKS_MALWARE,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Memory space for histograms is determined by the max.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOWNLOAD_CHECKS_MAX
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parent SafeBrowsing::Client class used to lookup the bad binary
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL and digest list.  There are two sub-classes (one for each list).
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadSBClient
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public SafeBrowsingDatabaseManager::Client,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public base::RefCountedThreadSafe<DownloadSBClient> {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadSBClient(
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const content::DownloadItem& item,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DownloadProtectionService::CheckDownloadCallback& callback,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const scoped_refptr<SafeBrowsingUIManager>& ui_manager,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SBStatsType total_type,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SBStatsType dangerous_type)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : sha256_hash_(item.GetHash()),
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_chain_(item.GetUrlChain()),
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        referrer_url_(item.GetReferrerUrl()),
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        callback_(callback),
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ui_manager_(ui_manager),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_time_(base::TimeTicks::Now()),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        total_type_(total_type),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dangerous_type_(dangerous_type) {}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void StartCheck() = 0;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool IsDangerous(SBThreatType threat_type) const = 0;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<DownloadSBClient>;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DownloadSBClient() {}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckDone(SBThreatType threat_type) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadProtectionService::DownloadCheckResult result =
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IsDangerous(threat_type) ?
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DownloadProtectionService::DANGEROUS :
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DownloadProtectionService::SAFE;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            FROM_HERE,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            base::Bind(callback_, result));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateDownloadCheckStats(total_type_);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (threat_type != SB_THREAT_TYPE_SAFE) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateDownloadCheckStats(dangerous_type_);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::UI,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&DownloadSBClient::ReportMalware,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     this, threat_type));
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReportMalware(SBThreatType threat_type) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string post_data;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!sha256_hash_.empty())
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      post_data += base::HexEncode(sha256_hash_.data(),
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   sha256_hash_.size()) + "\n";
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < url_chain_.size(); ++i) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      post_data += url_chain_[i].spec() + "\n";
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_manager_->ReportSafeBrowsingHit(
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_chain_.back(),  // malicious_url
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_chain_.front(), // page_url
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        referrer_url_,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        true,  // is_subresource
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        threat_type,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        post_data);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateDownloadCheckStats(SBStatsType stat_type) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("SB2.DownloadChecks",
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              stat_type,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DOWNLOAD_CHECKS_MAX);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string sha256_hash_;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<GURL> url_chain_;
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL referrer_url_;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadProtectionService::CheckDownloadCallback callback_;
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<SafeBrowsingUIManager> ui_manager_;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start_time_;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SBStatsType total_type_;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SBStatsType dangerous_type_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DownloadSBClient);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadUrlSBClient : public DownloadSBClient {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadUrlSBClient(
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const content::DownloadItem& item,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DownloadProtectionService::CheckDownloadCallback& callback,
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const scoped_refptr<SafeBrowsingUIManager>& ui_manager,
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : DownloadSBClient(item, callback, ui_manager,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         DOWNLOAD_URL_CHECKS_TOTAL,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         DOWNLOAD_URL_CHECKS_MALWARE),
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        database_manager_(database_manager) { }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void StartCheck() OVERRIDE {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!database_manager_.get() ||
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        database_manager_->CheckDownloadUrl(url_chain_, this)) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CheckDone(SB_THREAT_TYPE_SAFE);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddRef();  // SafeBrowsingService takes a pointer not a scoped_refptr.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool IsDangerous(SBThreatType threat_type) const OVERRIDE {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnCheckDownloadUrlResult(const std::vector<GURL>& url_chain,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        SBThreatType threat_type) OVERRIDE {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckDone(threat_type);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration",
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        base::TimeTicks::Now() - start_time_);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DownloadUrlSBClient() {}
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DownloadUrlSBClient);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadProtectionService::CheckClientDownloadRequest
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          DownloadProtectionService::CheckClientDownloadRequest,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::DeleteOnUIThread>,
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      public net::URLFetcherDelegate,
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      public content::DownloadItem::Observer {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckClientDownloadRequest(
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::DownloadItem* item,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const CheckDownloadCallback& callback,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DownloadProtectionService* service,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      BinaryFeatureExtractor* binary_feature_extractor)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : item_(item),
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_chain_(item->GetUrlChain()),
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        referrer_url_(item->GetReferrerUrl()),
282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        tab_url_(item->GetTabUrl()),
283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        tab_referrer_url_(item->GetTabReferrerUrl()),
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        zipped_executable_(false),
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        callback_(callback),
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        service_(service),
287effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        binary_feature_extractor_(binary_feature_extractor),
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        database_manager_(database_manager),
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pingback_enabled_(service_->enabled()),
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        finished_(false),
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        type_(ClientDownloadRequest::WIN_EXECUTABLE),
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        weakptr_factory_(this),
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_time_(base::TimeTicks::Now()) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item_->AddObserver(this);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(2) << "Starting SafeBrowsing download check for: "
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            << item_->DebugString(true);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(noelutz): implement some cache to make sure we don't issue the same
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // request over and over again if a user downloads the same binary multiple
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // times.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadCheckResultReason reason = REASON_MAX;
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!IsSupportedDownload(
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *item_, item_->GetTargetFilePath(), &reason, &type_)) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (reason) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case REASON_EMPTY_URL_CHAIN:
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case REASON_INVALID_URL:
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          PostFinishTask(SAFE, reason);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case REASON_NOT_BINARY_FILE:
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          RecordFileExtensionType(item_->GetTargetFilePath());
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          PostFinishTask(SAFE, reason);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // We only expect the reasons explicitly handled above.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NOTREACHED();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordFileExtensionType(item_->GetTargetFilePath());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compute features from the file contents. Note that we record histograms
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // based on the result, so this runs regardless of whether the pingbacks
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // are enabled.
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (item_->GetTargetFilePath().MatchesExtension(
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FILE_PATH_LITERAL(".zip"))) {
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StartExtractZipFeatures();
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(!download_protection_util::IsArchiveFile(
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          item_->GetTargetFilePath()));
335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      StartExtractFileFeatures();
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start a timeout to cancel the request if it takes too long.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This should only be called after we have finished accessing the file.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StartTimeout() {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!service_) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Request has already been cancelled.
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
34746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    timeout_start_time_ = base::TimeTicks::Now();
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostDelayedTask(
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CheckClientDownloadRequest::Cancel,
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   weakptr_factory_.GetWeakPtr()),
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            service_->download_request_timeout_ms()));
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Canceling a request will cause us to always report the result as SAFE
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unless a pending request is about to call FinishRequest.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fetcher_.get()) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The DownloadProtectionService is going to release its reference, so we
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // might be destroyed before the URLFetcher completes.  Cancel the
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // fetcher so it does not try to invoke OnURLFetchComplete.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fetcher_.reset();
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: If there is no fetcher, then some callback is still holding a
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reference to this object.  We'll eventually wind up in some method on
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the UI thread that will call FinishRequest() again.  If FinishRequest()
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is called a second time, it will be a no-op.
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    FinishRequest(SAFE, REASON_REQUEST_CANCELED);
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Calling FinishRequest might delete this object, we may be deleted by
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // this point.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // content::DownloadItem::Observer implementation.
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE {
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Cancel();
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(item_ == NULL);
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // From the net::URLFetcherDelegate interface.
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(source, fetcher_.get());
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(2) << "Received a response for URL: "
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            << item_->GetUrlChain().back() << ": success="
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << source->GetStatus().is_success() << " response_code="
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << source->GetResponseCode();
39058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    if (source->GetStatus().is_success()) {
39158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      UMA_HISTOGRAM_SPARSE_SLOWLY(
39258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch          "SBClientDownload.DownloadRequestResponseCode",
39358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch          source->GetResponseCode());
39458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    }
39558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    UMA_HISTOGRAM_SPARSE_SLOWLY(
39658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch        "SBClientDownload.DownloadRequestNetError",
39758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch        -source->GetStatus().error());
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadCheckResultReason reason = REASON_SERVER_PING_FAILED;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadCheckResult result = SAFE;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (source->GetStatus().is_success() &&
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net::HTTP_OK == source->GetResponseCode()) {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientDownloadResponse response;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string data;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool got_data = source->GetResponseAsString(&data);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(got_data);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!response.ParseFromString(data)) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reason = REASON_INVALID_RESPONSE_PROTO;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (response.verdict() == ClientDownloadResponse::SAFE) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reason = REASON_DOWNLOAD_SAFE;
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (service_ && !service_->IsSupportedDownload(
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *item_, item_->GetTargetFilePath())) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The client of the download protection service assumes that we don't
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // support this download so we cannot return any other verdict than
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // SAFE even if the server says it's dangerous to download this file.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Note: if service_ is NULL we already cancelled the request and
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // returned SAFE.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reason = REASON_DOWNLOAD_NOT_SUPPORTED;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (response.verdict() == ClientDownloadResponse::DANGEROUS) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reason = REASON_DOWNLOAD_DANGEROUS;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result = DANGEROUS;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (response.verdict() == ClientDownloadResponse::UNCOMMON) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reason = REASON_DOWNLOAD_UNCOMMON;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result = UNCOMMON;
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (response.verdict() == ClientDownloadResponse::DANGEROUS_HOST) {
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        reason = REASON_DOWNLOAD_DANGEROUS_HOST;
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result = DANGEROUS_HOST;
427a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      } else if (
428a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch          response.verdict() == ClientDownloadResponse::POTENTIALLY_UNWANTED) {
429a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch        reason = REASON_DOWNLOAD_POTENTIALLY_UNWANTED;
430a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch        result = POTENTIALLY_UNWANTED;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(DFATAL) << "Unknown download response verdict: "
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    << response.verdict();
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reason = REASON_INVALID_RESPONSE_VERDICT;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DownloadFeedbackService::MaybeStorePingsForDownload(
4377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          result, item_, client_download_request_data_, data);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't need the fetcher anymore.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_.reset();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestDuration",
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        base::TimeTicks::Now() - start_time_);
44346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestNetworkDuration",
44446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        base::TimeTicks::Now() - request_start_time_);
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FinishRequest(result, reason);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool IsSupportedDownload(const content::DownloadItem& item,
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  const base::FilePath& target_path,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  DownloadCheckResultReason* reason,
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  ClientDownloadRequest::DownloadType* type) {
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (item.GetUrlChain().empty()) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *reason = REASON_EMPTY_URL_CHAIN;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& final_url = item.GetUrlChain().back();
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!final_url.is_valid() || final_url.is_empty() ||
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !final_url.IsStandard() || final_url.SchemeIsFile()) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *reason = REASON_INVALID_URL;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!download_protection_util::IsBinaryFile(target_path)) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *reason = REASON_NOT_BINARY_FILE;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
466bee9932bab44713b74b422b4b759b49f5a222977Bo Liu    *type = download_protection_util::GetDownloadType(target_path);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::DeleteHelper<CheckClientDownloadRequest>;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~CheckClientDownloadRequest() {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(item_ == NULL);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnFileFeatureExtractionDone() {
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // This can run in any thread, since it just posts more messages.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(noelutz): DownloadInfo should also contain the IP address of
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // every URL in the redirect chain.  We also should check whether the
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // download URL is hosted on the internal network.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::IO,
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this));
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We wait until after the file checks finish to start the timeout, as
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // windows can cause permissions errors if the timeout fired while we were
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // checking the file signature and we tried to complete the download.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI,
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CheckClientDownloadRequest::StartTimeout, this));
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
499effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void StartExtractFileFeatures() {
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(item_);  // Called directly from Start(), item should still exist.
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Since we do blocking I/O, offload this to a worker thread.
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The task does not need to block shutdown.
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
506effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::Bind(&CheckClientDownloadRequest::ExtractFileFeatures,
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this, item_->GetFullPath()),
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
511effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void ExtractFileFeatures(const base::FilePath& file_path) {
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeTicks start_time = base::TimeTicks::Now();
513effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    binary_feature_extractor_->CheckSignature(file_path, &signature_info_);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_signed = (signature_info_.certificate_chain_size() > 0);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_signed) {
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(2) << "Downloaded a signed binary: " << file_path.value();
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(2) << "Downloaded an unsigned binary: "
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              << file_path.value();
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractSignatureFeaturesTime",
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        base::TimeTicks::Now() - start_time);
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
525effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    start_time = base::TimeTicks::Now();
526effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    binary_feature_extractor_->ExtractImageHeaders(file_path, &image_headers_);
527effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractImageHeadersTime",
528effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        base::TimeTicks::Now() - start_time);
529effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnFileFeatureExtractionDone();
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StartExtractZipFeatures() {
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(item_);  // Called directly from Start(), item should still exist.
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    zip_analysis_start_time_ = base::TimeTicks::Now();
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We give the zip analyzer a weak pointer to this object.  Since the
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // analyzer is refcounted, it might outlive the request.
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    analyzer_ = new SandboxedZipAnalyzer(
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        item_->GetFullPath(),
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&CheckClientDownloadRequest::OnZipAnalysisFinished,
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   weakptr_factory_.GetWeakPtr()));
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    analyzer_->Start();
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnZipAnalysisFinished(const zip_analyzer::Results& results) {
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!service_)
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (results.success) {
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      zipped_executable_ = results.has_executable;
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(1) << "Zip analysis finished for " << item_->GetFullPath().value()
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              << ", has_executable=" << results.has_executable
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              << " has_archive=" << results.has_archive;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(1) << "Zip analysis failed for " << item_->GetFullPath().value();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable",
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          zipped_executable_);
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable",
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          results.has_archive && !zipped_executable_);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime",
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        base::TimeTicks::Now() - zip_analysis_start_time_);
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!zipped_executable_) {
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PostFinishTask(SAFE, REASON_ARCHIVE_WITHOUT_BINARIES);
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnFileFeatureExtractionDone();
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckWhitelists() {
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadCheckResultReason reason = REASON_MAX;
575868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!database_manager_.get()) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reason = REASON_SB_DISABLED;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const GURL& url = url_chain_.back();
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (url.is_valid() && database_manager_->MatchDownloadWhitelistUrl(url)) {
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        VLOG(2) << url << " is on the download whitelist.";
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reason = REASON_WHITELISTED_URL;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (reason != REASON_MAX || signature_info_.trusted()) {
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reason == REASON_MAX && signature_info_.trusted()) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int i = 0; i < signature_info_.certificate_chain_size(); ++i) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (CertificateChainIsWhitelisted(
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                signature_info_.certificate_chain(i))) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reason = REASON_TRUSTED_EXECUTABLE;
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reason != REASON_MAX) {
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PostFinishTask(SAFE, reason);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (!pingback_enabled_) {
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PostFinishTask(SAFE, REASON_PING_DISABLED);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Currently, the UI only works on Windows so we don't even bother
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // with pinging the server if we're not on Windows.  TODO(noelutz):
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // change this code once the UI is done for Linux and Mac.
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The URLFetcher is owned by the UI thread, so post a message to
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // start the pingback.
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::UI,
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
610effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          base::Bind(&CheckClientDownloadRequest::GetTabRedirects, this));
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PostFinishTask(SAFE, REASON_OS_NOT_SUPPORTED);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
617effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void GetTabRedirects() {
618effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
619effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!tab_url_.is_valid()) {
620effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      SendRequest();
621effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return;
622effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
623effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
624effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    Profile* profile = Profile::FromBrowserContext(item_->GetBrowserContext());
625effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    HistoryService* history =
626effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
627effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!history) {
628effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      SendRequest();
629effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return;
630effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
631effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
632effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    history->QueryRedirectsTo(
633effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        tab_url_,
634effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        &request_consumer_,
635effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::Bind(&CheckClientDownloadRequest::OnGotTabRedirects,
636effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                   base::Unretained(this)));
637effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
638effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
639effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void OnGotTabRedirects(HistoryService::Handle handle,
640effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         GURL url,
641effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         bool success,
642effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         history::RedirectList* redirect_list) {
643effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
644effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_EQ(url, tab_url_);
645effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
646effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (success && redirect_list->size() > 0) {
647effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      for (history::RedirectList::reverse_iterator i = redirect_list->rbegin();
648effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           i != redirect_list->rend();
649effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           ++i) {
650effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        tab_redirects_.push_back(*i);
651effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
652effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
653effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
654effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    SendRequest();
655effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SendRequest() {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is our last chance to check whether the request has been canceled
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // before sending it.
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!service_)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientDownloadRequest request;
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.set_url(item_->GetUrlChain().back().spec());
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.mutable_digests()->set_sha256(item_->GetHash());
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.set_length(item_->GetReceivedBytes());
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < item_->GetUrlChain().size(); ++i) {
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientDownloadRequest::Resource* resource = request.add_resources();
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource->set_url(item_->GetUrlChain()[i].spec());
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (i == item_->GetUrlChain().size() - 1) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The last URL in the chain is the download URL.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        resource->set_type(ClientDownloadRequest::DOWNLOAD_URL);
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        resource->set_referrer(item_->GetReferrerUrl().spec());
676effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        DVLOG(2) << "dl url " << resource->url();
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (!item_->GetRemoteAddress().empty()) {
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource->set_remote_ip(item_->GetRemoteAddress());
679effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          DVLOG(2) << "  dl url remote addr: " << resource->remote_ip();
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
681effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        DVLOG(2) << "dl referrer " << resource->referrer();
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
683effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        DVLOG(2) << "dl redirect " << i << " " << resource->url();
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT);
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(noelutz): fill out the remote IP addresses.
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
688effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // TODO(mattm): fill out the remote IP addresses for tab resources.
689effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (size_t i = 0; i < tab_redirects_.size(); ++i) {
690effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ClientDownloadRequest::Resource* resource = request.add_resources();
691effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      DVLOG(2) << "tab redirect " << i << " " << tab_redirects_[i].spec();
692effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      resource->set_url(tab_redirects_[i].spec());
693effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      resource->set_type(ClientDownloadRequest::TAB_REDIRECT);
694effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
695effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (tab_url_.is_valid()) {
696effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ClientDownloadRequest::Resource* resource = request.add_resources();
697effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      resource->set_url(tab_url_.spec());
698effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      DVLOG(2) << "tab url " << resource->url();
699effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      resource->set_type(ClientDownloadRequest::TAB_URL);
700effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (tab_referrer_url_.is_valid()) {
701effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        resource->set_referrer(tab_referrer_url_.spec());
702effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        DVLOG(2) << "tab referrer " << resource->referrer();
703effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
704effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
705effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.set_user_initiated(item_->HasUserGesture());
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.set_file_basename(
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        item_->GetTargetFilePath().BaseName().AsUTF8Unsafe());
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request.set_download_type(type_);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request.mutable_signature()->CopyFrom(signature_info_);
711effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    request.mutable_image_headers()->CopyFrom(image_headers_);
7127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!request.SerializeToString(&client_download_request_data_)) {
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FinishRequest(SAFE, REASON_INVALID_REQUEST_PROTO);
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(2) << "Sending a request for URL: "
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            << item_->GetUrlChain().back();
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */,
7204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           GetDownloadRequestUrl(),
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           net::URLFetcher::POST,
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           this));
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_->SetAutomaticallyRetryOn5xx(false);  // Don't retry on error.
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_->SetRequestContext(service_->request_context_getter_.get());
7267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    fetcher_->SetUploadData("application/octet-stream",
7277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                            client_download_request_data_);
72846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    request_start_time_ = base::TimeTicks::Now();
729a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("SBClientDownload.DownloadRequestPayloadSize",
730a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                         client_download_request_data_.size());
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_->Start();
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void PostFinishTask(DownloadCheckResult result,
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      DownloadCheckResultReason reason) {
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI,
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result,
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   reason));
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void FinishRequest(DownloadCheckResult result,
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     DownloadCheckResultReason reason) {
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (finished_) {
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    finished_ = true;
75090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Ensure the timeout task is cancelled while we still have a non-zero
75190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // refcount. (crbug.com/240449)
75290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    weakptr_factory_.InvalidateWeakPtrs();
75346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!request_start_time_.is_null()) {
75446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("SBClientDownload.DownloadRequestNetworkStats",
75546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                reason,
75646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                REASON_MAX);
75746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
75846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!timeout_start_time_.is_null()) {
75946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("SBClientDownload.DownloadRequestTimeoutStats",
76046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                reason,
76146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                REASON_MAX);
76246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (reason != REASON_REQUEST_CANCELED) {
76346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestTimeoutDuration",
76446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                            base::TimeTicks::Now() - timeout_start_time_);
76546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
76646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (service_) {
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(2) << "SafeBrowsing download verdict for: "
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              << item_->DebugString(true) << " verdict:" << reason;
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats",
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                reason,
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                REASON_MAX);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_.Run(result);
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item_->RemoveObserver(this);
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item_ = NULL;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadProtectionService* service = service_;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_ = NULL;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service->RequestFinished(this);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // DownloadProtectionService::RequestFinished will decrement our refcount,
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // so we may be deleted now.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_.Run(SAFE);
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CertificateChainIsWhitelisted(
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ClientDownloadRequest_CertificateChain& chain) {
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chain.element_size() < 2) {
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We need to have both a signing certificate and its issuer certificate
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // present to construct a whitelist entry.
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<net::X509Certificate> cert =
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net::X509Certificate::CreateFromBytes(
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            chain.element(0).certificate().data(),
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            chain.element(0).certificate().size());
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!cert.get()) {
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 1; i < chain.element_size(); ++i) {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<net::X509Certificate> issuer =
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          net::X509Certificate::CreateFromBytes(
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              chain.element(i).certificate().data(),
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              chain.element(i).certificate().size());
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!issuer.get()) {
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<std::string> whitelist_strings;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DownloadProtectionService::GetCertificateWhitelistStrings(
812868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          *cert.get(), *issuer.get(), &whitelist_strings);
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < whitelist_strings.size(); ++j) {
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (database_manager_->MatchDownloadWhitelistString(
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                whitelist_strings[j])) {
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          VLOG(2) << "Certificate matched whitelist, cert="
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << cert->subject().GetDisplayName()
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << " issuer=" << issuer->subject().GetDisplayName();
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return true;
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cert = issuer;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The DownloadItem we are checking. Will be NULL if the request has been
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // canceled. Must be accessed only on UI thread.
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::DownloadItem* item_;
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copies of data from |item_| for access on other threads.
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<GURL> url_chain_;
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL referrer_url_;
833effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // URL chain of redirects leading to (but not including) |tab_url|.
834effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<GURL> tab_redirects_;
835effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // URL and referrer of the window the download was started from.
836effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  GURL tab_url_;
837effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  GURL tab_referrer_url_;
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool zipped_executable_;
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientDownloadRequest_SignatureInfo signature_info_;
841effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ClientDownloadRequest_ImageHeaders image_headers_;
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckDownloadCallback callback_;
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be NULL if the request has been canceled.
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadProtectionService* service_;
845effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_;
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool pingback_enabled_;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::URLFetcher> fetcher_;
8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<SandboxedZipAnalyzer> analyzer_;
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks zip_analysis_start_time_;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool finished_;
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientDownloadRequest::DownloadType type_;
8537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string client_download_request_data_;
854effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CancelableRequestConsumer request_consumer_;  // For HistoryService lookup.
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtrFactory<CheckClientDownloadRequest> weakptr_factory_;
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start_time_;  // Used for stats.
85746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks timeout_start_time_;
85846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks request_start_time_;
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest);
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadProtectionService::DownloadProtectionService(
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SafeBrowsingService* sb_service,
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequestContextGetter* request_context_getter)
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : request_context_getter_(request_context_getter),
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enabled_(false),
868effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      binary_feature_extractor_(new BinaryFeatureExtractor()),
8697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      download_request_timeout_ms_(kDownloadRequestTimeoutMs),
8707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      feedback_service_(new DownloadFeedbackService(
8717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          request_context_getter, BrowserThread::GetBlockingPool())) {
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sb_service) {
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_manager_ = sb_service->ui_manager();
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    database_manager_ = sb_service->database_manager();
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadProtectionService::~DownloadProtectionService() {
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingRequests();
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::SetEnabled(bool enabled) {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enabled == enabled_) {
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enabled_ = enabled;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled_) {
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelPendingRequests();
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::CheckClientDownload(
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::DownloadItem* item,
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CheckDownloadCallback& callback) {
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<CheckClientDownloadRequest> request(
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new CheckClientDownloadRequest(item, callback, this,
900effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                     database_manager_,
901effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                     binary_feature_extractor_.get()));
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_requests_.insert(request);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->Start();
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::CheckDownloadUrl(
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::DownloadItem& item,
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CheckDownloadCallback& callback) {
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!item.GetUrlChain().empty());
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<DownloadUrlSBClient> client(
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new DownloadUrlSBClient(item, callback, ui_manager_, database_manager_));
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The client will release itself once it is done.
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::IO,
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadUrlSBClient::StartCheck, client));
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadProtectionService::IsSupportedDownload(
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::DownloadItem& item,
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& target_path) const {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Currently, the UI only works on Windows.  On Linux and Mac we still
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to show the dangerous file type warning if the file is possibly
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dangerous which means we have to always return false here.
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadCheckResultReason reason = REASON_MAX;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientDownloadRequest::DownloadType type =
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientDownloadRequest::WIN_EXECUTABLE;
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (CheckClientDownloadRequest::IsSupportedDownload(item, target_path,
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                          &reason, &type) &&
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (ClientDownloadRequest::ANDROID_APK == type ||
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           ClientDownloadRequest::WIN_EXECUTABLE == type ||
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           ClientDownloadRequest::ZIPPED_EXECUTABLE == type));
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::CancelPendingRequests() {
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it =
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           download_requests_.begin();
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != download_requests_.end();) {
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to advance the iterator before we cancel because canceling
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the request will invalidate it when RequestFinished is called below.
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<CheckClientDownloadRequest> tmp = *it++;
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tmp->Cancel();
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_requests_.empty());
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::RequestFinished(
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckClientDownloadRequest* request) {
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it =
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_requests_.find(request);
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(it != download_requests_.end());
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_requests_.erase(*it);
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::ShowDetailsForDownload(
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::DownloadItem& item,
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageNavigator* navigator) {
964a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  GURL learn_more_url(chrome::kDownloadScanningLearnMoreURL);
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  navigator->OpenURL(
966a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      content::OpenURLParams(learn_more_url,
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             content::Referrer(),
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NEW_FOREGROUND_TAB,
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             content::PAGE_TRANSITION_LINK,
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             false));
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Escapes a certificate attribute so that it can be used in a whitelist
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// entry.  Currently, we only escape slashes, since they are used as a
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// separator between attributes.
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string EscapeCertAttribute(const std::string& attribute) {
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string escaped;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < attribute.size(); ++i) {
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (attribute[i] == '%') {
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      escaped.append("%25");
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (attribute[i] == '/') {
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      escaped.append("%2F");
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      escaped.push_back(attribute[i]);
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return escaped;
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadProtectionService::GetCertificateWhitelistStrings(
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::X509Certificate& certificate,
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::X509Certificate& issuer,
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* whitelist_strings) {
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The whitelist paths are in the format:
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cert/<ascii issuer fingerprint>[/CN=common_name][/O=org][/OU=unit]
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any of CN, O, or OU may be omitted from the whitelist entry, in which
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // case they match anything.  However, the attributes that do appear will
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // always be in the order shown above.  At least one attribute will always
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be present.
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const net::CertPrincipal& subject = certificate.subject();
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> ou_tokens;
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < subject.organization_unit_names.size(); ++i) {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ou_tokens.push_back(
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "/OU=" + EscapeCertAttribute(subject.organization_unit_names[i]));
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> o_tokens;
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < subject.organization_names.size(); ++i) {
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    o_tokens.push_back(
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "/O=" + EscapeCertAttribute(subject.organization_names[i]));
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string cn_token;
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!subject.common_name.empty()) {
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cn_token = "/CN=" + EscapeCertAttribute(subject.common_name);
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<std::string> paths_to_check;
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cn_token.empty()) {
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_to_check.insert(cn_token);
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < o_tokens.size(); ++i) {
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_to_check.insert(cn_token + o_tokens[i]);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_to_check.insert(o_tokens[i]);
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < ou_tokens.size(); ++j) {
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      paths_to_check.insert(cn_token + o_tokens[i] + ou_tokens[j]);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      paths_to_check.insert(o_tokens[i] + ou_tokens[j]);
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < ou_tokens.size(); ++i) {
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_to_check.insert(cn_token + ou_tokens[i]);
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_to_check.insert(ou_tokens[i]);
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string issuer_fp = base::HexEncode(issuer.fingerprint().data,
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          sizeof(issuer.fingerprint().data));
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<std::string>::iterator it = paths_to_check.begin();
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != paths_to_check.end(); ++it) {
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    whitelist_strings->push_back("cert/" + issuer_fp + *it);
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
10494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GURL DownloadProtectionService::GetDownloadRequestUrl() {
10504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GURL url(kDownloadRequestUrl);
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string api_key = google_apis::GetAPIKey();
10524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!api_key.empty())
10534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    url = url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true));
10544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url;
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace safe_browsing
1059