diff options
author | asanka@chromium.org <asanka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-01 00:03:38 +0000 |
---|---|---|
committer | asanka@chromium.org <asanka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-01 00:03:38 +0000 |
commit | 856ace011b166e0f6dc48005d28b46a3bbbcee7c (patch) | |
tree | 4c5aaf8cb3a1ca88a271d493d5780ad4fd1c9bfb /chrome/browser/download/chrome_download_manager_delegate.cc | |
parent | 7081c687ff936384999d7f1fa29aac148ba0124f (diff) | |
download | chromium_src-856ace011b166e0f6dc48005d28b46a3bbbcee7c.zip chromium_src-856ace011b166e0f6dc48005d28b46a3bbbcee7c.tar.gz chromium_src-856ace011b166e0f6dc48005d28b46a3bbbcee7c.tar.bz2 |
Move download filename determination into a separate class.
* Extracts download filename determination into
DownloadTargetDeterminer. The new class maintains state and observes
the download. Doing so eliminates the need to pass state around as
bound arguments.
* Guarantees that the completion callback to
DownloadManagerDelegate::DetermineDownloadTarget is always invoked,
even if the download is interrupted on initialization. This is
required for reliably resuming downloads.
* The DownloadFilePicker always returns the virtual path for downloads
to Drive. ChromeDownloadManagerDelegate can use it to keep track of
the correct last selected directory for 'Save As' downloads.
* Since no path subsubstituion is necessary during prompting,
DownloadFilePickerChromeOS is no longer necessary.
* Re-orders the sequence of events so that the user is prompted as early
as possible. Expensive history database lookups won't introduce
unnecssary jank.
* History database lookups are only performed if the results of the
lookup are necessary.
* Downloads to Drive don't need the temporary local path to be
determined twice when the default downloads directory is Drive.
BUG=151618
BUG=104335
Review URL: https://chromiumcodereview.appspot.com/12850002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197518 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/download/chrome_download_manager_delegate.cc')
-rw-r--r-- | chrome/browser/download/chrome_download_manager_delegate.cc | 609 |
1 files changed, 132 insertions, 477 deletions
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc index f7342c8..1e314dc 100644 --- a/chrome/browser/download/chrome_download_manager_delegate.cc +++ b/chrome/browser/download/chrome_download_manager_delegate.cc @@ -19,45 +19,31 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_completion_blocker.h" #include "chrome/browser/download/download_crx_util.h" -#include "chrome/browser/download/download_extensions.h" #include "chrome/browser/download/download_file_picker.h" #include "chrome/browser/download/download_history.h" #include "chrome/browser/download/download_path_reservation_tracker.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/download_service.h" #include "chrome/browser/download/download_service_factory.h" -#include "chrome/browser/download/download_status_updater.h" +#include "chrome/browser/download/download_target_determiner.h" #include "chrome/browser/download/download_util.h" #include "chrome/browser/download/save_package_file_picker.h" #include "chrome/browser/extensions/api/downloads/downloads_api.h" #include "chrome/browser/extensions/crx_installer.h" -#include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/extensions/extension_system.h" -#include "chrome/browser/history/history_service.h" -#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" -#include "chrome/browser/ui/host_desktop.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_notification_types.h" -#include "chrome/common/extensions/feature_switch.h" -#include "chrome/common/extensions/user_script.h" +#include "chrome/common/extensions/extension.h" #include "chrome/common/pref_names.h" #include "components/user_prefs/pref_registry_syncable.h" #include "content/public/browser/download_item.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_source.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_delegate.h" -#include "grit/generated_resources.h" -#include "net/base/net_util.h" -#include "ui/base/l10n/l10n_util.h" #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/drive/download_handler.h" #include "chrome/browser/chromeos/drive/file_system_util.h" -#include "chrome/browser/download/download_file_picker_chromeos.h" #include "chrome/browser/download/save_package_file_picker_chromeos.h" #endif @@ -66,7 +52,6 @@ using content::BrowserThread; using content::DownloadId; using content::DownloadItem; using content::DownloadManager; -using content::WebContents; using safe_browsing::DownloadProtectionService; namespace { @@ -103,68 +88,6 @@ class SafeBrowsingState : public DownloadCompletionBlocker { SafeBrowsingState::~SafeBrowsingState() {} -// Generate a filename based on the response from the server. Similar -// in operation to net::GenerateFileName(), but uses a localized -// default name. -void GenerateFileNameFromRequest(const DownloadItem& download_item, - base::FilePath* generated_name, - std::string referrer_charset) { - std::string default_file_name( - l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME)); - - *generated_name = net::GenerateFileName(download_item.GetURL(), - download_item.GetContentDisposition(), - referrer_charset, - download_item.GetSuggestedFilename(), - download_item.GetMimeType(), - default_file_name); -} - -typedef base::Callback<void(bool)> VisitedBeforeCallback; - -// Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a -// single bool so that VisitedBeforeCallback can curry up to 5 other parameters -// without a struct. -void VisitCountsToVisitedBefore( - const VisitedBeforeCallback& callback, - HistoryService::Handle unused_handle, - bool found_visits, - int count, - base::Time first_visit) { - callback.Run(found_visits && count && - (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); -} - -base::FilePath GetIntermediatePath(const base::FilePath& target_path, - content::DownloadDangerType danger_type, - bool is_forced_path) { - // If the download is not dangerous, just append .crdownload to the target - // path. - if (danger_type == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) { - if (is_forced_path) - return target_path; - return download_util::GetCrDownloadPath(target_path); - } - - // If the download is potentially dangerous we create a filename of the form - // 'Unconfirmed <random>.crdownload'. - base::FilePath::StringType file_name; - base::FilePath dir = target_path.DirName(); -#if defined(OS_WIN) - string16 unconfirmed_prefix = - l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); -#else - std::string unconfirmed_prefix = - l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX); -#endif - base::SStringPrintf( - &file_name, - unconfirmed_prefix.append( - FILE_PATH_LITERAL(" %d.crdownload")).c_str(), - base::RandInt(0, 1000000)); - return dir.Append(file_name); -} - // Returns a file path in the form that is expected by // platform_util::OpenItem/ShowItemInFolder, including any transformation // required for download abstractions layered on top of the core system, @@ -181,6 +104,37 @@ base::FilePath GetPlatformDownloadPath(Profile* profile, return download->GetFullPath(); } +// Callback invoked by DownloadProtectionService::CheckClientDownload. +// |is_content_check_supported| is true if the SB service supports scanning the +// download for malicious content. +// |callback| is invoked with a danger type determined as follows: +// +// Danger type is (in order of preference): +// * DANGEROUS_URL, if the URL is a known malware site. +// * MAYBE_DANGEROUS_CONTENT, if the content will be scanned for +// malware. I.e. |is_content_check_supported| is true. +// * NOT_DANGEROUS. +void CheckDownloadUrlDone( + const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback& callback, + bool is_content_check_supported, + DownloadProtectionService::DownloadCheckResult result) { + content::DownloadDangerType danger_type; + if (result == DownloadProtectionService::SAFE) { + // If this type of files is handled by the enhanced SafeBrowsing download + // protection, mark it as potentially dangerous content until we are done + // with scanning it. + if (is_content_check_supported) + danger_type = content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; + else + danger_type = content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS; + } else { + // If the URL is malicious, we'll use that as the danger type. The results + // of the content check, if one is performed, will be ignored. + danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL; + } + callback.Run(danger_type); +} + } // namespace // static @@ -221,52 +175,25 @@ DownloadId ChromeDownloadManagerDelegate::GetNextId() { bool ChromeDownloadManagerDelegate::DetermineDownloadTarget( DownloadItem* download, const content::DownloadTargetCallback& callback) { -#if defined(FULL_SAFE_BROWSING) - DownloadProtectionService* service = GetDownloadProtectionService(); - if (service) { - VLOG(2) << __FUNCTION__ << "() Start SB URL check for download = " - << download->DebugString(false); - service->CheckDownloadUrl( - *download, - base::Bind( - &ChromeDownloadManagerDelegate::CheckDownloadUrlDone, - this, - download->GetId(), - callback)); - return true; - } -#endif - CheckDownloadUrlDone(download->GetId(), callback, - DownloadProtectionService::SAFE); + DownloadTargetDeterminer::Start(download, + download_prefs_.get(), + last_download_path_, + this, + callback); return true; } -void ChromeDownloadManagerDelegate::ChooseDownloadPath( - DownloadItem* item, - const base::FilePath& suggested_path, - const FileSelectedCallback& file_selected_callback) { - // Deletes itself. - DownloadFilePicker* file_picker = -#if defined(OS_CHROMEOS) - new DownloadFilePickerChromeOS(); -#else - new DownloadFilePicker(); -#endif - file_picker->Init(download_manager_, item, suggested_path, - file_selected_callback); -} - bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension( const base::FilePath& path) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - base::FilePath::StringType extension = path.Extension(); - if (extension.empty()) + if (path.Extension().empty()) return false; + // TODO(asanka): This determination is done based on |path|, while + // ShouldOpenDownload() detects extension downloads based on the + // characteristics of the download. Reconcile this. http://crbug.com/167702 if (extensions::Extension::IsExtension(path)) return false; - DCHECK(extension[0] == base::FilePath::kExtensionSeparator); - extension.erase(0, 1); - return download_prefs_->IsAutoOpenEnabledForExtension(extension); + return download_prefs_->IsAutoOpenEnabledBasedOnExtension(path); } // static @@ -401,7 +328,7 @@ void ChromeDownloadManagerDelegate::GetSaveDir( } void ChromeDownloadManagerDelegate::ChooseSavePath( - WebContents* web_contents, + content::WebContents* web_contents, const base::FilePath& suggested_path, const base::FilePath::StringType& default_extension, bool can_save_as_complete, @@ -457,6 +384,7 @@ void ChromeDownloadManagerDelegate::ClearLastDownloadPath() { DownloadProtectionService* ChromeDownloadManagerDelegate::GetDownloadProtectionService() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); #if defined(FULL_SAFE_BROWSING) SafeBrowsingService* sb_service = g_browser_process->safe_browsing_service(); if (sb_service && sb_service->download_protection_service() && @@ -467,93 +395,108 @@ DownloadProtectionService* return NULL; } -// TODO(phajdan.jr): This is apparently not being exercised in tests. -bool ChromeDownloadManagerDelegate::IsDangerousFile( - const DownloadItem& download, - const base::FilePath& suggested_path, - bool visited_referrer_before) { +void ChromeDownloadManagerDelegate::NotifyExtensions( + DownloadItem* download, + const base::FilePath& virtual_path, + const NotifyExtensionsCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const bool is_extension_download = - download_crx_util::IsExtensionDownload(download); - - // User-initiated extension downloads from pref-whitelisted sources are not - // considered dangerous. - if (download.HasUserGesture() && - is_extension_download && - download_crx_util::OffStoreInstallAllowedByPrefs(profile_, download)) { - return false; - } - - // Extensions that are not from the gallery are considered dangerous. - // When off-store install is disabled we skip this, since in this case, we - // will not offer to install the extension. - if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() && - is_extension_download && - !extensions::WebstoreInstaller::GetAssociatedApproval(download)) { - return true; +#if !defined(OS_ANDROID) + ExtensionDownloadsEventRouter* router = + DownloadServiceFactory::GetForProfile(profile_)-> + GetExtensionEventRouter(); + if (router) { + base::Closure original_path_callback = + base::Bind(callback, base::FilePath(), + DownloadPathReservationTracker::UNIQUIFY); + router->OnDeterminingFilename(download, virtual_path.BaseName(), + original_path_callback, + callback); + return; } +#endif + callback.Run(base::FilePath(), DownloadPathReservationTracker::UNIQUIFY); +} - // Anything the user has marked auto-open is OK if it's user-initiated. - if (ShouldOpenFileBasedOnExtension(suggested_path) && - download.HasUserGesture()) - return false; - - // "Allow on user gesture" is OK when we have a user gesture and the hosting - // page has been visited before today. - download_util::DownloadDangerLevel danger_level = - download_util::GetFileDangerLevel(suggested_path.BaseName()); - if (danger_level == download_util::AllowOnUserGesture) { - if (download.GetTransitionType() & - content::PAGE_TRANSITION_FROM_ADDRESS_BAR) { - return false; - } - return !download.HasUserGesture() || !visited_referrer_before; +void ChromeDownloadManagerDelegate::ReserveVirtualPath( + content::DownloadItem* download, + const base::FilePath& virtual_path, + DownloadPathReservationTracker::FilenameConflictAction conflict_action, + const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!virtual_path.empty()); +#if defined(OS_CHROMEOS) + // TODO(asanka): Handle path reservations for virtual paths as well. + // http://crbug.com/151618 + if (drive::util::IsUnderDriveMountPoint(virtual_path)) { + callback.Run(virtual_path, true); + return; } +#endif + DownloadPathReservationTracker::GetReservedPath( + *download, virtual_path, download_prefs_->DownloadPath(), + conflict_action, callback); +} - return danger_level == download_util::Dangerous; +void ChromeDownloadManagerDelegate::PromptUserForDownloadPath( + DownloadItem* download, + const base::FilePath& suggested_path, + const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DownloadFilePicker::ShowFilePicker( + download, + suggested_path, + base::Bind(&ChromeDownloadManagerDelegate::OnDownloadPathSelected, + this, + callback)); } -void ChromeDownloadManagerDelegate::GetReservedPath( - DownloadItem& download, - const base::FilePath& target_path, - const base::FilePath& default_download_path, - DownloadPathReservationTracker::FilenameConflictAction conflict_action, - const DownloadPathReservationTracker::ReservedPathCallback& callback) { - DownloadPathReservationTracker::GetReservedPath( - download, target_path, default_download_path, conflict_action, callback); +void ChromeDownloadManagerDelegate::OnDownloadPathSelected( + const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback, + const base::FilePath& virtual_path) { + if (!virtual_path.empty()) + last_download_path_ = virtual_path.DirName(); + callback.Run(virtual_path); } -void ChromeDownloadManagerDelegate::CheckDownloadUrlDone( - int32 download_id, - const content::DownloadTargetCallback& callback, - DownloadProtectionService::DownloadCheckResult result) { +void ChromeDownloadManagerDelegate::DetermineLocalPath( + DownloadItem* download, + const base::FilePath& virtual_path, + const DownloadTargetDeterminerDelegate::LocalPathCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DownloadItem* download = download_manager_->GetDownload(download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) +#if defined(OS_CHROMEOS) + drive::DownloadHandler* drive_download_handler = + drive::DownloadHandler::GetForProfile(profile_); + if (drive_download_handler) { + drive_download_handler->SubstituteDriveDownloadPath( + virtual_path, download, callback); return; + } +#endif + callback.Run(virtual_path); +} - VLOG(2) << __FUNCTION__ << "() download = " << download->DebugString(false) - << " verdict = " << result; - content::DownloadDangerType danger_type = download->GetDangerType(); - if (result != DownloadProtectionService::SAFE) - danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL; +void ChromeDownloadManagerDelegate::CheckDownloadUrl( + DownloadItem* download, + const base::FilePath& suggested_path, + const CheckDownloadUrlCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // HistoryServiceFactory redirects incognito profiles to on-record profiles. - HistoryService* history = HistoryServiceFactory::GetForProfile( - profile_, Profile::EXPLICIT_ACCESS); - if (!history || !download->GetReferrerUrl().is_valid()) { - // If the original profile doesn't have a HistoryService or the referrer url - // is invalid, then give up and assume the referrer has not been visited - // before. There's no history for on-record profiles in unit_tests, for - // example. - CheckVisitedReferrerBeforeDone(download_id, callback, danger_type, false); +#if defined(FULL_SAFE_BROWSING) + safe_browsing::DownloadProtectionService* service = + GetDownloadProtectionService(); + if (service) { + bool is_content_check_supported = + service->IsSupportedDownload(*download, suggested_path); + VLOG(2) << __FUNCTION__ << "() Start SB URL check for download = " + << download->DebugString(false); + service->CheckDownloadUrl(*download, + base::Bind(&CheckDownloadUrlDone, + callback, + is_content_check_supported)); return; } - history->GetVisibleVisitCountToHost( - download->GetReferrerUrl(), &history_consumer_, - base::Bind(&VisitCountsToVisitedBefore, base::Bind( - &ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone, - this, download_id, callback, danger_type))); +#endif + callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS); } void ChromeDownloadManagerDelegate::CheckClientDownloadDone( @@ -611,291 +554,3 @@ void ChromeDownloadManagerDelegate::Observe( crx_installers_.erase(installer.get()); callback.Run(installer->did_handle_successfully()); } - -struct ChromeDownloadManagerDelegate::ContinueFilenameDeterminationInfo { - ContinueFilenameDeterminationInfo(); - ~ContinueFilenameDeterminationInfo(); - - int32 download_id; - content::DownloadTargetCallback callback; - content::DownloadDangerType danger_type; - bool visited_referrer_before; - bool should_prompt; -}; - -ChromeDownloadManagerDelegate::ContinueFilenameDeterminationInfo:: - ContinueFilenameDeterminationInfo() {} -ChromeDownloadManagerDelegate::ContinueFilenameDeterminationInfo:: - ~ContinueFilenameDeterminationInfo() {} - -void ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone( - int32 download_id, - const content::DownloadTargetCallback& callback, - content::DownloadDangerType danger_type, - bool visited_referrer_before) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - DownloadItem* download = - download_manager_->GetDownload(download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) - return; - - bool should_prompt = (download->GetTargetDisposition() == - DownloadItem::TARGET_DISPOSITION_PROMPT); - bool is_forced_path = !download->GetForcedFilePath().empty(); - base::FilePath generated_name; - base::FilePath suggested_path; - - // Check whether this download is for an extension install or not. - // Allow extensions to be explicitly saved. - if (!is_forced_path) { - GenerateFileNameFromRequest( - *download, - &generated_name, - profile_->GetPrefs()->GetString(prefs::kDefaultCharset)); - - // Freeze the user's preference for showing a Save As dialog. We're going - // to bounce around a bunch of threads and we don't want to worry about race - // conditions where the user changes this pref out from under us. - if (download_prefs_->PromptForDownload()) { - // But ignore the user's preference for the following scenarios: - // 1) Extension installation. Note that we only care here about the case - // where an extension is installed, not when one is downloaded with - // "save as...". - // 2) Filetypes marked "always open." If the user just wants this file - // opened, don't bother asking where to keep it. - if (!download_crx_util::IsExtensionDownload(*download) && - !ShouldOpenFileBasedOnExtension(generated_name)) - should_prompt = true; - } - if (download_prefs_->IsDownloadPathManaged()) - should_prompt = false; - - // Determine the proper path for a download, by either one of the following: - // 1) using the default download directory. - // 2) prompting the user. - base::FilePath target_directory; - if (should_prompt && !last_download_path_.empty()) - target_directory = last_download_path_; - else - target_directory = download_prefs_->DownloadPath(); - suggested_path = target_directory.Append(generated_name); - } else { - DCHECK(!should_prompt); - suggested_path = download->GetForcedFilePath(); - } - - ContinueFilenameDeterminationInfo continue_info; - continue_info.download_id = download_id; - continue_info.callback = callback; - continue_info.danger_type = danger_type; - continue_info.visited_referrer_before = visited_referrer_before; - continue_info.should_prompt = should_prompt; - - DownloadPathReservationTracker::FilenameConflictAction conflict_action = ( - is_forced_path ? - DownloadPathReservationTracker::OVERWRITE : - DownloadPathReservationTracker::UNIQUIFY); - base::Closure filename_determined = base::Bind( - &ChromeDownloadManagerDelegate::ContinueDeterminingFilename, - this, continue_info, suggested_path, conflict_action); -#if defined(OS_ANDROID) - filename_determined.Run(); -#else - if (is_forced_path || - !DownloadServiceFactory::GetForProfile(profile_) - ->GetExtensionEventRouter()) { - filename_determined.Run(); - } else { - DownloadService* service = DownloadServiceFactory::GetForProfile(profile_); - ExtensionDownloadsEventRouter* router = service->GetExtensionEventRouter(); - ExtensionDownloadsEventRouter::FilenameChangedCallback overriding = - base::Bind(&ChromeDownloadManagerDelegate::OnExtensionOverridingFilename, - this, continue_info); - router->OnDeterminingFilename( - download, generated_name, filename_determined, overriding); - } -#endif -} - -void ChromeDownloadManagerDelegate::OnExtensionOverridingFilename( - const ContinueFilenameDeterminationInfo& continue_info, - const base::FilePath& changed_filename, - DownloadPathReservationTracker::FilenameConflictAction conflict_action) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DownloadItem* download = - download_manager_->GetDownload(continue_info.download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) - return; - - // If an extension overrides the filename, then the target directory will be - // forced to download_prefs_->DownloadPath() since extensions cannot place - // downloaded files anywhere except there. This prevents subdirectories from - // accumulating: if an extension is allowed to say that a file should go in - // last_download_path/music/foo.mp3, then last_download_path will accumulate - // the subdirectory /music/ so that the next download may end up in - // Downloads/music/music/music/bar.mp3. - base::FilePath temp_filename(download_prefs_->DownloadPath().Append( - changed_filename).NormalizePathSeparators()); - // Do not pass a mime type to GenerateSafeFileName so that it does not force - // the filename to have an extension if the (chrome) extension does not - // suggest it. - net::GenerateSafeFileName(std::string(), false, &temp_filename); - - ContinueDeterminingFilename(continue_info, temp_filename, conflict_action); -} - -void ChromeDownloadManagerDelegate::ContinueDeterminingFilename( - const ContinueFilenameDeterminationInfo& continue_info, - const base::FilePath& suggested_path, - DownloadPathReservationTracker::FilenameConflictAction conflict_action) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - int32 download_id = continue_info.download_id; - const content::DownloadTargetCallback& callback = continue_info.callback; - content::DownloadDangerType danger_type = continue_info.danger_type; - bool visited_referrer_before = continue_info.visited_referrer_before; - bool should_prompt = continue_info.should_prompt; - DownloadItem* download = - download_manager_->GetDownload(download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) - return; - - // If the download hasn't already been marked dangerous (could be - // DANGEROUS_URL), check if it is a dangerous file. - if (danger_type == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) { - if (!should_prompt && - download->GetForcedFilePath().empty() && - IsDangerousFile(*download, suggested_path, visited_referrer_before)) { - danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; - } - -#if defined(FULL_SAFE_BROWSING) - DownloadProtectionService* service = GetDownloadProtectionService(); - // If this type of files is handled by the enhanced SafeBrowsing download - // protection, mark it as potentially dangerous content until we are done - // with scanning it. - if (service && service->enabled()) { - // TODO(noelutz): if the user changes the extension name in the UI to - // something like .exe SafeBrowsing will currently *not* check if the - // download is malicious. - if (service->IsSupportedDownload(*download, suggested_path)) - danger_type = content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; - } -#endif - } else { - // Currently we only expect this case. - DCHECK_EQ(content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, danger_type); - } - -#if defined (OS_CHROMEOS) - drive::DownloadHandler* drive_download_handler = - drive::DownloadHandler::GetForProfile(profile_); - if (drive_download_handler) { - drive_download_handler->SubstituteDriveDownloadPath( - suggested_path, download, - base::Bind( - &ChromeDownloadManagerDelegate::SubstituteDriveDownloadPathCallback, - this, download->GetId(), callback, should_prompt, conflict_action, - danger_type)); - return; - } -#endif - GetReservedPath( - *download, suggested_path, download_prefs_->DownloadPath(), - conflict_action, - base::Bind(&ChromeDownloadManagerDelegate::OnPathReservationAvailable, - this, download->GetId(), callback, should_prompt, - danger_type)); -} - -#if defined (OS_CHROMEOS) -// TODO(asanka): Merge this logic with the logic in DownloadFilePickerChromeOS. -void ChromeDownloadManagerDelegate::SubstituteDriveDownloadPathCallback( - int32 download_id, - const content::DownloadTargetCallback& callback, - bool should_prompt, - DownloadPathReservationTracker::FilenameConflictAction conflict_action, - content::DownloadDangerType danger_type, - const base::FilePath& suggested_path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DownloadItem* download = - download_manager_->GetDownload(download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) - return; - - if (suggested_path.empty()) { - // Substitution failed. - callback.Run(base::FilePath(), - DownloadItem::TARGET_DISPOSITION_OVERWRITE, - danger_type, - base::FilePath()); - return; - } - - GetReservedPath( - *download, suggested_path, download_prefs_->DownloadPath(), - conflict_action, - base::Bind(&ChromeDownloadManagerDelegate::OnPathReservationAvailable, - this, download->GetId(), callback, should_prompt, - danger_type)); -} -#endif - -void ChromeDownloadManagerDelegate::OnPathReservationAvailable( - int32 download_id, - const content::DownloadTargetCallback& callback, - bool should_prompt, - content::DownloadDangerType danger_type, - const base::FilePath& reserved_path, - bool reserved_path_verified) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DownloadItem* download = - download_manager_->GetDownload(download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) - return; - if (should_prompt || !reserved_path_verified) { - // If the target path could not be verified then the path was non-existant, - // non writeable or could not be uniquified. Prompt the user. - ChooseDownloadPath( - download, reserved_path, - base::Bind(&ChromeDownloadManagerDelegate::OnTargetPathDetermined, - this, download_id, callback, - DownloadItem::TARGET_DISPOSITION_PROMPT, danger_type)); - } else { - OnTargetPathDetermined(download_id, callback, - DownloadItem::TARGET_DISPOSITION_OVERWRITE, - danger_type, reserved_path); - } -} - -void ChromeDownloadManagerDelegate::OnTargetPathDetermined( - int32 download_id, - const content::DownloadTargetCallback& callback, - DownloadItem::TargetDisposition disposition, - content::DownloadDangerType danger_type, - const base::FilePath& target_path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - base::FilePath intermediate_path; - DownloadItem* download = - download_manager_->GetDownload(download_id); - if (!download || (download->GetState() != DownloadItem::IN_PROGRESS)) - return; - - // If |target_path| is empty, then that means that the user wants to cancel - // the download. - if (!target_path.empty()) { - intermediate_path = GetIntermediatePath( - target_path, danger_type, !download->GetForcedFilePath().empty()); - - // Retain the last directory. Exclude temporary downloads since the path - // likely points at the location of a temporary file. - // TODO(asanka): This logic is a hack. DownloadFilePicker should give us a - // directory to persist. Or perhaps, if the Drive path - // substitution logic is moved here, then we would have a - // persistable path after the DownloadFilePicker is done. - if (disposition == DownloadItem::TARGET_DISPOSITION_PROMPT && - !download->IsTemporary()) - last_download_path_ = target_path.DirName(); - } - callback.Run(target_path, disposition, danger_type, intermediate_path); -} |