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