1 // Copyright 2013 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/download_target_determiner.h" 6 7 #include "base/prefs/pref_service.h" 8 #include "base/rand_util.h" 9 #include "base/strings/stringprintf.h" 10 #include "base/time/time.h" 11 #include "chrome/browser/download/chrome_download_manager_delegate.h" 12 #include "chrome/browser/download/download_crx_util.h" 13 #include "chrome/browser/download/download_extensions.h" 14 #include "chrome/browser/download/download_prefs.h" 15 #include "chrome/browser/download/download_util.h" 16 #include "chrome/browser/extensions/webstore_installer.h" 17 #include "chrome/browser/history/history_service.h" 18 #include "chrome/browser/history/history_service_factory.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/common/extensions/feature_switch.h" 21 #include "chrome/common/pref_names.h" 22 #include "content/public/browser/browser_context.h" 23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/download_interrupt_reasons.h" 25 #include "extensions/common/constants.h" 26 #include "grit/generated_resources.h" 27 #include "net/base/net_util.h" 28 #include "ui/base/l10n/l10n_util.h" 29 30 using content::BrowserThread; 31 using content::DownloadItem; 32 33 namespace { 34 35 const base::FilePath::CharType kCrdownloadSuffix[] = 36 FILE_PATH_LITERAL(".crdownload"); 37 38 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a 39 // single bool. A host is considered visited before if prior visible visits were 40 // found in history and the first such visit was earlier than the most recent 41 // midnight. 42 void VisitCountsToVisitedBefore( 43 const base::Callback<void(bool)>& callback, 44 HistoryService::Handle unused_handle, 45 bool found_visits, 46 int count, 47 base::Time first_visit) { 48 callback.Run( 49 found_visits && count > 0 && 50 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); 51 } 52 53 } // namespace 54 55 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { 56 } 57 58 DownloadTargetDeterminer::DownloadTargetDeterminer( 59 DownloadItem* download, 60 const base::FilePath& initial_virtual_path, 61 DownloadPrefs* download_prefs, 62 DownloadTargetDeterminerDelegate* delegate, 63 const content::DownloadTargetCallback& callback) 64 : next_state_(STATE_GENERATE_TARGET_PATH), 65 should_prompt_(false), 66 should_notify_extensions_(false), 67 create_target_directory_(false), 68 conflict_action_(DownloadPathReservationTracker::OVERWRITE), 69 danger_type_(download->GetDangerType()), 70 virtual_path_(initial_virtual_path), 71 download_(download), 72 is_resumption_(download_->GetLastReason() != 73 content::DOWNLOAD_INTERRUPT_REASON_NONE && 74 !initial_virtual_path.empty()), 75 download_prefs_(download_prefs), 76 delegate_(delegate), 77 completion_callback_(callback), 78 weak_ptr_factory_(this) { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 80 DCHECK(download_); 81 DCHECK(delegate); 82 download_->AddObserver(this); 83 84 DoLoop(); 85 } 86 87 DownloadTargetDeterminer::~DownloadTargetDeterminer() { 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89 DCHECK(download_); 90 DCHECK(completion_callback_.is_null()); 91 download_->RemoveObserver(this); 92 } 93 94 void DownloadTargetDeterminer::DoLoop() { 95 Result result = CONTINUE; 96 do { 97 State current_state = next_state_; 98 next_state_ = STATE_NONE; 99 100 switch (current_state) { 101 case STATE_GENERATE_TARGET_PATH: 102 result = DoGenerateTargetPath(); 103 break; 104 case STATE_NOTIFY_EXTENSIONS: 105 result = DoNotifyExtensions(); 106 break; 107 case STATE_RESERVE_VIRTUAL_PATH: 108 result = DoReserveVirtualPath(); 109 break; 110 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: 111 result = DoPromptUserForDownloadPath(); 112 break; 113 case STATE_DETERMINE_LOCAL_PATH: 114 result = DoDetermineLocalPath(); 115 break; 116 case STATE_CHECK_DOWNLOAD_URL: 117 result = DoCheckDownloadUrl(); 118 break; 119 case STATE_DETERMINE_INTERMEDIATE_PATH: 120 result = DoDetermineIntermediatePath(); 121 break; 122 case STATE_CHECK_VISITED_REFERRER_BEFORE: 123 result = DoCheckVisitedReferrerBefore(); 124 break; 125 case STATE_NONE: 126 NOTREACHED(); 127 return; 128 } 129 } while (result == CONTINUE); 130 // Note that if a callback completes synchronously, the handler will still 131 // return QUIT_DOLOOP. In this case, an inner DoLoop() may complete the target 132 // determination and delete |this|. 133 134 if (result == COMPLETE) 135 ScheduleCallbackAndDeleteSelf(); 136 } 137 138 DownloadTargetDeterminer::Result 139 DownloadTargetDeterminer::DoGenerateTargetPath() { 140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 141 DCHECK(local_path_.empty()); 142 DCHECK(!should_prompt_); 143 DCHECK(!should_notify_extensions_); 144 DCHECK_EQ(DownloadPathReservationTracker::OVERWRITE, conflict_action_); 145 bool is_forced_path = !download_->GetForcedFilePath().empty(); 146 147 next_state_ = STATE_NOTIFY_EXTENSIONS; 148 149 if (!virtual_path_.empty() && HasPromptedForPath() && !is_forced_path) { 150 // The download is being resumed and the user has already been prompted for 151 // a path. Assume that it's okay to overwrite the file if there's a conflict 152 // and reuse the selection. 153 should_prompt_ = ShouldPromptForDownload(virtual_path_); 154 } else if (!is_forced_path) { 155 // If we don't have a forced path, we should construct a path for the 156 // download. Forced paths are only specified for programmatic downloads 157 // (WebStore, Drag&Drop). Treat the path as a virtual path. We will 158 // eventually determine whether this is a local path and if not, figure out 159 // a local path. 160 std::string default_filename( 161 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); 162 base::FilePath generated_filename = net::GenerateFileName( 163 download_->GetURL(), 164 download_->GetContentDisposition(), 165 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset), 166 download_->GetSuggestedFilename(), 167 download_->GetMimeType(), 168 default_filename); 169 should_prompt_ = ShouldPromptForDownload(generated_filename); 170 base::FilePath target_directory; 171 if (should_prompt_) { 172 DCHECK(!download_prefs_->IsDownloadPathManaged()); 173 // If the user is going to be prompted and the user has been prompted 174 // before, then always prefer the last directory that the user selected. 175 target_directory = download_prefs_->SaveFilePath(); 176 } else { 177 target_directory = download_prefs_->DownloadPath(); 178 } 179 virtual_path_ = target_directory.Append(generated_filename); 180 conflict_action_ = DownloadPathReservationTracker::UNIQUIFY; 181 should_notify_extensions_ = true; 182 } else { 183 virtual_path_ = download_->GetForcedFilePath(); 184 // If this is a resumed download which was previously interrupted due to an 185 // issue with the forced path, the user is still not prompted. If the path 186 // supplied to a programmatic download is invalid, then the caller needs to 187 // intervene. 188 } 189 DCHECK(virtual_path_.IsAbsolute()); 190 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe(); 191 192 // If the download is DOA, don't bother going any further. This would be the 193 // case for a download that failed to initialize (e.g. the initial temporary 194 // file couldn't be created because both the downloads directory and the 195 // temporary directory are unwriteable). 196 // 197 // A virtual path is determined for DOA downloads for display purposes. This 198 // is why this check is performed here instead of at the start. 199 if (download_->GetState() != DownloadItem::IN_PROGRESS) 200 return COMPLETE; 201 return CONTINUE; 202 } 203 204 DownloadTargetDeterminer::Result 205 DownloadTargetDeterminer::DoNotifyExtensions() { 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 207 DCHECK(!virtual_path_.empty()); 208 209 next_state_ = STATE_RESERVE_VIRTUAL_PATH; 210 211 if (!should_notify_extensions_) 212 return CONTINUE; 213 214 delegate_->NotifyExtensions(download_, virtual_path_, 215 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone, 216 weak_ptr_factory_.GetWeakPtr())); 217 return QUIT_DOLOOP; 218 } 219 220 void DownloadTargetDeterminer::NotifyExtensionsDone( 221 const base::FilePath& suggested_path, 222 DownloadPathReservationTracker::FilenameConflictAction conflict_action) { 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 224 DVLOG(20) << "Extension suggested path: " << suggested_path.AsUTF8Unsafe(); 225 226 if (!suggested_path.empty()) { 227 // If an extension overrides the filename, then the target directory will be 228 // forced to download_prefs_->DownloadPath() since extensions cannot place 229 // downloaded files anywhere except there. This prevents subdirectories from 230 // accumulating: if an extension is allowed to say that a file should go in 231 // last_download_path/music/foo.mp3, then last_download_path will accumulate 232 // the subdirectory /music/ so that the next download may end up in 233 // Downloads/music/music/music/bar.mp3. 234 base::FilePath new_path(download_prefs_->DownloadPath().Append( 235 suggested_path).NormalizePathSeparators()); 236 // Do not pass a mime type to GenerateSafeFileName so that it does not force 237 // the filename to have an extension if the (Chrome) extension does not 238 // suggest it. 239 net::GenerateSafeFileName(std::string(), false, &new_path); 240 virtual_path_ = new_path; 241 create_target_directory_ = true; 242 conflict_action_ = conflict_action; 243 } 244 245 DoLoop(); 246 } 247 248 DownloadTargetDeterminer::Result 249 DownloadTargetDeterminer::DoReserveVirtualPath() { 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 251 DCHECK(!virtual_path_.empty()); 252 253 next_state_ = STATE_PROMPT_USER_FOR_DOWNLOAD_PATH; 254 255 delegate_->ReserveVirtualPath( 256 download_, virtual_path_, create_target_directory_, conflict_action_, 257 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone, 258 weak_ptr_factory_.GetWeakPtr())); 259 return QUIT_DOLOOP; 260 } 261 262 void DownloadTargetDeterminer::ReserveVirtualPathDone( 263 const base::FilePath& path, bool verified) { 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 265 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe() 266 << " Verified:" << verified; 267 should_prompt_ = (should_prompt_ || !verified); 268 virtual_path_ = path; 269 DoLoop(); 270 } 271 272 DownloadTargetDeterminer::Result 273 DownloadTargetDeterminer::DoPromptUserForDownloadPath() { 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 275 DCHECK(!virtual_path_.empty()); 276 277 next_state_ = STATE_DETERMINE_LOCAL_PATH; 278 279 if (should_prompt_) { 280 delegate_->PromptUserForDownloadPath( 281 download_, 282 virtual_path_, 283 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone, 284 weak_ptr_factory_.GetWeakPtr())); 285 return QUIT_DOLOOP; 286 } 287 return CONTINUE; 288 } 289 290 void DownloadTargetDeterminer::PromptUserForDownloadPathDone( 291 const base::FilePath& virtual_path) { 292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 293 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe(); 294 if (virtual_path.empty()) { 295 CancelOnFailureAndDeleteSelf(); 296 return; 297 } 298 virtual_path_ = virtual_path; 299 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); 300 DoLoop(); 301 } 302 303 DownloadTargetDeterminer::Result 304 DownloadTargetDeterminer::DoDetermineLocalPath() { 305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 306 DCHECK(!virtual_path_.empty()); 307 DCHECK(local_path_.empty()); 308 309 next_state_ = STATE_CHECK_DOWNLOAD_URL; 310 311 delegate_->DetermineLocalPath( 312 download_, 313 virtual_path_, 314 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, 315 weak_ptr_factory_.GetWeakPtr())); 316 return QUIT_DOLOOP; 317 } 318 319 void DownloadTargetDeterminer::DetermineLocalPathDone( 320 const base::FilePath& local_path) { 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 322 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); 323 if (local_path.empty()) { 324 // Path subsitution failed. 325 CancelOnFailureAndDeleteSelf(); 326 return; 327 } 328 local_path_ = local_path; 329 DoLoop(); 330 } 331 332 DownloadTargetDeterminer::Result 333 DownloadTargetDeterminer::DoCheckDownloadUrl() { 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 335 DCHECK(!virtual_path_.empty()); 336 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; 337 delegate_->CheckDownloadUrl( 338 download_, 339 virtual_path_, 340 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, 341 weak_ptr_factory_.GetWeakPtr())); 342 return QUIT_DOLOOP; 343 } 344 345 void DownloadTargetDeterminer::CheckDownloadUrlDone( 346 content::DownloadDangerType danger_type) { 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 348 DVLOG(20) << "URL Check Result:" << danger_type; 349 danger_type_ = danger_type; 350 DoLoop(); 351 } 352 353 DownloadTargetDeterminer::Result 354 DownloadTargetDeterminer::DoCheckVisitedReferrerBefore() { 355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 356 357 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH; 358 359 // Checking if there are prior visits to the referrer is only necessary if the 360 // danger level of the download depends on the file type. This excludes cases 361 // where the download has already been deemed dangerous, or where the user is 362 // going to be prompted or where this is a programmatic download. 363 if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) 364 return CONTINUE; 365 366 // Assume that: 367 // IsDangerousFile(VISITED_REFERRER) => IsDangerousFile(NO_VISITS_...) 368 // I.e. having visited a referrer only lowers a file's danger level. 369 if (IsDangerousFile(NO_VISITS_TO_REFERRER)) { 370 // Only need to ping the history DB if the download would be considered safe 371 // if there are prior visits and is considered dangerous otherwise. 372 if (!IsDangerousFile(VISITED_REFERRER)) { 373 // HistoryServiceFactory redirects incognito profiles to on-record 374 // profiles. There's no history for on-record profiles in unit_tests. 375 HistoryService* history_service = HistoryServiceFactory::GetForProfile( 376 GetProfile(), Profile::EXPLICIT_ACCESS); 377 378 if (history_service && download_->GetReferrerUrl().is_valid()) { 379 history_service->GetVisibleVisitCountToHost( 380 download_->GetReferrerUrl(), &history_consumer_, 381 base::Bind(&VisitCountsToVisitedBefore, base::Bind( 382 &DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone, 383 weak_ptr_factory_.GetWeakPtr()))); 384 return QUIT_DOLOOP; 385 } 386 } 387 388 // If the danger level doesn't depend on having visited the refererrer URL 389 // or if original profile doesn't have a HistoryService or the referrer url 390 // is invalid, then assume the referrer has not been visited before. 391 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; 392 } 393 return CONTINUE; 394 } 395 396 void DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone( 397 bool visited_referrer_before) { 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 399 if (IsDangerousFile( 400 visited_referrer_before ? VISITED_REFERRER : NO_VISITS_TO_REFERRER)) 401 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; 402 DoLoop(); 403 } 404 405 DownloadTargetDeterminer::Result 406 DownloadTargetDeterminer::DoDetermineIntermediatePath() { 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 408 DCHECK(!virtual_path_.empty()); 409 DCHECK(!local_path_.empty()); 410 DCHECK(intermediate_path_.empty()); 411 DCHECK(!virtual_path_.MatchesExtension(kCrdownloadSuffix)); 412 DCHECK(!local_path_.MatchesExtension(kCrdownloadSuffix)); 413 414 next_state_ = STATE_NONE; 415 416 // Note that the intermediate filename is always uniquified (i.e. if a file by 417 // the same name exists, it is never overwritten). Therefore the code below 418 // does not attempt to find a name that doesn't conflict with an existing 419 // file. 420 421 // If the actual target of the download is a virtual path, then the local path 422 // is considered to point to a temporary path. A separate intermediate path is 423 // unnecessary since the local path already serves that purpose. 424 if (virtual_path_.BaseName() != local_path_.BaseName()) { 425 intermediate_path_ = local_path_; 426 return COMPLETE; 427 } 428 429 // If the download has a forced path and is safe, then just use the 430 // target path. In practice the temporary download file that was created prior 431 // to download filename determination is already named 432 // download_->GetForcedFilePath(). 433 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS && 434 !download_->GetForcedFilePath().empty()) { 435 DCHECK_EQ(download_->GetForcedFilePath().value(), local_path_.value()); 436 intermediate_path_ = local_path_; 437 return COMPLETE; 438 } 439 440 // Other safe downloads get a .crdownload suffix for their intermediate name. 441 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) { 442 intermediate_path_ = GetCrDownloadPath(local_path_); 443 return COMPLETE; 444 } 445 446 // If this is a resumed download, then re-use the existing intermediate path 447 // if one is available. A resumed download shouldn't cause a non-dangerous 448 // download to be considered dangerous upon resumption. Therefore the 449 // intermediate file should already be in the correct form. 450 if (is_resumption_ && !download_->GetFullPath().empty() && 451 local_path_.DirName() == download_->GetFullPath().DirName()) { 452 DCHECK_NE(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 453 download_->GetDangerType()); 454 DCHECK_EQ(kCrdownloadSuffix, download_->GetFullPath().Extension()); 455 intermediate_path_ = download_->GetFullPath(); 456 return COMPLETE; 457 } 458 459 // Dangerous downloads receive a random intermediate name that looks like: 460 // 'Unconfirmed <random>.crdownload'. 461 const base::FilePath::CharType kUnconfirmedFormatSuffix[] = 462 FILE_PATH_LITERAL(" %d.crdownload"); 463 // Range of the <random> uniquifier. 464 const int kUnconfirmedUniquifierRange = 1000000; 465 #if defined(OS_WIN) 466 string16 unconfirmed_format = 467 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); 468 #else 469 std::string unconfirmed_format = 470 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); 471 #endif 472 unconfirmed_format.append(kUnconfirmedFormatSuffix); 473 474 base::FilePath::StringType file_name = base::StringPrintf( 475 unconfirmed_format.c_str(), 476 base::RandInt(0, kUnconfirmedUniquifierRange)); 477 intermediate_path_ = local_path_.DirName().Append(file_name); 478 return COMPLETE; 479 } 480 481 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { 482 DCHECK(download_); 483 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() 484 << " Local:" << local_path_.AsUTF8Unsafe() 485 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() 486 << " Should prompt:" << should_prompt_ 487 << " Danger type:" << danger_type_; 488 base::MessageLoop::current()->PostTask( 489 FROM_HERE, 490 base::Bind(completion_callback_, 491 local_path_, 492 (HasPromptedForPath() || should_prompt_ 493 ? DownloadItem::TARGET_DISPOSITION_PROMPT 494 : DownloadItem::TARGET_DISPOSITION_OVERWRITE), 495 danger_type_, 496 intermediate_path_)); 497 completion_callback_.Reset(); 498 delete this; 499 } 500 501 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { 502 // Path substitution failed. 503 virtual_path_.clear(); 504 local_path_.clear(); 505 intermediate_path_.clear(); 506 ScheduleCallbackAndDeleteSelf(); 507 } 508 509 Profile* DownloadTargetDeterminer::GetProfile() { 510 DCHECK(download_->GetBrowserContext()); 511 return Profile::FromBrowserContext(download_->GetBrowserContext()); 512 } 513 514 bool DownloadTargetDeterminer::ShouldPromptForDownload( 515 const base::FilePath& filename) const { 516 if (is_resumption_) { 517 // For resumed downloads, if the target disposition or prefs require 518 // prompting, the user has already been prompted. Try to respect the user's 519 // selection, unless we've discovered that the target path cannot be used 520 // for some reason. 521 content::DownloadInterruptReason reason = download_->GetLastReason(); 522 return (reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED || 523 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE || 524 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE); 525 } 526 527 // If the download path is forced, don't prompt. 528 if (!download_->GetForcedFilePath().empty()) { 529 // 'Save As' downloads shouldn't have a forced path. 530 DCHECK(DownloadItem::TARGET_DISPOSITION_PROMPT != 531 download_->GetTargetDisposition()); 532 return false; 533 } 534 535 // Don't ask where to save if the download path is managed. Even if the user 536 // wanted to be prompted for "all" downloads, or if this was a 'Save As' 537 // download. 538 if (download_prefs_->IsDownloadPathManaged()) 539 return false; 540 541 // Prompt if this is a 'Save As' download. 542 if (download_->GetTargetDisposition() == 543 DownloadItem::TARGET_DISPOSITION_PROMPT) 544 return true; 545 546 // Check if the user has the "Always prompt for download location" preference 547 // set. If so we prompt for most downloads except for the following scenarios: 548 // 1) Extension installation. Note that we only care here about the case where 549 // an extension is installed, not when one is downloaded with "save as...". 550 // 2) Filetypes marked "always open." If the user just wants this file opened, 551 // don't bother asking where to keep it. 552 if (download_prefs_->PromptForDownload() && 553 !download_crx_util::IsExtensionDownload(*download_) && 554 !filename.MatchesExtension(extensions::kExtensionFileExtension) && 555 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename)) 556 return true; 557 558 // Otherwise, don't prompt. Note that the user might still be prompted if 559 // there are unresolved conflicts during path reservation (e.g. due to the 560 // target path being unwriteable or because there are too many conflicting 561 // files), or if an extension signals that the user be prompted on a filename 562 // conflict. 563 return false; 564 } 565 566 bool DownloadTargetDeterminer::HasPromptedForPath() const { 567 return (is_resumption_ && download_->GetTargetDisposition() == 568 DownloadItem::TARGET_DISPOSITION_PROMPT); 569 } 570 571 bool DownloadTargetDeterminer::IsDangerousFile(PriorVisitsToReferrer visits) { 572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 573 574 // If the user has has been prompted or will be, assume that the user has 575 // approved the download. A programmatic download is considered safe unless it 576 // contains malware. 577 if (HasPromptedForPath() || should_prompt_ || 578 !download_->GetForcedFilePath().empty()) 579 return false; 580 581 const bool is_extension_download = 582 download_crx_util::IsExtensionDownload(*download_); 583 584 // User-initiated extension downloads from pref-whitelisted sources are not 585 // considered dangerous. 586 if (download_->HasUserGesture() && 587 is_extension_download && 588 download_crx_util::OffStoreInstallAllowedByPrefs( 589 GetProfile(), *download_)) { 590 return false; 591 } 592 593 // Extensions that are not from the gallery are considered dangerous. 594 // When off-store install is disabled we skip this, since in this case, we 595 // will not offer to install the extension. 596 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() && 597 is_extension_download && 598 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) { 599 return true; 600 } 601 602 // Anything the user has marked auto-open is OK if it's user-initiated. 603 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) && 604 download_->HasUserGesture()) 605 return false; 606 607 switch (download_util::GetFileDangerLevel(virtual_path_.BaseName())) { 608 case download_util::NOT_DANGEROUS: 609 return false; 610 611 case download_util::ALLOW_ON_USER_GESTURE: 612 // "Allow on user gesture" is OK when we have a user gesture and the 613 // hosting page has been visited before today. 614 if (download_->GetTransitionType() & 615 content::PAGE_TRANSITION_FROM_ADDRESS_BAR) { 616 return false; 617 } 618 return !download_->HasUserGesture() || visits == NO_VISITS_TO_REFERRER; 619 620 case download_util::DANGEROUS: 621 return true; 622 } 623 NOTREACHED(); 624 return false; 625 } 626 627 void DownloadTargetDeterminer::OnDownloadDestroyed( 628 DownloadItem* download) { 629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 630 DCHECK_EQ(download_, download); 631 CancelOnFailureAndDeleteSelf(); 632 } 633 634 // static 635 void DownloadTargetDeterminer::Start( 636 content::DownloadItem* download, 637 const base::FilePath& initial_virtual_path, 638 DownloadPrefs* download_prefs, 639 DownloadTargetDeterminerDelegate* delegate, 640 const content::DownloadTargetCallback& callback) { 641 // DownloadTargetDeterminer owns itself and will self destruct when the job is 642 // complete or the download item is destroyed. The callback is always invoked 643 // asynchronously. 644 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, 645 delegate, callback); 646 } 647 648 // static 649 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( 650 const base::FilePath& suggested_path) { 651 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); 652 } 653