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
60using content::BrowserThread;
61using content::DownloadItem;
62using content::DownloadManager;
63using safe_browsing::DownloadProtectionService;
64
65namespace {
66
67#if defined(FULL_SAFE_BROWSING)
68
69// String pointer used for identifying safebrowing data associated with
70// a download item.
71const char kSafeBrowsingUserDataKey[] = "Safe Browsing ID";
72
73// The state of a safebrowsing check.
74class 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
99SafeBrowsingState::~SafeBrowsingState() {}
100
101#endif  // FULL_SAFE_BROWSING
102
103// Used with GetPlatformDownloadPath() to indicate which platform path to
104// return.
105enum 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.
124base::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.
152void 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|.
176void 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
185bool 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
211ChromeDownloadManagerDelegate::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
218ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
219  // If a DownloadManager was set for this, Shutdown() must be called.
220  DCHECK(!download_manager_);
221}
222
223void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
224  download_manager_ = dm;
225}
226
227void ChromeDownloadManagerDelegate::Shutdown() {
228  download_prefs_.reset();
229  weak_ptr_factory_.InvalidateWeakPtrs();
230  download_manager_ = NULL;
231}
232
233content::DownloadIdCallback
234ChromeDownloadManagerDelegate::GetDownloadIdReceiverCallback() {
235  return base::Bind(&ChromeDownloadManagerDelegate::SetNextId,
236                    weak_ptr_factory_.GetWeakPtr());
237}
238
239void 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
253void 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
268void 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
276bool 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
293bool 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
307void 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
320bool 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
353void 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
363bool 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
371bool 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
395bool 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
404void 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
418void 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
434void 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
442void 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
479void 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
489void 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
514std::string
515ChromeDownloadManagerDelegate::ApplicationClientIdForFileScanning() const {
516  return std::string(chrome::kApplicationClientIDStringForAVScanning);
517}
518
519DownloadProtectionService*
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
532void 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
554void 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
579void 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
587void 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
604void 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
628void 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)
637void 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.
682void 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
700void 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