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.
5 #include "chrome/browser/download/chrome_download_manager_delegate.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/file_util.h"
13 #include "base/prefs/pref_member.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/rand_util.h"
16 #include "base/stringprintf.h"
17 #include "base/time.h"
18 #include "base/utf_string_conversions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/download/download_completion_blocker.h"
21 #include "chrome/browser/download/download_crx_util.h"
22 #include "chrome/browser/download/download_file_picker.h"
23 #include "chrome/browser/download/download_history.h"
24 #include "chrome/browser/download/download_path_reservation_tracker.h"
25 #include "chrome/browser/download/download_prefs.h"
26 #include "chrome/browser/download/download_service.h"
27 #include "chrome/browser/download/download_service_factory.h"
28 #include "chrome/browser/download/download_target_determiner.h"
29 #include "chrome/browser/download/download_util.h"
30 #include "chrome/browser/download/save_package_file_picker.h"
31 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
32 #include "chrome/browser/extensions/crx_installer.h"
33 #include "chrome/browser/platform_util.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
36 #include "chrome/common/chrome_notification_types.h"
37 #include "chrome/common/extensions/extension.h"
38 #include "chrome/common/pref_names.h"
39 #include "components/user_prefs/pref_registry_syncable.h"
40 #include "content/public/browser/download_item.h"
41 #include "content/public/browser/download_manager.h"
42 #include "content/public/browser/notification_source.h"
44 #if defined(OS_CHROMEOS)
45 #include "chrome/browser/chromeos/drive/download_handler.h"
46 #include "chrome/browser/chromeos/drive/file_system_util.h"
47 #include "chrome/browser/download/save_package_file_picker_chromeos.h"
50 using content::BrowserContext
;
51 using content::BrowserThread
;
52 using content::DownloadId
;
53 using content::DownloadItem
;
54 using content::DownloadManager
;
55 using safe_browsing::DownloadProtectionService
;
59 // String pointer used for identifying safebrowing data associated with
61 static const char safe_browsing_id
[] = "Safe Browsing ID";
63 // The state of a safebrowsing check.
64 class SafeBrowsingState
: public DownloadCompletionBlocker
{
67 : verdict_(DownloadProtectionService::SAFE
) {
70 virtual ~SafeBrowsingState();
72 // The verdict that we got from calling CheckClientDownload. Only valid to
73 // call if |is_complete()|.
74 DownloadProtectionService::DownloadCheckResult
verdict() const {
78 void SetVerdict(DownloadProtectionService::DownloadCheckResult result
) {
84 DownloadProtectionService::DownloadCheckResult verdict_
;
86 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingState
);
89 SafeBrowsingState::~SafeBrowsingState() {}
91 // Returns a file path in the form that is expected by
92 // platform_util::OpenItem/ShowItemInFolder, including any transformation
93 // required for download abstractions layered on top of the core system,
94 // e.g. download to Drive.
95 base::FilePath
GetPlatformDownloadPath(Profile
* profile
,
96 const DownloadItem
* download
) {
97 #if defined(OS_CHROMEOS)
98 drive::DownloadHandler
* drive_download_handler
=
99 drive::DownloadHandler::GetForProfile(profile
);
100 if (drive_download_handler
&&
101 drive_download_handler
->IsDriveDownload(download
))
102 return drive_download_handler
->GetTargetPath(download
);
104 // The caller wants to open the download or show it in a file browser. The
105 // download could be in one of three states:
106 // - Complete: The path we want is GetTargetFilePath().
107 // - Not complete, but there's an intermediate file: GetFullPath() will be
108 // non-empty and is the location of the intermediate file. Since no target
109 // file exits yet, use GetFullPath(). This should only happen during
110 // ShowDownloadInShell().
111 // - Not Complete, and there's no intermediate file: GetFullPath() will be
112 // empty. This shouldn't happen since CanShowInFolder() returns false and
113 // this function shouldn't have been called.
114 if (download
->IsComplete()) {
115 DCHECK(!download
->GetTargetFilePath().empty());
116 return download
->GetTargetFilePath();
119 DCHECK(!download
->GetFullPath().empty());
120 return download
->GetFullPath();
123 // Callback invoked by DownloadProtectionService::CheckClientDownload.
124 // |is_content_check_supported| is true if the SB service supports scanning the
125 // download for malicious content.
126 // |callback| is invoked with a danger type determined as follows:
128 // Danger type is (in order of preference):
129 // * DANGEROUS_URL, if the URL is a known malware site.
130 // * MAYBE_DANGEROUS_CONTENT, if the content will be scanned for
131 // malware. I.e. |is_content_check_supported| is true.
133 void CheckDownloadUrlDone(
134 const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback
& callback
,
135 bool is_content_check_supported
,
136 DownloadProtectionService::DownloadCheckResult result
) {
137 content::DownloadDangerType danger_type
;
138 if (result
== DownloadProtectionService::SAFE
) {
139 // If this type of files is handled by the enhanced SafeBrowsing download
140 // protection, mark it as potentially dangerous content until we are done
142 if (is_content_check_supported
)
143 danger_type
= content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
;
145 danger_type
= content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
;
147 // If the URL is malicious, we'll use that as the danger type. The results
148 // of the content check, if one is performed, will be ignored.
149 danger_type
= content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
;
151 callback
.Run(danger_type
);
157 void ChromeDownloadManagerDelegate::RegisterUserPrefs(
158 user_prefs::PrefRegistrySyncable
* registry
) {
159 const base::FilePath
& default_download_path
=
160 download_util::GetDefaultDownloadDirectory();
161 registry
->RegisterFilePathPref(
162 prefs::kSaveFileDefaultDirectory
,
163 default_download_path
,
164 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
167 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile
* profile
)
169 next_download_id_(0),
170 download_prefs_(new DownloadPrefs(profile
)) {
173 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
176 void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager
* dm
) {
177 download_manager_
= dm
;
180 void ChromeDownloadManagerDelegate::Shutdown() {
181 download_prefs_
.reset();
184 DownloadId
ChromeDownloadManagerDelegate::GetNextId() {
185 if (!profile_
->IsOffTheRecord())
186 return DownloadId(this, next_download_id_
++);
188 return BrowserContext::GetDownloadManager(profile_
->GetOriginalProfile())->
189 GetDelegate()->GetNextId();
192 bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
193 DownloadItem
* download
,
194 const content::DownloadTargetCallback
& callback
) {
195 DownloadTargetDeterminer::Start(download
,
196 download_prefs_
.get(),
203 bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension(
204 const base::FilePath
& path
) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
206 if (path
.Extension().empty())
208 // TODO(asanka): This determination is done based on |path|, while
209 // ShouldOpenDownload() detects extension downloads based on the
210 // characteristics of the download. Reconcile this. http://crbug.com/167702
211 if (extensions::Extension::IsExtension(path
))
213 return download_prefs_
->IsAutoOpenEnabledBasedOnExtension(path
);
217 void ChromeDownloadManagerDelegate::DisableSafeBrowsing(DownloadItem
* item
) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
219 #if defined(FULL_SAFE_BROWSING)
220 SafeBrowsingState
* state
= static_cast<SafeBrowsingState
*>(
221 item
->GetUserData(&safe_browsing_id
));
223 state
= new SafeBrowsingState();
224 item
->SetUserData(&safe_browsing_id
, state
);
226 state
->SetVerdict(DownloadProtectionService::SAFE
);
230 bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion(
232 const base::Closure
& internal_complete_callback
) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
234 #if defined(FULL_SAFE_BROWSING)
235 SafeBrowsingState
* state
= static_cast<SafeBrowsingState
*>(
236 item
->GetUserData(&safe_browsing_id
));
238 // Begin the safe browsing download protection check.
239 DownloadProtectionService
* service
= GetDownloadProtectionService();
241 VLOG(2) << __FUNCTION__
<< "() Start SB download check for download = "
242 << item
->DebugString(false);
243 state
= new SafeBrowsingState();
244 state
->set_callback(internal_complete_callback
);
245 item
->SetUserData(&safe_browsing_id
, state
);
246 service
->CheckClientDownload(
249 &ChromeDownloadManagerDelegate::CheckClientDownloadDone
,
254 } else if (!state
->is_complete()) {
255 // Don't complete the download until we have an answer.
256 state
->set_callback(internal_complete_callback
);
263 void ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal(
265 const base::Closure
& user_complete_callback
) {
266 DownloadItem
* item
= download_manager_
->GetDownload(download_id
);
269 if (ShouldCompleteDownload(item
, user_complete_callback
))
270 user_complete_callback
.Run();
273 bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(
275 const base::Closure
& user_complete_callback
) {
276 return IsDownloadReadyForCompletion(item
, base::Bind(
277 &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal
,
278 this, item
->GetId(), user_complete_callback
));
281 bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
282 DownloadItem
* item
, const content::DownloadOpenDelayedCallback
& callback
) {
283 if (download_crx_util::IsExtensionDownload(*item
)) {
284 scoped_refptr
<extensions::CrxInstaller
> crx_installer
=
285 download_crx_util::OpenChromeExtension(profile_
, *item
);
287 // CRX_INSTALLER_DONE will fire when the install completes. At that
288 // time, Observe() will call the passed callback.
291 chrome::NOTIFICATION_CRX_INSTALLER_DONE
,
292 content::Source
<extensions::CrxInstaller
>(crx_installer
.get()));
294 crx_installers_
[crx_installer
.get()] = callback
;
295 // The status text and percent complete indicator will change now
296 // that we are installing a CRX. Update observers so that they pick
298 item
->UpdateObservers();
305 bool ChromeDownloadManagerDelegate::GenerateFileHash() {
306 #if defined(FULL_SAFE_BROWSING)
307 return profile_
->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled
) &&
308 g_browser_process
->safe_browsing_service()->DownloadBinHashNeeded();
314 void ChromeDownloadManagerDelegate::GetSaveDir(
315 BrowserContext
* browser_context
,
316 base::FilePath
* website_save_dir
,
317 base::FilePath
* download_save_dir
,
318 bool* skip_dir_check
) {
319 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
320 PrefService
* prefs
= profile
->GetPrefs();
322 // Check whether the preference for the preferred directory for
323 // saving file has been explicitly set. If not, and the preference
324 // for the default download directory has been set, initialize it
325 // with the latter. Note that the defaults for both are the same.
326 const PrefService::Preference
* download_default_directory
=
327 prefs
->FindPreference(prefs::kDownloadDefaultDirectory
);
328 if (!download_default_directory
->IsDefaultValue() &&
329 prefs
->FindPreference(
330 prefs::kSaveFileDefaultDirectory
)->IsDefaultValue()) {
331 prefs
->Set(prefs::kSaveFileDefaultDirectory
,
332 *(download_default_directory
->GetValue()));
335 // Get the directory from preference.
336 *website_save_dir
= prefs
->GetFilePath(prefs::kSaveFileDefaultDirectory
);
337 DCHECK(!website_save_dir
->empty());
339 *download_save_dir
= prefs
->GetFilePath(prefs::kDownloadDefaultDirectory
);
341 *skip_dir_check
= false;
342 #if defined(OS_CHROMEOS)
343 *skip_dir_check
= drive::util::IsUnderDriveMountPoint(*website_save_dir
);
347 void ChromeDownloadManagerDelegate::ChooseSavePath(
348 content::WebContents
* web_contents
,
349 const base::FilePath
& suggested_path
,
350 const base::FilePath::StringType
& default_extension
,
351 bool can_save_as_complete
,
352 const content::SavePackagePathPickedCallback
& callback
) {
354 #if defined(OS_CHROMEOS)
355 new SavePackageFilePickerChromeOS(
358 can_save_as_complete
,
361 new SavePackageFilePicker(
365 can_save_as_complete
,
366 download_prefs_
.get(),
371 void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem
* download
) {
372 DCHECK(download
->IsComplete());
373 if (!download
->CanOpenDownload())
375 platform_util::OpenItem(GetPlatformDownloadPath(profile_
, download
));
378 void ChromeDownloadManagerDelegate::ShowDownloadInShell(
379 DownloadItem
* download
) {
380 if (!download
->CanShowInFolder())
382 platform_util::ShowItemInFolder(GetPlatformDownloadPath(profile_
, download
));
385 void ChromeDownloadManagerDelegate::CheckForFileExistence(
386 DownloadItem
* download
,
387 const content::CheckForFileExistenceCallback
& callback
) {
388 #if defined(OS_CHROMEOS)
389 drive::DownloadHandler
* drive_download_handler
=
390 drive::DownloadHandler::GetForProfile(profile_
);
391 if (drive_download_handler
&&
392 drive_download_handler
->IsDriveDownload(download
)) {
393 drive_download_handler
->CheckForFileExistence(download
, callback
);
397 BrowserThread::PostTaskAndReplyWithResult(
398 BrowserThread::FILE, FROM_HERE
,
399 base::Bind(&file_util::PathExists
, download
->GetTargetFilePath()),
403 void ChromeDownloadManagerDelegate::ClearLastDownloadPath() {
404 last_download_path_
.clear();
407 DownloadProtectionService
*
408 ChromeDownloadManagerDelegate::GetDownloadProtectionService() {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
410 #if defined(FULL_SAFE_BROWSING)
411 SafeBrowsingService
* sb_service
= g_browser_process
->safe_browsing_service();
412 if (sb_service
&& sb_service
->download_protection_service() &&
413 profile_
->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled
)) {
414 return sb_service
->download_protection_service();
420 void ChromeDownloadManagerDelegate::NotifyExtensions(
421 DownloadItem
* download
,
422 const base::FilePath
& virtual_path
,
423 const NotifyExtensionsCallback
& callback
) {
424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
425 #if !defined(OS_ANDROID)
426 ExtensionDownloadsEventRouter
* router
=
427 DownloadServiceFactory::GetForProfile(profile_
)->
428 GetExtensionEventRouter();
430 base::Closure original_path_callback
=
431 base::Bind(callback
, base::FilePath(),
432 DownloadPathReservationTracker::UNIQUIFY
);
433 router
->OnDeterminingFilename(download
, virtual_path
.BaseName(),
434 original_path_callback
,
439 callback
.Run(base::FilePath(), DownloadPathReservationTracker::UNIQUIFY
);
442 void ChromeDownloadManagerDelegate::ReserveVirtualPath(
443 content::DownloadItem
* download
,
444 const base::FilePath
& virtual_path
,
445 bool create_directory
,
446 DownloadPathReservationTracker::FilenameConflictAction conflict_action
,
447 const DownloadTargetDeterminerDelegate::ReservedPathCallback
& callback
) {
448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
449 DCHECK(!virtual_path
.empty());
450 #if defined(OS_CHROMEOS)
451 // TODO(asanka): Handle path reservations for virtual paths as well.
452 // http://crbug.com/151618
453 if (drive::util::IsUnderDriveMountPoint(virtual_path
)) {
454 callback
.Run(virtual_path
, true);
458 DownloadPathReservationTracker::GetReservedPath(
459 *download
, virtual_path
, download_prefs_
->DownloadPath(),
460 create_directory
, conflict_action
, callback
);
463 void ChromeDownloadManagerDelegate::PromptUserForDownloadPath(
464 DownloadItem
* download
,
465 const base::FilePath
& suggested_path
,
466 const DownloadTargetDeterminerDelegate::FileSelectedCallback
& callback
) {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
468 DownloadFilePicker::ShowFilePicker(
471 base::Bind(&ChromeDownloadManagerDelegate::OnDownloadPathSelected
,
476 void ChromeDownloadManagerDelegate::OnDownloadPathSelected(
477 const DownloadTargetDeterminerDelegate::FileSelectedCallback
& callback
,
478 const base::FilePath
& virtual_path
) {
479 if (!virtual_path
.empty())
480 last_download_path_
= virtual_path
.DirName();
481 callback
.Run(virtual_path
);
484 void ChromeDownloadManagerDelegate::DetermineLocalPath(
485 DownloadItem
* download
,
486 const base::FilePath
& virtual_path
,
487 const DownloadTargetDeterminerDelegate::LocalPathCallback
& callback
) {
488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
489 #if defined(OS_CHROMEOS)
490 drive::DownloadHandler
* drive_download_handler
=
491 drive::DownloadHandler::GetForProfile(profile_
);
492 if (drive_download_handler
) {
493 drive_download_handler
->SubstituteDriveDownloadPath(
494 virtual_path
, download
, callback
);
498 callback
.Run(virtual_path
);
501 void ChromeDownloadManagerDelegate::CheckDownloadUrl(
502 DownloadItem
* download
,
503 const base::FilePath
& suggested_path
,
504 const CheckDownloadUrlCallback
& callback
) {
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
507 #if defined(FULL_SAFE_BROWSING)
508 safe_browsing::DownloadProtectionService
* service
=
509 GetDownloadProtectionService();
511 bool is_content_check_supported
=
512 service
->IsSupportedDownload(*download
, suggested_path
);
513 VLOG(2) << __FUNCTION__
<< "() Start SB URL check for download = "
514 << download
->DebugString(false);
515 service
->CheckDownloadUrl(*download
,
516 base::Bind(&CheckDownloadUrlDone
,
518 is_content_check_supported
));
522 callback
.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
);
525 void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
527 DownloadProtectionService::DownloadCheckResult result
) {
528 DownloadItem
* item
= download_manager_
->GetDownload(download_id
);
529 if (!item
|| (item
->GetState() != DownloadItem::IN_PROGRESS
))
532 VLOG(2) << __FUNCTION__
<< "() download = " << item
->DebugString(false)
533 << " verdict = " << result
;
534 // We only mark the content as being dangerous if the download's safety state
535 // has not been set to DANGEROUS yet. We don't want to show two warnings.
536 if (item
->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
||
537 item
->GetDangerType() ==
538 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
) {
540 case DownloadProtectionService::SAFE
:
543 case DownloadProtectionService::DANGEROUS
:
544 item
->OnContentCheckCompleted(
545 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
);
547 case DownloadProtectionService::UNCOMMON
:
548 item
->OnContentCheckCompleted(
549 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
);
551 case DownloadProtectionService::DANGEROUS_HOST
:
552 item
->OnContentCheckCompleted(
553 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
);
558 SafeBrowsingState
* state
= static_cast<SafeBrowsingState
*>(
559 item
->GetUserData(&safe_browsing_id
));
560 state
->SetVerdict(result
);
563 // content::NotificationObserver implementation.
564 void ChromeDownloadManagerDelegate::Observe(
566 const content::NotificationSource
& source
,
567 const content::NotificationDetails
& details
) {
568 DCHECK(type
== chrome::NOTIFICATION_CRX_INSTALLER_DONE
);
570 registrar_
.Remove(this,
571 chrome::NOTIFICATION_CRX_INSTALLER_DONE
,
574 scoped_refptr
<extensions::CrxInstaller
> installer
=
575 content::Source
<extensions::CrxInstaller
>(source
).ptr();
576 content::DownloadOpenDelayedCallback callback
= crx_installers_
[installer
];
577 crx_installers_
.erase(installer
.get());
578 callback
.Run(installer
->did_handle_successfully());