Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / download / chrome_download_manager_delegate.cc
blob429daac1019ade7887a8035be4a4ec7c8707ad9a
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"
7 #include <string>
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 "net/base/filename_util.h"
50 #include "net/base/mime_util.h"
52 #if defined(OS_CHROMEOS)
53 #include "chrome/browser/chromeos/drive/download_handler.h"
54 #include "chrome/browser/chromeos/drive/file_system_util.h"
55 #endif
57 #if defined(ENABLE_EXTENSIONS)
58 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
59 #include "chrome/browser/extensions/crx_installer.h"
60 #include "chrome/browser/extensions/webstore_installer.h"
61 #include "extensions/browser/notification_types.h"
62 #include "extensions/common/constants.h"
63 #endif
65 using content::BrowserThread;
66 using content::DownloadItem;
67 using content::DownloadManager;
68 using safe_browsing::DownloadProtectionService;
70 namespace {
72 #if defined(FULL_SAFE_BROWSING)
74 // String pointer used for identifying safebrowing data associated with
75 // a download item.
76 const char kSafeBrowsingUserDataKey[] = "Safe Browsing ID";
78 // The state of a safebrowsing check.
79 class SafeBrowsingState : public DownloadCompletionBlocker {
80 public:
81 SafeBrowsingState() {}
82 virtual ~SafeBrowsingState();
84 private:
85 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingState);
88 SafeBrowsingState::~SafeBrowsingState() {}
90 #endif // FULL_SAFE_BROWSING
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,
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
104 // Returns a path in the form that that is expected by platform_util::OpenItem /
105 // platform_util::ShowItemInFolder / DownloadTargetDeterminer.
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.
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
125 if (path_type == PLATFORM_TARGET_PATH)
126 return download->GetTargetFilePath();
127 return download->GetFullPath();
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:
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;
160 callback.Run(danger_type);
163 #endif // FULL_SAFE_BROWSING
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;
172 } // namespace
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) {
181 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
182 // If a DownloadManager was set for this, Shutdown() must be called.
183 DCHECK(!download_manager_);
186 void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
187 download_manager_ = dm;
190 void ChromeDownloadManagerDelegate::Shutdown() {
191 download_prefs_.reset();
192 weak_ptr_factory_.InvalidateWeakPtrs();
193 download_manager_ = NULL;
196 content::DownloadIdCallback
197 ChromeDownloadManagerDelegate::GetDownloadIdReceiverCallback() {
198 return base::Bind(&ChromeDownloadManagerDelegate::SetNextId,
199 weak_ptr_factory_.GetWeakPtr());
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;
208 IdCallbackVector callbacks;
209 id_callbacks_.swap(callbacks);
210 for (IdCallbackVector::const_iterator it = callbacks.begin();
211 it != callbacks.end(); ++it) {
212 ReturnNextId(*it);
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;
224 if (next_download_id_ == content::DownloadItem::kInvalidId) {
225 id_callbacks_.push_back(callback);
226 return;
228 ReturnNextId(callback);
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_++);
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;
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);
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);
281 state->CompleteDownload();
282 #endif
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;
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;
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;
330 #endif
331 return true;
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();
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));
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);
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()));
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;
374 #endif
376 return true;
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
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
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);
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);
426 void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem* download) {
427 DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
428 DCHECK(!download->GetTargetFilePath().empty());
429 if (!download->CanOpenDownload())
430 return;
432 if (!DownloadItemModel(download).ShouldPreferOpeningInBrowser()) {
433 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_DEFAULT_PLATFORM);
434 OpenDownloadUsingPlatformHandler(download);
435 return;
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();
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
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);
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;
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);
498 std::string
499 ChromeDownloadManagerDelegate::ApplicationClientIdForFileScanning() const {
500 return std::string(chrome::kApplicationClientIDStringForAVScanning);
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();
512 #endif
513 return NULL;
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;
534 #endif
535 callback.Run(base::FilePath(), DownloadPathReservationTracker::UNIQUIFY);
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;
553 #endif
554 DownloadPathReservationTracker::GetReservedPath(
555 download,
556 virtual_path,
557 download_prefs_->DownloadPath(),
558 create_directory,
559 conflict_action,
560 callback);
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);
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;
584 #endif
585 callback.Run(virtual_path);
588 void ChromeDownloadManagerDelegate::CheckDownloadUrl(
589 DownloadItem* download,
590 const base::FilePath& suggested_path,
591 const CheckDownloadUrlCallback& callback) {
592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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;
608 #endif
609 callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
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);
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;
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;
662 if (danger_type != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
663 item->OnContentCheckCompleted(danger_type);
666 SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
667 item->GetUserData(&kSafeBrowsingUserDataKey));
668 state->CompleteDownload();
670 #endif // FULL_SAFE_BROWSING
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);
680 registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
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
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);
703 if (target_info->is_dangerous_file)
704 DownloadItemModel(item).SetIsDangerousFileBasedOnType(true);
706 callback.Run(target_info->target_path,
707 target_info->target_disposition,
708 target_info->danger_type,
709 target_info->intermediate_path);
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();
720 #endif
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;
740 #endif
741 return false;