| Index: chrome/browser/download/chrome_download_manager_delegate.cc
|
| diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
|
| index f7342c81dbe2d6d4159aac1575dc3de5026e482f..1e314dcb27d960a72a2efb33578899f8e8ecfe56 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);
|
| -}
|
|
|