Home | History | Annotate | Download | only in download
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/download/chrome_download_manager_delegate.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/callback.h"
     13 #include "base/file_util.h"
     14 #include "base/prefs/pref_member.h"
     15 #include "base/prefs/pref_service.h"
     16 #include "base/rand_util.h"
     17 #include "base/strings/stringprintf.h"
     18 #include "base/strings/utf_string_conversions.h"
     19 #include "base/task_runner.h"
     20 #include "base/threading/sequenced_worker_pool.h"
     21 #include "base/time/time.h"
     22 #include "chrome/browser/browser_process.h"
     23 #include "chrome/browser/chrome_notification_types.h"
     24 #include "chrome/browser/download/download_completion_blocker.h"
     25 #include "chrome/browser/download/download_crx_util.h"
     26 #include "chrome/browser/download/download_file_picker.h"
     27 #include "chrome/browser/download/download_history.h"
     28 #include "chrome/browser/download/download_item_model.h"
     29 #include "chrome/browser/download/download_path_reservation_tracker.h"
     30 #include "chrome/browser/download/download_prefs.h"
     31 #include "chrome/browser/download/download_service.h"
     32 #include "chrome/browser/download/download_service_factory.h"
     33 #include "chrome/browser/download/download_stats.h"
     34 #include "chrome/browser/download/download_target_determiner.h"
     35 #include "chrome/browser/download/save_package_file_picker.h"
     36 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
     37 #include "chrome/browser/extensions/crx_installer.h"
     38 #include "chrome/browser/platform_util.h"
     39 #include "chrome/browser/profiles/profile.h"
     40 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     41 #include "chrome/browser/ui/browser.h"
     42 #include "chrome/browser/ui/browser_finder.h"
     43 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
     44 #include "chrome/common/chrome_constants.h"
     45 #include "chrome/common/pref_names.h"
     46 #include "components/user_prefs/pref_registry_syncable.h"
     47 #include "content/public/browser/download_item.h"
     48 #include "content/public/browser/download_manager.h"
     49 #include "content/public/browser/notification_source.h"
     50 #include "content/public/browser/page_navigator.h"
     51 #include "extensions/common/constants.h"
     52 #include "net/base/mime_util.h"
     53 #include "net/base/net_util.h"
     54 
     55 #if defined(OS_CHROMEOS)
     56 #include "chrome/browser/chromeos/drive/download_handler.h"
     57 #include "chrome/browser/chromeos/drive/file_system_util.h"
     58 #endif
     59 
     60 using content::BrowserThread;
     61 using content::DownloadItem;
     62 using content::DownloadManager;
     63 using safe_browsing::DownloadProtectionService;
     64 
     65 namespace {
     66 
     67 #if defined(FULL_SAFE_BROWSING)
     68 
     69 // String pointer used for identifying safebrowing data associated with
     70 // a download item.
     71 const char kSafeBrowsingUserDataKey[] = "Safe Browsing ID";
     72 
     73 // The state of a safebrowsing check.
     74 class SafeBrowsingState : public DownloadCompletionBlocker {
     75  public:
     76   SafeBrowsingState()
     77     : verdict_(DownloadProtectionService::SAFE) {
     78   }
     79 
     80   virtual ~SafeBrowsingState();
     81 
     82   // The verdict that we got from calling CheckClientDownload. Only valid to
     83   // call if |is_complete()|.
     84   DownloadProtectionService::DownloadCheckResult verdict() const {
     85     return verdict_;
     86   }
     87 
     88   void SetVerdict(DownloadProtectionService::DownloadCheckResult result) {
     89     verdict_ = result;
     90     CompleteDownload();
     91   }
     92 
     93  private:
     94   DownloadProtectionService::DownloadCheckResult verdict_;
     95 
     96   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingState);
     97 };
     98 
     99 SafeBrowsingState::~SafeBrowsingState() {}
    100 
    101 #endif  // FULL_SAFE_BROWSING
    102 
    103 // Used with GetPlatformDownloadPath() to indicate which platform path to
    104 // return.
    105 enum PlatformDownloadPathType {
    106   // Return the platform specific target path.
    107   PLATFORM_TARGET_PATH,
    108 
    109   // Return the platform specific current path. If the download is in-progress
    110   // and the download location is a local filesystem path, then
    111   // GetPlatformDownloadPath will return the path to the intermediate file.
    112   PLATFORM_CURRENT_PATH
    113 };
    114 
    115 // Returns a path in the form that that is expected by platform_util::OpenItem /
    116 // platform_util::ShowItemInFolder / DownloadTargetDeterminer.
    117 //
    118 // DownloadItems corresponding to Drive downloads use a temporary file as the
    119 // target path. The paths returned by DownloadItem::GetFullPath() /
    120 // GetTargetFilePath() refer to this temporary file. This function looks up the
    121 // corresponding path in Drive for these downloads.
    122 //
    123 // How the platform path is determined is based on PlatformDownloadPathType.
    124 base::FilePath GetPlatformDownloadPath(Profile* profile,
    125                                        const DownloadItem* download,
    126                                        PlatformDownloadPathType path_type) {
    127 #if defined(OS_CHROMEOS)
    128   // Drive downloads always return the target path for all types.
    129   drive::DownloadHandler* drive_download_handler =
    130       drive::DownloadHandler::GetForProfile(profile);
    131   if (drive_download_handler &&
    132       drive_download_handler->IsDriveDownload(download))
    133     return drive_download_handler->GetTargetPath(download);
    134 #endif
    135 
    136   if (path_type == PLATFORM_TARGET_PATH)
    137     return download->GetTargetFilePath();
    138   return download->GetFullPath();
    139 }
    140 
    141 #if defined(FULL_SAFE_BROWSING)
    142 // Callback invoked by DownloadProtectionService::CheckClientDownload.
    143 // |is_content_check_supported| is true if the SB service supports scanning the
    144 // download for malicious content.
    145 // |callback| is invoked with a danger type determined as follows:
    146 //
    147 // Danger type is (in order of preference):
    148 //   * DANGEROUS_URL, if the URL is a known malware site.
    149 //   * MAYBE_DANGEROUS_CONTENT, if the content will be scanned for
    150 //         malware. I.e. |is_content_check_supported| is true.
    151 //   * NOT_DANGEROUS.
    152 void CheckDownloadUrlDone(
    153     const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback& callback,
    154     bool is_content_check_supported,
    155     DownloadProtectionService::DownloadCheckResult result) {
    156   content::DownloadDangerType danger_type;
    157   if (result == DownloadProtectionService::SAFE) {
    158     // If this type of files is handled by the enhanced SafeBrowsing download
    159     // protection, mark it as potentially dangerous content until we are done
    160     // with scanning it.
    161     if (is_content_check_supported)
    162       danger_type = content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT;
    163     else
    164       danger_type = content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
    165   } else {
    166     // If the URL is malicious, we'll use that as the danger type. The results
    167     // of the content check, if one is performed, will be ignored.
    168     danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL;
    169   }
    170   callback.Run(danger_type);
    171 }
    172 
    173 #endif  // FULL_SAFE_BROWSING
    174 
    175 // Called on the blocking pool to determine the MIME type for |path|.
    176 void GetMimeTypeAndReplyOnUIThread(
    177     const base::FilePath& path,
    178     const base::Callback<void(const std::string&)>& callback) {
    179   std::string mime_type;
    180   net::GetMimeTypeFromFile(path, &mime_type);
    181   BrowserThread::PostTask(
    182       BrowserThread::UI, FROM_HERE, base::Bind(callback, mime_type));
    183 }
    184 
    185 bool IsOpenInBrowserPreferreredForFile(const base::FilePath& path) {
    186   // On Android, always prefer opening with an external app. On ChromeOS, there
    187   // are no external apps so just allow all opens to be handled by the "System."
    188 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && defined(ENABLE_PLUGINS)
    189   // TODO(asanka): Consider other file types and MIME types.
    190   // http://crbug.com/323561
    191   if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf")) ||
    192       path.MatchesExtension(FILE_PATH_LITERAL(".htm")) ||
    193       path.MatchesExtension(FILE_PATH_LITERAL(".html")) ||
    194       path.MatchesExtension(FILE_PATH_LITERAL(".shtm")) ||
    195       path.MatchesExtension(FILE_PATH_LITERAL(".shtml")) ||
    196       path.MatchesExtension(FILE_PATH_LITERAL(".svg")) ||
    197       path.MatchesExtension(FILE_PATH_LITERAL(".xht")) ||
    198       path.MatchesExtension(FILE_PATH_LITERAL(".xhtm")) ||
    199       path.MatchesExtension(FILE_PATH_LITERAL(".xhtml")) ||
    200       path.MatchesExtension(FILE_PATH_LITERAL(".xml")) ||
    201       path.MatchesExtension(FILE_PATH_LITERAL(".xsl")) ||
    202       path.MatchesExtension(FILE_PATH_LITERAL(".xslt"))) {
    203     return true;
    204   }
    205 #endif
    206   return false;
    207 }
    208 
    209 }  // namespace
    210 
    211 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile)
    212     : profile_(profile),
    213       next_download_id_(content::DownloadItem::kInvalidId),
    214       download_prefs_(new DownloadPrefs(profile)),
    215       weak_ptr_factory_(this) {
    216 }
    217 
    218 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
    219   // If a DownloadManager was set for this, Shutdown() must be called.
    220   DCHECK(!download_manager_);
    221 }
    222 
    223 void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
    224   download_manager_ = dm;
    225 }
    226 
    227 void ChromeDownloadManagerDelegate::Shutdown() {
    228   download_prefs_.reset();
    229   weak_ptr_factory_.InvalidateWeakPtrs();
    230   download_manager_ = NULL;
    231 }
    232 
    233 content::DownloadIdCallback
    234 ChromeDownloadManagerDelegate::GetDownloadIdReceiverCallback() {
    235   return base::Bind(&ChromeDownloadManagerDelegate::SetNextId,
    236                     weak_ptr_factory_.GetWeakPtr());
    237 }
    238 
    239 void ChromeDownloadManagerDelegate::SetNextId(uint32 next_id) {
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    241   DCHECK(!profile_->IsOffTheRecord());
    242   DCHECK_NE(content::DownloadItem::kInvalidId, next_id);
    243   next_download_id_ = next_id;
    244 
    245   IdCallbackVector callbacks;
    246   id_callbacks_.swap(callbacks);
    247   for (IdCallbackVector::const_iterator it = callbacks.begin();
    248        it != callbacks.end(); ++it) {
    249     ReturnNextId(*it);
    250   }
    251 }
    252 
    253 void ChromeDownloadManagerDelegate::GetNextId(
    254     const content::DownloadIdCallback& callback) {
    255   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    256   if (profile_->IsOffTheRecord()) {
    257     content::BrowserContext::GetDownloadManager(
    258         profile_->GetOriginalProfile())->GetDelegate()->GetNextId(callback);
    259     return;
    260   }
    261   if (next_download_id_ == content::DownloadItem::kInvalidId) {
    262     id_callbacks_.push_back(callback);
    263     return;
    264   }
    265   ReturnNextId(callback);
    266 }
    267 
    268 void ChromeDownloadManagerDelegate::ReturnNextId(
    269     const content::DownloadIdCallback& callback) {
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    271   DCHECK(!profile_->IsOffTheRecord());
    272   DCHECK_NE(content::DownloadItem::kInvalidId, next_download_id_);
    273   callback.Run(next_download_id_++);
    274 }
    275 
    276 bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
    277     DownloadItem* download,
    278     const content::DownloadTargetCallback& callback) {
    279   DownloadTargetDeterminer::CompletionCallback target_determined_callback =
    280       base::Bind(&ChromeDownloadManagerDelegate::OnDownloadTargetDetermined,
    281                  weak_ptr_factory_.GetWeakPtr(),
    282                  download->GetId(),
    283                  callback);
    284   DownloadTargetDeterminer::Start(
    285       download,
    286       GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH),
    287       download_prefs_.get(),
    288       this,
    289       target_determined_callback);
    290   return true;
    291 }
    292 
    293 bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension(
    294     const base::FilePath& path) {
    295   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    296   if (path.Extension().empty())
    297     return false;
    298   // TODO(asanka): This determination is done based on |path|, while
    299   // ShouldOpenDownload() detects extension downloads based on the
    300   // characteristics of the download. Reconcile this. http://crbug.com/167702
    301   if (path.MatchesExtension(extensions::kExtensionFileExtension))
    302     return false;
    303   return download_prefs_->IsAutoOpenEnabledBasedOnExtension(path);
    304 }
    305 
    306 // static
    307 void ChromeDownloadManagerDelegate::DisableSafeBrowsing(DownloadItem* item) {
    308   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    309 #if defined(FULL_SAFE_BROWSING)
    310   SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
    311       item->GetUserData(&kSafeBrowsingUserDataKey));
    312   if (!state) {
    313     state = new SafeBrowsingState();
    314     item->SetUserData(&kSafeBrowsingUserDataKey, state);
    315   }
    316   state->SetVerdict(DownloadProtectionService::SAFE);
    317 #endif
    318 }
    319 
    320 bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion(
    321     DownloadItem* item,
    322     const base::Closure& internal_complete_callback) {
    323   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    324 #if defined(FULL_SAFE_BROWSING)
    325   SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
    326       item->GetUserData(&kSafeBrowsingUserDataKey));
    327   if (!state) {
    328     // Begin the safe browsing download protection check.
    329     DownloadProtectionService* service = GetDownloadProtectionService();
    330     if (service) {
    331       VLOG(2) << __FUNCTION__ << "() Start SB download check for download = "
    332               << item->DebugString(false);
    333       state = new SafeBrowsingState();
    334       state->set_callback(internal_complete_callback);
    335       item->SetUserData(&kSafeBrowsingUserDataKey, state);
    336       service->CheckClientDownload(
    337           item,
    338           base::Bind(
    339               &ChromeDownloadManagerDelegate::CheckClientDownloadDone,
    340               weak_ptr_factory_.GetWeakPtr(),
    341               item->GetId()));
    342       return false;
    343     }
    344   } else if (!state->is_complete()) {
    345     // Don't complete the download until we have an answer.
    346     state->set_callback(internal_complete_callback);
    347     return false;
    348   }
    349 #endif
    350   return true;
    351 }
    352 
    353 void ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal(
    354     uint32 download_id,
    355     const base::Closure& user_complete_callback) {
    356   DownloadItem* item = download_manager_->GetDownload(download_id);
    357   if (!item)
    358     return;
    359   if (ShouldCompleteDownload(item, user_complete_callback))
    360     user_complete_callback.Run();
    361 }
    362 
    363 bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(
    364     DownloadItem* item,
    365     const base::Closure& user_complete_callback) {
    366   return IsDownloadReadyForCompletion(item, base::Bind(
    367       &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal,
    368       weak_ptr_factory_.GetWeakPtr(), item->GetId(), user_complete_callback));
    369 }
    370 
    371 bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
    372     DownloadItem* item, const content::DownloadOpenDelayedCallback& callback) {
    373   if (download_crx_util::IsExtensionDownload(*item)) {
    374     scoped_refptr<extensions::CrxInstaller> crx_installer =
    375         download_crx_util::OpenChromeExtension(profile_, *item);
    376 
    377     // CRX_INSTALLER_DONE will fire when the install completes.  At that
    378     // time, Observe() will call the passed callback.
    379     registrar_.Add(
    380         this,
    381         chrome::NOTIFICATION_CRX_INSTALLER_DONE,
    382         content::Source<extensions::CrxInstaller>(crx_installer.get()));
    383 
    384     crx_installers_[crx_installer.get()] = callback;
    385     // The status text and percent complete indicator will change now
    386     // that we are installing a CRX.  Update observers so that they pick
    387     // up the change.
    388     item->UpdateObservers();
    389     return false;
    390   }
    391 
    392   return true;
    393 }
    394 
    395 bool ChromeDownloadManagerDelegate::GenerateFileHash() {
    396 #if defined(FULL_SAFE_BROWSING)
    397   return profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled) &&
    398       g_browser_process->safe_browsing_service()->DownloadBinHashNeeded();
    399 #else
    400   return false;
    401 #endif
    402 }
    403 
    404 void ChromeDownloadManagerDelegate::GetSaveDir(
    405     content::BrowserContext* browser_context,
    406     base::FilePath* website_save_dir,
    407     base::FilePath* download_save_dir,
    408     bool* skip_dir_check) {
    409   *website_save_dir = download_prefs_->SaveFilePath();
    410   DCHECK(!website_save_dir->empty());
    411   *download_save_dir = download_prefs_->DownloadPath();
    412   *skip_dir_check = false;
    413 #if defined(OS_CHROMEOS)
    414   *skip_dir_check = drive::util::IsUnderDriveMountPoint(*website_save_dir);
    415 #endif
    416 }
    417 
    418 void ChromeDownloadManagerDelegate::ChooseSavePath(
    419     content::WebContents* web_contents,
    420     const base::FilePath& suggested_path,
    421     const base::FilePath::StringType& default_extension,
    422     bool can_save_as_complete,
    423     const content::SavePackagePathPickedCallback& callback) {
    424   // Deletes itself.
    425   new SavePackageFilePicker(
    426       web_contents,
    427       suggested_path,
    428       default_extension,
    429       can_save_as_complete,
    430       download_prefs_.get(),
    431       callback);
    432 }
    433 
    434 void ChromeDownloadManagerDelegate::OpenDownloadUsingPlatformHandler(
    435     DownloadItem* download) {
    436   base::FilePath platform_path(
    437       GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH));
    438   DCHECK(!platform_path.empty());
    439   platform_util::OpenItem(profile_, platform_path);
    440 }
    441 
    442 void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem* download) {
    443   DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
    444   DCHECK(!download->GetTargetFilePath().empty());
    445   if (!download->CanOpenDownload())
    446     return;
    447 
    448   if (!DownloadItemModel(download).ShouldPreferOpeningInBrowser()) {
    449     RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_DEFAULT_PLATFORM);
    450     OpenDownloadUsingPlatformHandler(download);
    451     return;
    452   }
    453 
    454 #if !defined(OS_ANDROID)
    455   content::WebContents* web_contents = download->GetWebContents();
    456   Browser* browser =
    457       web_contents ? chrome::FindBrowserWithWebContents(web_contents) : NULL;
    458   scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> browser_displayer;
    459   if (!browser ||
    460       !browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
    461     browser_displayer.reset(new chrome::ScopedTabbedBrowserDisplayer(
    462         profile_, chrome::GetActiveDesktop()));
    463     browser = browser_displayer->browser();
    464   }
    465   content::OpenURLParams params(
    466       net::FilePathToFileURL(download->GetTargetFilePath()),
    467       content::Referrer(),
    468       NEW_FOREGROUND_TAB,
    469       content::PAGE_TRANSITION_LINK,
    470       false);
    471   browser->OpenURL(params);
    472   RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_DEFAULT_BROWSER);
    473 #else
    474   // ShouldPreferOpeningInBrowser() should never be true on Android.
    475   NOTREACHED();
    476 #endif
    477 }
    478 
    479 void ChromeDownloadManagerDelegate::ShowDownloadInShell(
    480     DownloadItem* download) {
    481   if (!download->CanShowInFolder())
    482     return;
    483   base::FilePath platform_path(
    484       GetPlatformDownloadPath(profile_, download, PLATFORM_CURRENT_PATH));
    485   DCHECK(!platform_path.empty());
    486   platform_util::ShowItemInFolder(profile_, platform_path);
    487 }
    488 
    489 void ChromeDownloadManagerDelegate::CheckForFileExistence(
    490     DownloadItem* download,
    491     const content::CheckForFileExistenceCallback& callback) {
    492 #if defined(OS_CHROMEOS)
    493   drive::DownloadHandler* drive_download_handler =
    494       drive::DownloadHandler::GetForProfile(profile_);
    495   if (drive_download_handler &&
    496       drive_download_handler->IsDriveDownload(download)) {
    497     drive_download_handler->CheckForFileExistence(download, callback);
    498     return;
    499   }
    500 #endif
    501   static const char kSequenceToken[] = "ChromeDMD-FileExistenceChecker";
    502   base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
    503   scoped_refptr<base::SequencedTaskRunner> task_runner =
    504       worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
    505           worker_pool->GetNamedSequenceToken(kSequenceToken),
    506           base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    507   base::PostTaskAndReplyWithResult(
    508       task_runner.get(),
    509       FROM_HERE,
    510       base::Bind(&base::PathExists, download->GetTargetFilePath()),
    511       callback);
    512 }
    513 
    514 std::string
    515 ChromeDownloadManagerDelegate::ApplicationClientIdForFileScanning() const {
    516   return std::string(chrome::kApplicationClientIDStringForAVScanning);
    517 }
    518 
    519 DownloadProtectionService*
    520     ChromeDownloadManagerDelegate::GetDownloadProtectionService() {
    521   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    522 #if defined(FULL_SAFE_BROWSING)
    523   SafeBrowsingService* sb_service = g_browser_process->safe_browsing_service();
    524   if (sb_service && sb_service->download_protection_service() &&
    525       profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
    526     return sb_service->download_protection_service();
    527   }
    528 #endif
    529   return NULL;
    530 }
    531 
    532 void ChromeDownloadManagerDelegate::NotifyExtensions(
    533     DownloadItem* download,
    534     const base::FilePath& virtual_path,
    535     const NotifyExtensionsCallback& callback) {
    536   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    537 #if !defined(OS_ANDROID)
    538   ExtensionDownloadsEventRouter* router =
    539       DownloadServiceFactory::GetForBrowserContext(profile_)->
    540       GetExtensionEventRouter();
    541   if (router) {
    542     base::Closure original_path_callback =
    543         base::Bind(callback, base::FilePath(),
    544                    DownloadPathReservationTracker::UNIQUIFY);
    545     router->OnDeterminingFilename(download, virtual_path.BaseName(),
    546                                   original_path_callback,
    547                                   callback);
    548     return;
    549   }
    550 #endif
    551   callback.Run(base::FilePath(), DownloadPathReservationTracker::UNIQUIFY);
    552 }
    553 
    554 void ChromeDownloadManagerDelegate::ReserveVirtualPath(
    555     content::DownloadItem* download,
    556     const base::FilePath& virtual_path,
    557     bool create_directory,
    558     DownloadPathReservationTracker::FilenameConflictAction conflict_action,
    559     const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) {
    560   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    561   DCHECK(!virtual_path.empty());
    562 #if defined(OS_CHROMEOS)
    563   // TODO(asanka): Handle path reservations for virtual paths as well.
    564   //               http://crbug.com/151618
    565   if (drive::util::IsUnderDriveMountPoint(virtual_path)) {
    566     callback.Run(virtual_path, true);
    567     return;
    568   }
    569 #endif
    570   DownloadPathReservationTracker::GetReservedPath(
    571       download,
    572       virtual_path,
    573       download_prefs_->DownloadPath(),
    574       create_directory,
    575       conflict_action,
    576       callback);
    577 }
    578 
    579 void ChromeDownloadManagerDelegate::PromptUserForDownloadPath(
    580     DownloadItem* download,
    581     const base::FilePath& suggested_path,
    582     const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) {
    583   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    584   DownloadFilePicker::ShowFilePicker(download, suggested_path, callback);
    585 }
    586 
    587 void ChromeDownloadManagerDelegate::DetermineLocalPath(
    588     DownloadItem* download,
    589     const base::FilePath& virtual_path,
    590     const DownloadTargetDeterminerDelegate::LocalPathCallback& callback) {
    591   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    592 #if defined(OS_CHROMEOS)
    593   drive::DownloadHandler* drive_download_handler =
    594       drive::DownloadHandler::GetForProfile(profile_);
    595   if (drive_download_handler) {
    596     drive_download_handler->SubstituteDriveDownloadPath(
    597         virtual_path, download, callback);
    598     return;
    599   }
    600 #endif
    601   callback.Run(virtual_path);
    602 }
    603 
    604 void ChromeDownloadManagerDelegate::CheckDownloadUrl(
    605     DownloadItem* download,
    606     const base::FilePath& suggested_path,
    607     const CheckDownloadUrlCallback& callback) {
    608   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    609 
    610 #if defined(FULL_SAFE_BROWSING)
    611   safe_browsing::DownloadProtectionService* service =
    612       GetDownloadProtectionService();
    613   if (service) {
    614     bool is_content_check_supported =
    615         service->IsSupportedDownload(*download, suggested_path);
    616     VLOG(2) << __FUNCTION__ << "() Start SB URL check for download = "
    617             << download->DebugString(false);
    618     service->CheckDownloadUrl(*download,
    619                               base::Bind(&CheckDownloadUrlDone,
    620                                          callback,
    621                                          is_content_check_supported));
    622     return;
    623   }
    624 #endif
    625   callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    626 }
    627 
    628 void ChromeDownloadManagerDelegate::GetFileMimeType(
    629     const base::FilePath& path,
    630     const GetFileMimeTypeCallback& callback) {
    631   BrowserThread::PostBlockingPoolTask(
    632       FROM_HERE,
    633       base::Bind(&GetMimeTypeAndReplyOnUIThread, path, callback));
    634 }
    635 
    636 #if defined(FULL_SAFE_BROWSING)
    637 void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
    638     uint32 download_id,
    639     DownloadProtectionService::DownloadCheckResult result) {
    640   DownloadItem* item = download_manager_->GetDownload(download_id);
    641   if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
    642     return;
    643 
    644   VLOG(2) << __FUNCTION__ << "() download = " << item->DebugString(false)
    645           << " verdict = " << result;
    646   // We only mark the content as being dangerous if the download's safety state
    647   // has not been set to DANGEROUS yet.  We don't want to show two warnings.
    648   if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
    649       item->GetDangerType() ==
    650       content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) {
    651     content::DownloadDangerType danger_type =
    652         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
    653     switch (result) {
    654       case DownloadProtectionService::SAFE:
    655         // Do nothing.
    656         break;
    657       case DownloadProtectionService::DANGEROUS:
    658         danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT;
    659         break;
    660       case DownloadProtectionService::UNCOMMON:
    661         danger_type = content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT;
    662         break;
    663       case DownloadProtectionService::DANGEROUS_HOST:
    664         danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST;
    665         break;
    666       case DownloadProtectionService::POTENTIALLY_UNWANTED:
    667         danger_type = content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED;
    668         break;
    669     }
    670 
    671     if (danger_type != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
    672       item->OnContentCheckCompleted(danger_type);
    673   }
    674 
    675   SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
    676       item->GetUserData(&kSafeBrowsingUserDataKey));
    677   state->SetVerdict(result);
    678 }
    679 #endif  // FULL_SAFE_BROWSING
    680 
    681 // content::NotificationObserver implementation.
    682 void ChromeDownloadManagerDelegate::Observe(
    683     int type,
    684     const content::NotificationSource& source,
    685     const content::NotificationDetails& details) {
    686   DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE);
    687 
    688   registrar_.Remove(this,
    689                     chrome::NOTIFICATION_CRX_INSTALLER_DONE,
    690                     source);
    691 
    692   scoped_refptr<extensions::CrxInstaller> installer =
    693       content::Source<extensions::CrxInstaller>(source).ptr();
    694   content::DownloadOpenDelayedCallback callback =
    695       crx_installers_[installer.get()];
    696   crx_installers_.erase(installer.get());
    697   callback.Run(installer->did_handle_successfully());
    698 }
    699 
    700 void ChromeDownloadManagerDelegate::OnDownloadTargetDetermined(
    701     int32 download_id,
    702     const content::DownloadTargetCallback& callback,
    703     scoped_ptr<DownloadTargetInfo> target_info) {
    704   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    705   DownloadItem* item = download_manager_->GetDownload(download_id);
    706   if (!target_info->target_path.empty() && item &&
    707       IsOpenInBrowserPreferreredForFile(target_info->target_path) &&
    708       target_info->is_filetype_handled_securely)
    709     DownloadItemModel(item).SetShouldPreferOpeningInBrowser(true);
    710   callback.Run(target_info->target_path,
    711                target_info->target_disposition,
    712                target_info->danger_type,
    713                target_info->intermediate_path);
    714 }
    715