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