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/history/history_service.h" 16 #include "chrome/browser/history/history_service_factory.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/common/pref_names.h" 19 #include "chrome/grit/generated_resources.h" 20 #include "content/public/browser/browser_context.h" 21 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/download_interrupt_reasons.h" 23 #include "extensions/common/constants.h" 24 #include "net/base/filename_util.h" 25 #include "net/base/mime_util.h" 26 #include "ui/base/l10n/l10n_util.h" 27 28 #if defined(ENABLE_EXTENSIONS) 29 #include "chrome/browser/extensions/webstore_installer.h" 30 #include "extensions/common/feature_switch.h" 31 #endif 32 33 #if defined(ENABLE_PLUGINS) 34 #include "chrome/browser/plugins/plugin_prefs.h" 35 #include "content/public/browser/plugin_service.h" 36 #include "content/public/common/webplugininfo.h" 37 #endif 38 39 #if defined(OS_WIN) 40 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h" 41 #endif 42 43 using content::BrowserThread; 44 using content::DownloadItem; 45 46 namespace { 47 48 const base::FilePath::CharType kCrdownloadSuffix[] = 49 FILE_PATH_LITERAL(".crdownload"); 50 51 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a 52 // single bool. A host is considered visited before if prior visible visits were 53 // found in history and the first such visit was earlier than the most recent 54 // midnight. 55 void VisitCountsToVisitedBefore( 56 const base::Callback<void(bool)>& callback, 57 bool found_visits, 58 int count, 59 base::Time first_visit) { 60 callback.Run( 61 found_visits && count > 0 && 62 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); 63 } 64 65 #if defined(OS_WIN) 66 // Keeps track of whether Adobe Reader is up to date. 67 bool g_is_adobe_reader_up_to_date_ = false; 68 #endif 69 70 } // namespace 71 72 DownloadTargetInfo::DownloadTargetInfo() 73 : is_filetype_handled_safely(false) {} 74 75 DownloadTargetInfo::~DownloadTargetInfo() {} 76 77 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { 78 } 79 80 DownloadTargetDeterminer::DownloadTargetDeterminer( 81 DownloadItem* download, 82 const base::FilePath& initial_virtual_path, 83 DownloadPrefs* download_prefs, 84 DownloadTargetDeterminerDelegate* delegate, 85 const CompletionCallback& callback) 86 : next_state_(STATE_GENERATE_TARGET_PATH), 87 should_prompt_(false), 88 should_notify_extensions_(false), 89 create_target_directory_(false), 90 conflict_action_(DownloadPathReservationTracker::OVERWRITE), 91 danger_type_(download->GetDangerType()), 92 is_dangerous_file_(false), 93 virtual_path_(initial_virtual_path), 94 is_filetype_handled_safely_(false), 95 download_(download), 96 is_resumption_(download_->GetLastReason() != 97 content::DOWNLOAD_INTERRUPT_REASON_NONE && 98 !initial_virtual_path.empty()), 99 download_prefs_(download_prefs), 100 delegate_(delegate), 101 completion_callback_(callback), 102 weak_ptr_factory_(this) { 103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 104 DCHECK(download_); 105 DCHECK(delegate); 106 download_->AddObserver(this); 107 108 DoLoop(); 109 } 110 111 DownloadTargetDeterminer::~DownloadTargetDeterminer() { 112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 113 DCHECK(download_); 114 DCHECK(completion_callback_.is_null()); 115 download_->RemoveObserver(this); 116 } 117 118 void DownloadTargetDeterminer::DoLoop() { 119 Result result = CONTINUE; 120 do { 121 State current_state = next_state_; 122 next_state_ = STATE_NONE; 123 124 switch (current_state) { 125 case STATE_GENERATE_TARGET_PATH: 126 result = DoGenerateTargetPath(); 127 break; 128 case STATE_NOTIFY_EXTENSIONS: 129 result = DoNotifyExtensions(); 130 break; 131 case STATE_RESERVE_VIRTUAL_PATH: 132 result = DoReserveVirtualPath(); 133 break; 134 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH: 135 result = DoPromptUserForDownloadPath(); 136 break; 137 case STATE_DETERMINE_LOCAL_PATH: 138 result = DoDetermineLocalPath(); 139 break; 140 case STATE_DETERMINE_MIME_TYPE: 141 result = DoDetermineMimeType(); 142 break; 143 case STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER: 144 result = DoDetermineIfHandledSafely(); 145 break; 146 case STATE_DETERMINE_IF_ADOBE_READER_UP_TO_DATE: 147 result = DoDetermineIfAdobeReaderUpToDate(); 148 break; 149 case STATE_CHECK_DOWNLOAD_URL: 150 result = DoCheckDownloadUrl(); 151 break; 152 case STATE_DETERMINE_INTERMEDIATE_PATH: 153 result = DoDetermineIntermediatePath(); 154 break; 155 case STATE_CHECK_VISITED_REFERRER_BEFORE: 156 result = DoCheckVisitedReferrerBefore(); 157 break; 158 case STATE_NONE: 159 NOTREACHED(); 160 return; 161 } 162 } while (result == CONTINUE); 163 // Note that if a callback completes synchronously, the handler will still 164 // return QUIT_DOLOOP. In this case, an inner DoLoop() may complete the target 165 // determination and delete |this|. 166 167 if (result == COMPLETE) 168 ScheduleCallbackAndDeleteSelf(); 169 } 170 171 DownloadTargetDeterminer::Result 172 DownloadTargetDeterminer::DoGenerateTargetPath() { 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 174 DCHECK(local_path_.empty()); 175 DCHECK(!should_prompt_); 176 DCHECK(!should_notify_extensions_); 177 DCHECK_EQ(DownloadPathReservationTracker::OVERWRITE, conflict_action_); 178 bool is_forced_path = !download_->GetForcedFilePath().empty(); 179 180 next_state_ = STATE_NOTIFY_EXTENSIONS; 181 182 if (!virtual_path_.empty() && HasPromptedForPath() && !is_forced_path) { 183 // The download is being resumed and the user has already been prompted for 184 // a path. Assume that it's okay to overwrite the file if there's a conflict 185 // and reuse the selection. 186 should_prompt_ = ShouldPromptForDownload(virtual_path_); 187 } else if (!is_forced_path) { 188 // If we don't have a forced path, we should construct a path for the 189 // download. Forced paths are only specified for programmatic downloads 190 // (WebStore, Drag&Drop). Treat the path as a virtual path. We will 191 // eventually determine whether this is a local path and if not, figure out 192 // a local path. 193 std::string default_filename( 194 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); 195 base::FilePath generated_filename = net::GenerateFileName( 196 download_->GetURL(), 197 download_->GetContentDisposition(), 198 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset), 199 download_->GetSuggestedFilename(), 200 download_->GetMimeType(), 201 default_filename); 202 should_prompt_ = ShouldPromptForDownload(generated_filename); 203 base::FilePath target_directory; 204 if (should_prompt_) { 205 DCHECK(!download_prefs_->IsDownloadPathManaged()); 206 // If the user is going to be prompted and the user has been prompted 207 // before, then always prefer the last directory that the user selected. 208 target_directory = download_prefs_->SaveFilePath(); 209 } else { 210 target_directory = download_prefs_->DownloadPath(); 211 } 212 virtual_path_ = target_directory.Append(generated_filename); 213 conflict_action_ = DownloadPathReservationTracker::UNIQUIFY; 214 should_notify_extensions_ = true; 215 } else { 216 virtual_path_ = download_->GetForcedFilePath(); 217 // If this is a resumed download which was previously interrupted due to an 218 // issue with the forced path, the user is still not prompted. If the path 219 // supplied to a programmatic download is invalid, then the caller needs to 220 // intervene. 221 } 222 DCHECK(virtual_path_.IsAbsolute()); 223 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe(); 224 225 // If the download is DOA, don't bother going any further. This would be the 226 // case for a download that failed to initialize (e.g. the initial temporary 227 // file couldn't be created because both the downloads directory and the 228 // temporary directory are unwriteable). 229 // 230 // A virtual path is determined for DOA downloads for display purposes. This 231 // is why this check is performed here instead of at the start. 232 if (download_->GetState() != DownloadItem::IN_PROGRESS) 233 return COMPLETE; 234 return CONTINUE; 235 } 236 237 DownloadTargetDeterminer::Result 238 DownloadTargetDeterminer::DoNotifyExtensions() { 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 240 DCHECK(!virtual_path_.empty()); 241 242 next_state_ = STATE_RESERVE_VIRTUAL_PATH; 243 244 if (!should_notify_extensions_) 245 return CONTINUE; 246 247 delegate_->NotifyExtensions(download_, virtual_path_, 248 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone, 249 weak_ptr_factory_.GetWeakPtr())); 250 return QUIT_DOLOOP; 251 } 252 253 void DownloadTargetDeterminer::NotifyExtensionsDone( 254 const base::FilePath& suggested_path, 255 DownloadPathReservationTracker::FilenameConflictAction conflict_action) { 256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 257 DVLOG(20) << "Extension suggested path: " << suggested_path.AsUTF8Unsafe(); 258 259 // Extensions should not call back here more than once. 260 DCHECK_EQ(STATE_RESERVE_VIRTUAL_PATH, next_state_); 261 262 if (!suggested_path.empty()) { 263 // If an extension overrides the filename, then the target directory will be 264 // forced to download_prefs_->DownloadPath() since extensions cannot place 265 // downloaded files anywhere except there. This prevents subdirectories from 266 // accumulating: if an extension is allowed to say that a file should go in 267 // last_download_path/music/foo.mp3, then last_download_path will accumulate 268 // the subdirectory /music/ so that the next download may end up in 269 // Downloads/music/music/music/bar.mp3. 270 base::FilePath new_path(download_prefs_->DownloadPath().Append( 271 suggested_path).NormalizePathSeparators()); 272 // Do not pass a mime type to GenerateSafeFileName so that it does not force 273 // the filename to have an extension if the (Chrome) extension does not 274 // suggest it. 275 net::GenerateSafeFileName(std::string(), false, &new_path); 276 virtual_path_ = new_path; 277 create_target_directory_ = true; 278 } 279 // An extension may set conflictAction without setting filename. 280 if (conflict_action != DownloadPathReservationTracker::UNIQUIFY) 281 conflict_action_ = conflict_action; 282 283 DoLoop(); 284 } 285 286 DownloadTargetDeterminer::Result 287 DownloadTargetDeterminer::DoReserveVirtualPath() { 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 289 DCHECK(!virtual_path_.empty()); 290 291 next_state_ = STATE_PROMPT_USER_FOR_DOWNLOAD_PATH; 292 293 delegate_->ReserveVirtualPath( 294 download_, virtual_path_, create_target_directory_, conflict_action_, 295 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone, 296 weak_ptr_factory_.GetWeakPtr())); 297 return QUIT_DOLOOP; 298 } 299 300 void DownloadTargetDeterminer::ReserveVirtualPathDone( 301 const base::FilePath& path, bool verified) { 302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 303 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe() 304 << " Verified:" << verified; 305 DCHECK_EQ(STATE_PROMPT_USER_FOR_DOWNLOAD_PATH, next_state_); 306 307 should_prompt_ = (should_prompt_ || !verified); 308 virtual_path_ = path; 309 DoLoop(); 310 } 311 312 DownloadTargetDeterminer::Result 313 DownloadTargetDeterminer::DoPromptUserForDownloadPath() { 314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 315 DCHECK(!virtual_path_.empty()); 316 317 next_state_ = STATE_DETERMINE_LOCAL_PATH; 318 319 if (should_prompt_) { 320 delegate_->PromptUserForDownloadPath( 321 download_, 322 virtual_path_, 323 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone, 324 weak_ptr_factory_.GetWeakPtr())); 325 return QUIT_DOLOOP; 326 } 327 return CONTINUE; 328 } 329 330 void DownloadTargetDeterminer::PromptUserForDownloadPathDone( 331 const base::FilePath& virtual_path) { 332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 333 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe(); 334 if (virtual_path.empty()) { 335 CancelOnFailureAndDeleteSelf(); 336 return; 337 } 338 DCHECK_EQ(STATE_DETERMINE_LOCAL_PATH, next_state_); 339 340 virtual_path_ = virtual_path; 341 download_prefs_->SetSaveFilePath(virtual_path_.DirName()); 342 DoLoop(); 343 } 344 345 DownloadTargetDeterminer::Result 346 DownloadTargetDeterminer::DoDetermineLocalPath() { 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 348 DCHECK(!virtual_path_.empty()); 349 DCHECK(local_path_.empty()); 350 351 next_state_ = STATE_DETERMINE_MIME_TYPE; 352 353 delegate_->DetermineLocalPath( 354 download_, 355 virtual_path_, 356 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, 357 weak_ptr_factory_.GetWeakPtr())); 358 return QUIT_DOLOOP; 359 } 360 361 void DownloadTargetDeterminer::DetermineLocalPathDone( 362 const base::FilePath& local_path) { 363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 364 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); 365 if (local_path.empty()) { 366 // Path subsitution failed. 367 CancelOnFailureAndDeleteSelf(); 368 return; 369 } 370 DCHECK_EQ(STATE_DETERMINE_MIME_TYPE, next_state_); 371 372 local_path_ = local_path; 373 DoLoop(); 374 } 375 376 DownloadTargetDeterminer::Result 377 DownloadTargetDeterminer::DoDetermineMimeType() { 378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 379 DCHECK(!virtual_path_.empty()); 380 DCHECK(!local_path_.empty()); 381 DCHECK(mime_type_.empty()); 382 383 next_state_ = STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER; 384 385 if (virtual_path_ == local_path_) { 386 delegate_->GetFileMimeType( 387 local_path_, 388 base::Bind(&DownloadTargetDeterminer::DetermineMimeTypeDone, 389 weak_ptr_factory_.GetWeakPtr())); 390 return QUIT_DOLOOP; 391 } 392 return CONTINUE; 393 } 394 395 void DownloadTargetDeterminer::DetermineMimeTypeDone( 396 const std::string& mime_type) { 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 DVLOG(20) << "MIME type: " << mime_type; 399 DCHECK_EQ(STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER, next_state_); 400 401 mime_type_ = mime_type; 402 DoLoop(); 403 } 404 405 #if defined(ENABLE_PLUGINS) 406 // The code below is used by DoDetermineIfHandledSafely to determine if the 407 // file type is handled by a sandboxed plugin. 408 namespace { 409 410 void InvokeClosureAfterGetPluginCallback( 411 const base::Closure& closure, 412 const std::vector<content::WebPluginInfo>& unused) { 413 closure.Run(); 414 } 415 416 enum ActionOnStalePluginList { 417 RETRY_IF_STALE_PLUGIN_LIST, 418 IGNORE_IF_STALE_PLUGIN_LIST 419 }; 420 421 void IsHandledBySafePlugin(content::ResourceContext* resource_context, 422 const GURL& url, 423 const std::string& mime_type, 424 ActionOnStalePluginList stale_plugin_action, 425 const base::Callback<void(bool)>& callback) { 426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 427 DCHECK(!mime_type.empty()); 428 using content::WebPluginInfo; 429 430 std::string actual_mime_type; 431 bool is_stale = false; 432 WebPluginInfo plugin_info; 433 434 content::PluginService* plugin_service = 435 content::PluginService::GetInstance(); 436 bool plugin_found = plugin_service->GetPluginInfo(-1, -1, resource_context, 437 url, GURL(), mime_type, 438 false, &is_stale, 439 &plugin_info, 440 &actual_mime_type); 441 if (is_stale && stale_plugin_action == RETRY_IF_STALE_PLUGIN_LIST) { 442 // The GetPlugins call causes the plugin list to be refreshed. Once that's 443 // done we can retry the GetPluginInfo call. We break out of this cycle 444 // after a single retry in order to avoid retrying indefinitely. 445 plugin_service->GetPlugins( 446 base::Bind(&InvokeClosureAfterGetPluginCallback, 447 base::Bind(&IsHandledBySafePlugin, 448 resource_context, 449 url, 450 mime_type, 451 IGNORE_IF_STALE_PLUGIN_LIST, 452 callback))); 453 return; 454 } 455 // In practice, we assume that retrying once is enough. 456 DCHECK(!is_stale); 457 bool is_handled_safely = 458 plugin_found && 459 (plugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS || 460 plugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS); 461 BrowserThread::PostTask( 462 BrowserThread::UI, FROM_HERE, base::Bind(callback, is_handled_safely)); 463 } 464 465 } // namespace 466 #endif // defined(ENABLE_PLUGINS) 467 468 DownloadTargetDeterminer::Result 469 DownloadTargetDeterminer::DoDetermineIfHandledSafely() { 470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 471 DCHECK(!virtual_path_.empty()); 472 DCHECK(!local_path_.empty()); 473 DCHECK(!is_filetype_handled_safely_); 474 475 next_state_ = STATE_DETERMINE_IF_ADOBE_READER_UP_TO_DATE; 476 477 if (mime_type_.empty()) 478 return CONTINUE; 479 480 if (net::IsSupportedMimeType(mime_type_)) { 481 is_filetype_handled_safely_ = true; 482 return CONTINUE; 483 } 484 485 #if defined(ENABLE_PLUGINS) 486 BrowserThread::PostTask( 487 BrowserThread::IO, 488 FROM_HERE, 489 base::Bind( 490 &IsHandledBySafePlugin, 491 GetProfile()->GetResourceContext(), 492 net::FilePathToFileURL(local_path_), 493 mime_type_, 494 RETRY_IF_STALE_PLUGIN_LIST, 495 base::Bind(&DownloadTargetDeterminer::DetermineIfHandledSafelyDone, 496 weak_ptr_factory_.GetWeakPtr()))); 497 return QUIT_DOLOOP; 498 #else 499 return CONTINUE; 500 #endif 501 } 502 503 #if defined(ENABLE_PLUGINS) 504 void DownloadTargetDeterminer::DetermineIfHandledSafelyDone( 505 bool is_handled_safely) { 506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 507 DVLOG(20) << "Is file type handled safely: " << is_filetype_handled_safely_; 508 DCHECK_EQ(STATE_DETERMINE_IF_ADOBE_READER_UP_TO_DATE, next_state_); 509 is_filetype_handled_safely_ = is_handled_safely; 510 DoLoop(); 511 } 512 #endif 513 514 DownloadTargetDeterminer::Result 515 DownloadTargetDeterminer::DoDetermineIfAdobeReaderUpToDate() { 516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 517 518 next_state_ = STATE_CHECK_DOWNLOAD_URL; 519 520 #if defined(OS_WIN) 521 if (!local_path_.MatchesExtension(FILE_PATH_LITERAL(".pdf"))) 522 return CONTINUE; 523 if (!IsAdobeReaderDefaultPDFViewer()) { 524 g_is_adobe_reader_up_to_date_ = false; 525 return CONTINUE; 526 } 527 528 base::PostTaskAndReplyWithResult( 529 BrowserThread::GetBlockingPool(), 530 FROM_HERE, 531 base::Bind(&::IsAdobeReaderUpToDate), 532 base::Bind(&DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone, 533 weak_ptr_factory_.GetWeakPtr())); 534 return QUIT_DOLOOP; 535 #else 536 return CONTINUE; 537 #endif 538 } 539 540 #if defined(OS_WIN) 541 void DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone( 542 bool adobe_reader_up_to_date) { 543 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 544 DVLOG(20) << "Is Adobe Reader Up To Date: " << adobe_reader_up_to_date; 545 DCHECK_EQ(STATE_CHECK_DOWNLOAD_URL, next_state_); 546 g_is_adobe_reader_up_to_date_ = adobe_reader_up_to_date; 547 DoLoop(); 548 } 549 #endif 550 551 DownloadTargetDeterminer::Result 552 DownloadTargetDeterminer::DoCheckDownloadUrl() { 553 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 554 DCHECK(!virtual_path_.empty()); 555 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; 556 delegate_->CheckDownloadUrl( 557 download_, 558 virtual_path_, 559 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, 560 weak_ptr_factory_.GetWeakPtr())); 561 return QUIT_DOLOOP; 562 } 563 564 void DownloadTargetDeterminer::CheckDownloadUrlDone( 565 content::DownloadDangerType danger_type) { 566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 567 DVLOG(20) << "URL Check Result:" << danger_type; 568 DCHECK_EQ(STATE_CHECK_VISITED_REFERRER_BEFORE, next_state_); 569 danger_type_ = danger_type; 570 DoLoop(); 571 } 572 573 DownloadTargetDeterminer::Result 574 DownloadTargetDeterminer::DoCheckVisitedReferrerBefore() { 575 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 576 577 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH; 578 579 // Checking if there are prior visits to the referrer is only necessary if the 580 // danger level of the download depends on the file type. 581 if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS && 582 danger_type_ != content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) 583 return CONTINUE; 584 585 // Assume that: 586 // IsDangerousFile(VISITED_REFERRER) => IsDangerousFile(NO_VISITS_...) 587 // I.e. having visited a referrer only lowers a file's danger level. 588 if (IsDangerousFile(NO_VISITS_TO_REFERRER)) { 589 // Only need to ping the history DB if the download would be considered safe 590 // if there are prior visits and is considered dangerous otherwise. 591 if (!IsDangerousFile(VISITED_REFERRER)) { 592 // HistoryServiceFactory redirects incognito profiles to on-record 593 // profiles. There's no history for on-record profiles in unit_tests. 594 HistoryService* history_service = HistoryServiceFactory::GetForProfile( 595 GetProfile(), Profile::EXPLICIT_ACCESS); 596 597 if (history_service && download_->GetReferrerUrl().is_valid()) { 598 history_service->GetVisibleVisitCountToHost( 599 download_->GetReferrerUrl(), 600 base::Bind( 601 &VisitCountsToVisitedBefore, 602 base::Bind( 603 &DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone, 604 weak_ptr_factory_.GetWeakPtr())), 605 &history_tracker_); 606 return QUIT_DOLOOP; 607 } 608 } 609 610 // If the danger level doesn't depend on having visited the refererrer URL 611 // or if original profile doesn't have a HistoryService or the referrer url 612 // is invalid, then assume the referrer has not been visited before. 613 is_dangerous_file_ = true; 614 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) 615 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; 616 } 617 return CONTINUE; 618 } 619 620 void DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone( 621 bool visited_referrer_before) { 622 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 623 DCHECK_EQ(STATE_DETERMINE_INTERMEDIATE_PATH, next_state_); 624 if (IsDangerousFile(visited_referrer_before ? VISITED_REFERRER 625 : NO_VISITS_TO_REFERRER)) { 626 is_dangerous_file_ = true; 627 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) 628 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; 629 } 630 DoLoop(); 631 } 632 633 DownloadTargetDeterminer::Result 634 DownloadTargetDeterminer::DoDetermineIntermediatePath() { 635 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 636 DCHECK(!virtual_path_.empty()); 637 DCHECK(!local_path_.empty()); 638 DCHECK(intermediate_path_.empty()); 639 DCHECK(!virtual_path_.MatchesExtension(kCrdownloadSuffix)); 640 DCHECK(!local_path_.MatchesExtension(kCrdownloadSuffix)); 641 642 next_state_ = STATE_NONE; 643 644 // Note that the intermediate filename is always uniquified (i.e. if a file by 645 // the same name exists, it is never overwritten). Therefore the code below 646 // does not attempt to find a name that doesn't conflict with an existing 647 // file. 648 649 // If the actual target of the download is a virtual path, then the local path 650 // is considered to point to a temporary path. A separate intermediate path is 651 // unnecessary since the local path already serves that purpose. 652 if (virtual_path_.BaseName() != local_path_.BaseName()) { 653 intermediate_path_ = local_path_; 654 return COMPLETE; 655 } 656 657 // If the download has a forced path and is safe, then just use the 658 // target path. In practice the temporary download file that was created prior 659 // to download filename determination is already named 660 // download_->GetForcedFilePath(). 661 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS && 662 !download_->GetForcedFilePath().empty()) { 663 DCHECK_EQ(download_->GetForcedFilePath().value(), local_path_.value()); 664 intermediate_path_ = local_path_; 665 return COMPLETE; 666 } 667 668 // Other safe downloads get a .crdownload suffix for their intermediate name. 669 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) { 670 intermediate_path_ = GetCrDownloadPath(local_path_); 671 return COMPLETE; 672 } 673 674 // If this is a resumed download, then re-use the existing intermediate path 675 // if one is available. A resumed download shouldn't cause a non-dangerous 676 // download to be considered dangerous upon resumption. Therefore the 677 // intermediate file should already be in the correct form. 678 if (is_resumption_ && !download_->GetFullPath().empty() && 679 local_path_.DirName() == download_->GetFullPath().DirName()) { 680 DCHECK_NE(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 681 download_->GetDangerType()); 682 DCHECK_EQ(kCrdownloadSuffix, download_->GetFullPath().Extension()); 683 intermediate_path_ = download_->GetFullPath(); 684 return COMPLETE; 685 } 686 687 // Dangerous downloads receive a random intermediate name that looks like: 688 // 'Unconfirmed <random>.crdownload'. 689 const base::FilePath::CharType kUnconfirmedFormatSuffix[] = 690 FILE_PATH_LITERAL(" %d.crdownload"); 691 // Range of the <random> uniquifier. 692 const int kUnconfirmedUniquifierRange = 1000000; 693 #if defined(OS_WIN) 694 base::string16 unconfirmed_format = 695 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); 696 #else 697 std::string unconfirmed_format = 698 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); 699 #endif 700 unconfirmed_format.append(kUnconfirmedFormatSuffix); 701 702 base::FilePath::StringType file_name = base::StringPrintf( 703 unconfirmed_format.c_str(), 704 base::RandInt(0, kUnconfirmedUniquifierRange)); 705 intermediate_path_ = local_path_.DirName().Append(file_name); 706 return COMPLETE; 707 } 708 709 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { 710 DCHECK(download_); 711 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() 712 << " Local:" << local_path_.AsUTF8Unsafe() 713 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() 714 << " Should prompt:" << should_prompt_ 715 << " Danger type:" << danger_type_ 716 << " Is dangerous file:" << is_dangerous_file_; 717 scoped_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo); 718 719 target_info->target_path = local_path_; 720 target_info->target_disposition = 721 (HasPromptedForPath() || should_prompt_ 722 ? DownloadItem::TARGET_DISPOSITION_PROMPT 723 : DownloadItem::TARGET_DISPOSITION_OVERWRITE); 724 target_info->danger_type = danger_type_; 725 target_info->is_dangerous_file = is_dangerous_file_; 726 target_info->intermediate_path = intermediate_path_; 727 target_info->mime_type = mime_type_; 728 target_info->is_filetype_handled_safely = is_filetype_handled_safely_; 729 730 base::MessageLoop::current()->PostTask( 731 FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info))); 732 completion_callback_.Reset(); 733 delete this; 734 } 735 736 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { 737 // Path substitution failed. 738 virtual_path_.clear(); 739 local_path_.clear(); 740 intermediate_path_.clear(); 741 ScheduleCallbackAndDeleteSelf(); 742 } 743 744 Profile* DownloadTargetDeterminer::GetProfile() { 745 DCHECK(download_->GetBrowserContext()); 746 return Profile::FromBrowserContext(download_->GetBrowserContext()); 747 } 748 749 bool DownloadTargetDeterminer::ShouldPromptForDownload( 750 const base::FilePath& filename) const { 751 if (is_resumption_) { 752 // For resumed downloads, if the target disposition or prefs require 753 // prompting, the user has already been prompted. Try to respect the user's 754 // selection, unless we've discovered that the target path cannot be used 755 // for some reason. 756 content::DownloadInterruptReason reason = download_->GetLastReason(); 757 return (reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED || 758 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE || 759 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE); 760 } 761 762 // If the download path is forced, don't prompt. 763 if (!download_->GetForcedFilePath().empty()) { 764 // 'Save As' downloads shouldn't have a forced path. 765 DCHECK(DownloadItem::TARGET_DISPOSITION_PROMPT != 766 download_->GetTargetDisposition()); 767 return false; 768 } 769 770 // Don't ask where to save if the download path is managed. Even if the user 771 // wanted to be prompted for "all" downloads, or if this was a 'Save As' 772 // download. 773 if (download_prefs_->IsDownloadPathManaged()) 774 return false; 775 776 // Prompt if this is a 'Save As' download. 777 if (download_->GetTargetDisposition() == 778 DownloadItem::TARGET_DISPOSITION_PROMPT) 779 return true; 780 781 // Check if the user has the "Always prompt for download location" preference 782 // set. If so we prompt for most downloads except for the following scenarios: 783 // 1) Extension installation. Note that we only care here about the case where 784 // an extension is installed, not when one is downloaded with "save as...". 785 // 2) Filetypes marked "always open." If the user just wants this file opened, 786 // don't bother asking where to keep it. 787 if (download_prefs_->PromptForDownload() && 788 !download_crx_util::IsExtensionDownload(*download_) && 789 !filename.MatchesExtension(extensions::kExtensionFileExtension) && 790 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename)) 791 return true; 792 793 // Otherwise, don't prompt. Note that the user might still be prompted if 794 // there are unresolved conflicts during path reservation (e.g. due to the 795 // target path being unwriteable or because there are too many conflicting 796 // files), or if an extension signals that the user be prompted on a filename 797 // conflict. 798 return false; 799 } 800 801 bool DownloadTargetDeterminer::HasPromptedForPath() const { 802 return (is_resumption_ && download_->GetTargetDisposition() == 803 DownloadItem::TARGET_DISPOSITION_PROMPT); 804 } 805 806 bool DownloadTargetDeterminer::IsDangerousFile(PriorVisitsToReferrer visits) { 807 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 808 809 // If the user has has been prompted or will be, assume that the user has 810 // approved the download. A programmatic download is considered safe unless it 811 // contains malware. 812 if (HasPromptedForPath() || should_prompt_ || 813 !download_->GetForcedFilePath().empty()) 814 return false; 815 816 const bool is_extension_download = 817 download_crx_util::IsExtensionDownload(*download_); 818 819 // User-initiated extension downloads from pref-whitelisted sources are not 820 // considered dangerous. 821 if (download_->HasUserGesture() && 822 is_extension_download && 823 download_crx_util::OffStoreInstallAllowedByPrefs( 824 GetProfile(), *download_)) { 825 return false; 826 } 827 828 #if defined(ENABLE_EXTENSIONS) 829 // Extensions that are not from the gallery are considered dangerous. 830 // When off-store install is disabled we skip this, since in this case, we 831 // will not offer to install the extension. 832 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() && 833 is_extension_download && 834 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) { 835 return true; 836 } 837 #endif 838 839 // Anything the user has marked auto-open is OK if it's user-initiated. 840 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) && 841 download_->HasUserGesture()) 842 return false; 843 844 switch (download_util::GetFileDangerLevel(virtual_path_.BaseName())) { 845 case download_util::NOT_DANGEROUS: 846 return false; 847 848 case download_util::ALLOW_ON_USER_GESTURE: 849 // "Allow on user gesture" is OK when we have a user gesture and the 850 // hosting page has been visited before today. 851 if (download_->GetTransitionType() & 852 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) { 853 return false; 854 } 855 return !download_->HasUserGesture() || visits == NO_VISITS_TO_REFERRER; 856 857 case download_util::DANGEROUS: 858 return true; 859 } 860 NOTREACHED(); 861 return false; 862 } 863 864 void DownloadTargetDeterminer::OnDownloadDestroyed( 865 DownloadItem* download) { 866 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 867 DCHECK_EQ(download_, download); 868 CancelOnFailureAndDeleteSelf(); 869 } 870 871 // static 872 void DownloadTargetDeterminer::Start(content::DownloadItem* download, 873 const base::FilePath& initial_virtual_path, 874 DownloadPrefs* download_prefs, 875 DownloadTargetDeterminerDelegate* delegate, 876 const CompletionCallback& callback) { 877 // DownloadTargetDeterminer owns itself and will self destruct when the job is 878 // complete or the download item is destroyed. The callback is always invoked 879 // asynchronously. 880 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, 881 delegate, callback); 882 } 883 884 // static 885 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath( 886 const base::FilePath& suggested_path) { 887 return base::FilePath(suggested_path.value() + kCrdownloadSuffix); 888 } 889 890 #if defined(OS_WIN) 891 // static 892 bool DownloadTargetDeterminer::IsAdobeReaderUpToDate() { 893 return g_is_adobe_reader_up_to_date_; 894 } 895 #endif 896