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