| 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/download_handler.h" |
| 31 #include "chrome/browser/chromeos/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 // |
| 182 // A virtual path is determined for DOA downloads for display purposes. This |
| 183 // is why this check is performed here instead of at the start. |
| 184 if (!download_->IsInProgress()) |
| 185 return COMPLETE; |
| 186 return CONTINUE; |
| 187 } |
| 188 |
| 189 DownloadTargetDeterminer::Result |
| 190 DownloadTargetDeterminer::DoNotifyExtensions() { |
| 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 192 DCHECK(!virtual_path_.empty()); |
| 193 |
| 194 next_state_ = STATE_RESERVE_VIRTUAL_PATH; |
| 195 |
| 196 // If the target path is forced or if we don't have an extensions event |
| 197 // router, then proceed with the original path. |
| 198 if (!download_->GetForcedFilePath().empty()) |
| 199 return CONTINUE; |
| 200 |
| 201 delegate_->NotifyExtensions(download_, virtual_path_, |
| 202 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone, |
| 203 weak_ptr_factory_.GetWeakPtr())); |
| 204 return QUIT_DOLOOP; |
| 205 } |
| 206 |
| 207 void DownloadTargetDeterminer::NotifyExtensionsDone( |
| 208 const base::FilePath& suggested_path, |
| 209 DownloadPathReservationTracker::FilenameConflictAction conflict_action) { |
| 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 211 DVLOG(20) << "Extension suggested path: " << suggested_path.AsUTF8Unsafe(); |
| 212 |
| 213 if (!suggested_path.empty()) { |
| 214 // If an extension overrides the filename, then the target directory will be |
| 215 // forced to download_prefs_->DownloadPath() since extensions cannot place |
| 216 // downloaded files anywhere except there. This prevents subdirectories from |
| 217 // accumulating: if an extension is allowed to say that a file should go in |
| 218 // last_download_path/music/foo.mp3, then last_download_path will accumulate |
| 219 // the subdirectory /music/ so that the next download may end up in |
| 220 // Downloads/music/music/music/bar.mp3. |
| 221 base::FilePath new_path(download_prefs_->DownloadPath().Append( |
| 222 suggested_path).NormalizePathSeparators()); |
| 223 // Do not pass a mime type to GenerateSafeFileName so that it does not force |
| 224 // the filename to have an extension if the (Chrome) extension does not |
| 225 // suggest it. |
| 226 net::GenerateSafeFileName(std::string(), false, &new_path); |
| 227 virtual_path_ = new_path; |
| 228 conflict_action_ = conflict_action; |
| 229 } |
| 230 |
| 231 DoLoop(); |
| 232 } |
| 233 |
| 234 DownloadTargetDeterminer::Result |
| 235 DownloadTargetDeterminer::DoReserveVirtualPath() { |
| 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 237 DCHECK(!virtual_path_.empty()); |
| 238 |
| 239 next_state_ = STATE_PROMPT_USER_FOR_DOWNLOAD_PATH; |
| 240 |
| 241 delegate_->ReserveVirtualPath( |
| 242 download_, virtual_path_, conflict_action_, |
| 243 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone, |
| 244 weak_ptr_factory_.GetWeakPtr())); |
| 245 return QUIT_DOLOOP; |
| 246 } |
| 247 |
| 248 void DownloadTargetDeterminer::ReserveVirtualPathDone( |
| 249 const base::FilePath& path, bool verified) { |
| 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 251 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe() |
| 252 << " Verified:" << verified; |
| 253 should_prompt_ = (should_prompt_ || !verified); |
| 254 virtual_path_ = path; |
| 255 DoLoop(); |
| 256 } |
| 257 |
| 258 DownloadTargetDeterminer::Result |
| 259 DownloadTargetDeterminer::DoPromptUserForDownloadPath() { |
| 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 261 DCHECK(!virtual_path_.empty()); |
| 262 |
| 263 next_state_ = STATE_DETERMINE_LOCAL_PATH; |
| 264 |
| 265 if (should_prompt_) { |
| 266 delegate_->PromptUserForDownloadPath( |
| 267 download_, |
| 268 virtual_path_, |
| 269 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone, |
| 270 weak_ptr_factory_.GetWeakPtr())); |
| 271 return QUIT_DOLOOP; |
| 272 } |
| 273 return CONTINUE; |
| 274 } |
| 275 |
| 276 void DownloadTargetDeterminer::PromptUserForDownloadPathDone( |
| 277 const base::FilePath& virtual_path) { |
| 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 279 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe(); |
| 280 if (virtual_path.empty()) { |
| 281 CancelOnFailureAndDeleteSelf(); |
| 282 return; |
| 283 } |
| 284 virtual_path_ = virtual_path; |
| 285 DoLoop(); |
| 286 } |
| 287 |
| 288 DownloadTargetDeterminer::Result |
| 289 DownloadTargetDeterminer::DoDetermineLocalPath() { |
| 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 291 DCHECK(!virtual_path_.empty()); |
| 292 DCHECK(local_path_.empty()); |
| 293 |
| 294 next_state_ = STATE_CHECK_DOWNLOAD_URL; |
| 295 |
| 296 delegate_->DetermineLocalPath( |
| 297 download_, |
| 298 virtual_path_, |
| 299 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone, |
| 300 weak_ptr_factory_.GetWeakPtr())); |
| 301 return QUIT_DOLOOP; |
| 302 } |
| 303 |
| 304 void DownloadTargetDeterminer::DetermineLocalPathDone( |
| 305 const base::FilePath& local_path) { |
| 306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 307 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe(); |
| 308 if (local_path.empty()) { |
| 309 // Path subsitution failed. |
| 310 CancelOnFailureAndDeleteSelf(); |
| 311 return; |
| 312 } |
| 313 local_path_ = local_path; |
| 314 DoLoop(); |
| 315 } |
| 316 |
| 317 DownloadTargetDeterminer::Result |
| 318 DownloadTargetDeterminer::DoCheckDownloadUrl() { |
| 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 320 DCHECK(!virtual_path_.empty()); |
| 321 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE; |
| 322 delegate_->CheckDownloadUrl( |
| 323 download_, |
| 324 virtual_path_, |
| 325 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone, |
| 326 weak_ptr_factory_.GetWeakPtr())); |
| 327 return QUIT_DOLOOP; |
| 328 } |
| 329 |
| 330 void DownloadTargetDeterminer::CheckDownloadUrlDone( |
| 331 content::DownloadDangerType danger_type) { |
| 332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 333 DVLOG(20) << "URL Check Result:" << danger_type; |
| 334 danger_type_ = danger_type; |
| 335 DoLoop(); |
| 336 } |
| 337 |
| 338 DownloadTargetDeterminer::Result |
| 339 DownloadTargetDeterminer::DoCheckVisitedReferrerBefore() { |
| 340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 341 |
| 342 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH; |
| 343 |
| 344 // Checking if there are prior visits to the referrer is only necessary if the |
| 345 // danger level of the download depends on the file type. This excludes cases |
| 346 // where the download has already been deemed dangerous, or where the user is |
| 347 // going to be prompted or where this is a programmatic download. |
| 348 if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS || |
| 349 should_prompt_ || |
| 350 !download_->GetForcedFilePath().empty()) { |
| 351 return CONTINUE; |
| 352 } |
| 353 |
| 354 // Assume that: |
| 355 // IsDangerousFile(VISITED_REFERRER) => IsDangerousFile(NO_VISITS_...) |
| 356 // I.e. having visited a referrer only lowers a file's danger level. |
| 357 if (IsDangerousFile(NO_VISITS_TO_REFERRER)) { |
| 358 // Only need to ping the history DB if the download would be considered safe |
| 359 // if there are prior visits and is considered dangerous otherwise. |
| 360 if (!IsDangerousFile(VISITED_REFERRER)) { |
| 361 // HistoryServiceFactory redirects incognito profiles to on-record |
| 362 // profiles. There's no history for on-record profiles in unit_tests. |
| 363 HistoryService* history_service = HistoryServiceFactory::GetForProfile( |
| 364 GetProfile(), Profile::EXPLICIT_ACCESS); |
| 365 |
| 366 if (history_service && download_->GetReferrerUrl().is_valid()) { |
| 367 history_service->GetVisibleVisitCountToHost( |
| 368 download_->GetReferrerUrl(), &history_consumer_, |
| 369 base::Bind(&VisitCountsToVisitedBefore, base::Bind( |
| 370 &DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone, |
| 371 weak_ptr_factory_.GetWeakPtr()))); |
| 372 return QUIT_DOLOOP; |
| 373 } |
| 374 } |
| 375 |
| 376 // If the danger level doesn't depend on having visited the refererrer URL |
| 377 // or if original profile doesn't have a HistoryService or the referrer url |
| 378 // is invalid, then assume the referrer has not been visited before. |
| 379 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; |
| 380 } |
| 381 return CONTINUE; |
| 382 } |
| 383 |
| 384 void DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone( |
| 385 bool visited_referrer_before) { |
| 386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 387 if (IsDangerousFile( |
| 388 visited_referrer_before ? VISITED_REFERRER : NO_VISITS_TO_REFERRER)) |
| 389 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; |
| 390 DoLoop(); |
| 391 } |
| 392 |
| 393 DownloadTargetDeterminer::Result |
| 394 DownloadTargetDeterminer::DoDetermineIntermediatePath() { |
| 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 396 DCHECK(!virtual_path_.empty()); |
| 397 DCHECK(!local_path_.empty()); |
| 398 DCHECK(intermediate_path_.empty()); |
| 399 |
| 400 next_state_ = STATE_NONE; |
| 401 |
| 402 // Note that the intermediate filename is always uniquified (i.e. if a file by |
| 403 // the same name exists, it is never overwritten). Therefore the code below |
| 404 // does not attempt to find a name that doesn't conflict with an existing |
| 405 // file. |
| 406 |
| 407 // If the actual target of the download is a virtual path, then the local path |
| 408 // is considered to point to a temporary path. A separate intermediate path is |
| 409 // unnecessary since the local path already serves that purpose. |
| 410 if (virtual_path_.BaseName() != local_path_.BaseName()) { |
| 411 intermediate_path_ = local_path_; |
| 412 return COMPLETE; |
| 413 } |
| 414 |
| 415 // If the download has a forced path and is safe, then just use the |
| 416 // target path. In practice the temporary download file that was created prior |
| 417 // to download filename determination is already named |
| 418 // download_->GetForcedFilePath(). |
| 419 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS && |
| 420 !download_->GetForcedFilePath().empty()) { |
| 421 DCHECK_EQ(download_->GetForcedFilePath().value(), local_path_.value()); |
| 422 intermediate_path_ = local_path_; |
| 423 return COMPLETE; |
| 424 } |
| 425 |
| 426 // Other safe downloads get a .crdownload suffix for their intermediate name. |
| 427 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) { |
| 428 intermediate_path_ = download_util::GetCrDownloadPath(local_path_); |
| 429 return COMPLETE; |
| 430 } |
| 431 |
| 432 // Dangerous downloads receive a random intermediate name that looks like: |
| 433 // 'Unconfirmed <random>.crdownload'. |
| 434 const base::FilePath::CharType kUnconfirmedFormatSuffix[] = |
| 435 FILE_PATH_LITERAL(" %d.crdownload"); |
| 436 // Range of the <random> uniquifier. |
| 437 const int kUnconfirmedUniquifierRange = 1000000; |
| 438 #if defined(OS_WIN) |
| 439 string16 unconfirmed_format = |
| 440 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); |
| 441 #else |
| 442 std::string unconfirmed_format = |
| 443 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); |
| 444 #endif |
| 445 unconfirmed_format.append(kUnconfirmedFormatSuffix); |
| 446 |
| 447 base::FilePath::StringType file_name = base::StringPrintf( |
| 448 unconfirmed_format.c_str(), |
| 449 base::RandInt(0, kUnconfirmedUniquifierRange)); |
| 450 intermediate_path_ = local_path_.DirName().Append(file_name); |
| 451 return COMPLETE; |
| 452 } |
| 453 |
| 454 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { |
| 455 DCHECK(download_); |
| 456 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe() |
| 457 << " Local:" << local_path_.AsUTF8Unsafe() |
| 458 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe() |
| 459 << " Should prompt:" << should_prompt_ |
| 460 << " Danger type:" << danger_type_; |
| 461 MessageLoop::current()->PostTask( |
| 462 FROM_HERE, |
| 463 base::Bind(completion_callback_, |
| 464 local_path_, |
| 465 (should_prompt_ ? DownloadItem::TARGET_DISPOSITION_PROMPT : |
| 466 DownloadItem::TARGET_DISPOSITION_OVERWRITE), |
| 467 danger_type_, |
| 468 intermediate_path_)); |
| 469 completion_callback_.Reset(); |
| 470 delete this; |
| 471 } |
| 472 |
| 473 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() { |
| 474 // Path substitution failed. |
| 475 virtual_path_.clear(); |
| 476 local_path_.clear(); |
| 477 intermediate_path_.clear(); |
| 478 ScheduleCallbackAndDeleteSelf(); |
| 479 } |
| 480 |
| 481 Profile* DownloadTargetDeterminer::GetProfile() { |
| 482 DCHECK(download_->GetBrowserContext()); |
| 483 return Profile::FromBrowserContext(download_->GetBrowserContext()); |
| 484 } |
| 485 |
| 486 bool DownloadTargetDeterminer::ShouldPromptForDownload( |
| 487 const base::FilePath& filename) { |
| 488 // If the download path is forced, don't prompt. |
| 489 if (!download_->GetForcedFilePath().empty()) { |
| 490 // 'Save As' downloads shouldn't have a forced path. |
| 491 DCHECK_NE(DownloadItem::TARGET_DISPOSITION_PROMPT, |
| 492 download_->GetTargetDisposition()); |
| 493 return false; |
| 494 } |
| 495 |
| 496 // Don't ask where to save if the download path is managed. Even if the user |
| 497 // wanted to be prompted for "all" downloads, or if this was a 'Save As' |
| 498 // download. |
| 499 if (download_prefs_->IsDownloadPathManaged()) |
| 500 return false; |
| 501 |
| 502 // Prompt if this is a 'Save As' download. |
| 503 if (download_->GetTargetDisposition() == |
| 504 DownloadItem::TARGET_DISPOSITION_PROMPT) |
| 505 return true; |
| 506 |
| 507 // Check if the user has the "Always prompt for download location" preference |
| 508 // set. If so we prompt for most downloads except for the following scenarios: |
| 509 // 1) Extension installation. Note that we only care here about the case where |
| 510 // an extension is installed, not when one is downloaded with "save as...". |
| 511 // 2) Filetypes marked "always open." If the user just wants this file opened, |
| 512 // don't bother asking where to keep it. |
| 513 if (download_prefs_->PromptForDownload() && |
| 514 !download_crx_util::IsExtensionDownload(*download_) && |
| 515 !extensions::Extension::IsExtension(filename) && |
| 516 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename)) |
| 517 return true; |
| 518 |
| 519 // Otherwise, don't prompt. Note that the user might still be prompted if |
| 520 // there are unresolved conflicts during path reservation (e.g. due to the |
| 521 // target path being unwriteable or because there are too many conflicting |
| 522 // files), or if an extension signals that the user be prompted on a filename |
| 523 // conflict. |
| 524 return false; |
| 525 } |
| 526 |
| 527 bool DownloadTargetDeterminer::IsDangerousFile(PriorVisitsToReferrer visits) { |
| 528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 529 const bool is_extension_download = |
| 530 download_crx_util::IsExtensionDownload(*download_); |
| 531 |
| 532 // User-initiated extension downloads from pref-whitelisted sources are not |
| 533 // considered dangerous. |
| 534 if (download_->HasUserGesture() && |
| 535 is_extension_download && |
| 536 download_crx_util::OffStoreInstallAllowedByPrefs( |
| 537 GetProfile(), *download_)) { |
| 538 return false; |
| 539 } |
| 540 |
| 541 // Extensions that are not from the gallery are considered dangerous. |
| 542 // When off-store install is disabled we skip this, since in this case, we |
| 543 // will not offer to install the extension. |
| 544 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() && |
| 545 is_extension_download && |
| 546 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) { |
| 547 return true; |
| 548 } |
| 549 |
| 550 // Anything the user has marked auto-open is OK if it's user-initiated. |
| 551 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) && |
| 552 download_->HasUserGesture()) |
| 553 return false; |
| 554 |
| 555 switch (download_util::GetFileDangerLevel(virtual_path_.BaseName())) { |
| 556 case download_util::NotDangerous: |
| 557 return false; |
| 558 |
| 559 case download_util::AllowOnUserGesture: |
| 560 // "Allow on user gesture" is OK when we have a user gesture and the |
| 561 // hosting page has been visited before today. |
| 562 if (download_->GetTransitionType() & |
| 563 content::PAGE_TRANSITION_FROM_ADDRESS_BAR) { |
| 564 return false; |
| 565 } |
| 566 return !download_->HasUserGesture() || visits == NO_VISITS_TO_REFERRER; |
| 567 |
| 568 case download_util::Dangerous: |
| 569 return true; |
| 570 } |
| 571 NOTREACHED(); |
| 572 return false; |
| 573 } |
| 574 |
| 575 void DownloadTargetDeterminer::OnDownloadDestroyed( |
| 576 DownloadItem* download) { |
| 577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 578 DCHECK_EQ(download_, download); |
| 579 CancelOnFailureAndDeleteSelf(); |
| 580 } |
| 581 |
| 582 // static |
| 583 void DownloadTargetDeterminer::Start( |
| 584 content::DownloadItem* download, |
| 585 DownloadPrefs* download_prefs, |
| 586 const base::FilePath& last_selected_directory, |
| 587 DownloadTargetDeterminerDelegate* delegate, |
| 588 const content::DownloadTargetCallback& callback) { |
| 589 // DownloadTargetDeterminer owns itself and will self destruct when the job is |
| 590 // complete or the download item is destroyed. The callback is always invoked |
| 591 // asynchronously. |
| 592 new DownloadTargetDeterminer(download, download_prefs, |
| 593 last_selected_directory, delegate, callback); |
| 594 } |
| OLD | NEW |