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