summaryrefslogtreecommitdiffstats
path: root/chrome/browser/download/chrome_download_manager_delegate.cc
diff options
context:
space:
mode:
authorasanka@chromium.org <asanka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-01 00:03:38 +0000
committerasanka@chromium.org <asanka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-01 00:03:38 +0000
commit856ace011b166e0f6dc48005d28b46a3bbbcee7c (patch)
tree4c5aaf8cb3a1ca88a271d493d5780ad4fd1c9bfb /chrome/browser/download/chrome_download_manager_delegate.cc
parent7081c687ff936384999d7f1fa29aac148ba0124f (diff)
downloadchromium_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.cc609
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);
-}