Chromium Code Reviews| Index: chrome/browser/download/download_target_determiner.cc |
| diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc |
| index caf1083c83c2e3415d404b55ec3a3fb7f0ebd39d..1a1fc48a9e55286905066201f209abb2b968c7d3 100644 |
| --- a/chrome/browser/download/download_target_determiner.cc |
| +++ b/chrome/browser/download/download_target_determiner.cc |
| @@ -22,6 +22,7 @@ |
| #include "chrome/common/pref_names.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/download_interrupt_reasons.h" |
| #include "grit/generated_resources.h" |
| #include "net/base/net_util.h" |
| #include "ui/base/l10n/l10n_util.h" |
| @@ -58,18 +59,22 @@ DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() { |
| DownloadTargetDeterminer::DownloadTargetDeterminer( |
| DownloadItem* download, |
| + const base::FilePath& initial_virtual_path, |
| DownloadPrefs* download_prefs, |
| const base::FilePath& last_selected_directory, |
| DownloadTargetDeterminerDelegate* delegate, |
| const content::DownloadTargetCallback& callback) |
| : next_state_(STATE_GENERATE_TARGET_PATH), |
| should_prompt_(false), |
| + should_notify_extensions_(false), |
| create_directory_(false), |
| - conflict_action_(download->GetForcedFilePath().empty() ? |
| - DownloadPathReservationTracker::UNIQUIFY : |
| - DownloadPathReservationTracker::OVERWRITE), |
| + conflict_action_(DownloadPathReservationTracker::OVERWRITE), |
| danger_type_(download->GetDangerType()), |
| + virtual_path_(initial_virtual_path), |
| download_(download), |
| + is_resumption_(download_->GetLastReason() != |
| + content::DOWNLOAD_INTERRUPT_REASON_NONE && |
| + !initial_virtual_path.empty()), |
| download_prefs_(download_prefs), |
| delegate_(delegate), |
| last_selected_directory_(last_selected_directory), |
| @@ -137,18 +142,29 @@ void DownloadTargetDeterminer::DoLoop() { |
| DownloadTargetDeterminer::Result |
| DownloadTargetDeterminer::DoGenerateTargetPath() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - DCHECK(virtual_path_.empty()); |
| DCHECK(local_path_.empty()); |
| + DCHECK(!should_prompt_); |
| + DCHECK(!should_notify_extensions_); |
|
Randy Smith (Not in Mondays)
2013/05/24 01:53:55
Why is this a member variable rather than a local
asanka
2013/05/29 22:30:11
It's set here, but is read in DoNotifyExtensions()
|
| + DCHECK_EQ(DownloadPathReservationTracker::OVERWRITE, conflict_action_); |
| bool is_forced_path = !download_->GetForcedFilePath().empty(); |
| next_state_ = STATE_NOTIFY_EXTENSIONS; |
| - // If we don't have a forced path, we should construct a path for the |
| - // download. Forced paths are only specified for programmatic downloads |
| - // (WebStore, Drag&Drop). Treat the path as a virtual path. We will eventually |
| - // determine whether this is a local path and if not, figure out a local path. |
| - if (!is_forced_path) { |
| - std::string default_filename( |
| + if (!virtual_path_.empty() && HasPromptedForPath() && !is_forced_path) { |
| + // The download is being resumed and the user has already been prompted for |
| + // a path. Assume that it's okay to overwrite the file if there's a |
| + // conflict and reuse the selection. |
| + // Note: |virtual_path_| may already be uniquified. In this case setting |
| + // conflict_action_ to UNIQUIFY may cause additional levels of uniquifiers |
| + // (e.g. "foo (1) (1).txt"). |
|
Randy Smith (Not in Mondays)
2013/05/24 01:53:55
Why is this comment still relevant? If we prompte
asanka
2013/05/29 22:30:11
Yes. The comment was explaining why we aren't sett
|
| + should_prompt_ = ShouldPromptForDownload(virtual_path_); |
| + } else if (!is_forced_path) { |
| + // If we don't have a forced path, we should construct a path for the |
| + // download. Forced paths are only specified for programmatic downloads |
| + // (WebStore, Drag&Drop). Treat the path as a virtual path. We will |
| + // eventually determine whether this is a local path and if not, figure out |
| + // a local path. |
| + std::string default_filename( |
| l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); |
| base::FilePath generated_filename = net::GenerateFileName( |
| download_->GetURL(), |
| @@ -168,9 +184,15 @@ DownloadTargetDeterminer::Result |
| target_directory = download_prefs_->DownloadPath(); |
| } |
| virtual_path_ = target_directory.Append(generated_filename); |
| + conflict_action_ = DownloadPathReservationTracker::UNIQUIFY; |
| + should_notify_extensions_ = true; |
| } else { |
| DCHECK(!should_prompt_); |
|
Randy Smith (Not in Mondays)
2013/05/24 01:53:55
nit: Feels a little redundant with identical DCHEC
asanka
2013/05/29 22:30:11
Done.
|
| virtual_path_ = download_->GetForcedFilePath(); |
| + // If this is a resumed download which was previously interrupted due to an |
| + // issue with the forced path, the user is still not prompted. If the path |
| + // supplied to a programmatic download is invalid, then the caller needs to |
| + // intervene. |
| } |
| DCHECK(virtual_path_.IsAbsolute()); |
| DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe(); |
| @@ -194,9 +216,7 @@ DownloadTargetDeterminer::Result |
| next_state_ = STATE_RESERVE_VIRTUAL_PATH; |
| - // If the target path is forced or if we don't have an extensions event |
| - // router, then proceed with the original path. |
| - if (!download_->GetForcedFilePath().empty()) |
| + if (!should_notify_extensions_) |
| return CONTINUE; |
| delegate_->NotifyExtensions(download_, virtual_path_, |
| @@ -347,11 +367,8 @@ DownloadTargetDeterminer::Result |
| // danger level of the download depends on the file type. This excludes cases |
| // where the download has already been deemed dangerous, or where the user is |
| // going to be prompted or where this is a programmatic download. |
| - if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS || |
| - should_prompt_ || |
| - !download_->GetForcedFilePath().empty()) { |
|
Randy Smith (Not in Mondays)
2013/05/24 01:53:55
Sorry, confused. Why remove the other two checks?
asanka
2013/05/29 22:30:11
The checks were moved to IsDangerousFile().
|
| + if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) |
| return CONTINUE; |
| - } |
| // Assume that: |
| // IsDangerousFile(VISITED_REFERRER) => IsDangerousFile(NO_VISITS_...) |
| @@ -398,6 +415,8 @@ DownloadTargetDeterminer::Result |
| DCHECK(!virtual_path_.empty()); |
| DCHECK(!local_path_.empty()); |
| DCHECK(intermediate_path_.empty()); |
| + DCHECK(!virtual_path_.MatchesExtension(FILE_PATH_LITERAL(".crdownload"))); |
| + DCHECK(!local_path_.MatchesExtension(FILE_PATH_LITERAL(".crdownload"))); |
| next_state_ = STATE_NONE; |
| @@ -464,8 +483,9 @@ void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() { |
| FROM_HERE, |
| base::Bind(completion_callback_, |
| local_path_, |
| - (should_prompt_ ? DownloadItem::TARGET_DISPOSITION_PROMPT : |
| - DownloadItem::TARGET_DISPOSITION_OVERWRITE), |
| + (HasPromptedForPath() |
| + ? DownloadItem::TARGET_DISPOSITION_PROMPT |
| + : DownloadItem::TARGET_DISPOSITION_OVERWRITE), |
| danger_type_, |
| intermediate_path_)); |
| completion_callback_.Reset(); |
| @@ -486,12 +506,23 @@ Profile* DownloadTargetDeterminer::GetProfile() { |
| } |
| bool DownloadTargetDeterminer::ShouldPromptForDownload( |
| - const base::FilePath& filename) { |
| + const base::FilePath& filename) const { |
| + if (is_resumption_) { |
| + // If the target disposition or prefs require prompting, the user has |
| + // already been prompted. Try to respect the user's selection, unless we've |
| + // discovered that the target path cannot be used for some reason. |
| + content::DownloadInterruptReason reason = download_->GetLastReason(); |
| + return (reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED || |
| + reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE || |
| + reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE); |
| + } |
| + |
| // If the download path is forced, don't prompt. |
| if (!download_->GetForcedFilePath().empty()) { |
| // 'Save As' downloads shouldn't have a forced path. |
| - DCHECK_NE(DownloadItem::TARGET_DISPOSITION_PROMPT, |
| - download_->GetTargetDisposition()); |
| + DCHECK(is_resumption_ || |
|
Randy Smith (Not in Mondays)
2013/05/24 01:53:55
This portion of the DCHECK seems strange, since th
asanka
2013/05/29 22:30:11
Done.
|
| + (DownloadItem::TARGET_DISPOSITION_PROMPT != |
| + download_->GetTargetDisposition())); |
| return false; |
| } |
| @@ -526,8 +557,21 @@ bool DownloadTargetDeterminer::ShouldPromptForDownload( |
| return false; |
| } |
| +bool DownloadTargetDeterminer::HasPromptedForPath() const { |
| + return should_prompt_ || |
| + (is_resumption_ && download_->GetTargetDisposition() == |
| + DownloadItem::TARGET_DISPOSITION_PROMPT); |
| +} |
| + |
| bool DownloadTargetDeterminer::IsDangerousFile(PriorVisitsToReferrer visits) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // If the user has has been prompted, assume that the user has approved the |
| + // download. Programmatic downloads are considered safe unless it contains |
|
Randy Smith (Not in Mondays)
2013/05/24 01:53:55
nit: "it contains" -> "they contain" (or "A progra
asanka
2013/05/29 22:30:11
Done.
|
| + // malware. |
| + if (HasPromptedForPath() || !download_->GetForcedFilePath().empty()) |
| + return false; |
| + |
| const bool is_extension_download = |
| download_crx_util::IsExtensionDownload(*download_); |
| @@ -584,6 +628,7 @@ void DownloadTargetDeterminer::OnDownloadDestroyed( |
| // static |
| void DownloadTargetDeterminer::Start( |
| content::DownloadItem* download, |
| + const base::FilePath& initial_virtual_path, |
| DownloadPrefs* download_prefs, |
| const base::FilePath& last_selected_directory, |
| DownloadTargetDeterminerDelegate* delegate, |
| @@ -591,7 +636,7 @@ void DownloadTargetDeterminer::Start( |
| // DownloadTargetDeterminer owns itself and will self destruct when the job is |
| // complete or the download item is destroyed. The callback is always invoked |
| // asynchronously. |
| - new DownloadTargetDeterminer(download, download_prefs, |
| + new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs, |
| last_selected_directory, delegate, callback); |
| } |