Commit b7fa8459 authored by Min Qin's avatar Min Qin Committed by Commit Bot

Fix an DOS issue using download prompt dialog

This CL changes the behavior to show dialog one by one,
not showing all of them at once.
This CL also fixes an issue that DownloadFilePicker is not
deleted in some cases.

BUG=868619

Change-Id: I71958b8c8d1383d95996d00c58c84c5523e08bd1
Reviewed-on: https://chromium-review.googlesource.com/1157141
Commit-Queue: Min Qin <qinmin@chromium.org>
Reviewed-by: default avatarXing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579955}
parent 8bfe46fe
...@@ -300,6 +300,7 @@ ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile) ...@@ -300,6 +300,7 @@ ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile)
disk_access_task_runner_(base::CreateSequencedTaskRunnerWithTraits( disk_access_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT, {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
is_file_picker_showing_(false),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
location_dialog_bridge_.reset(new DownloadLocationDialogBridgeImpl); location_dialog_bridge_.reset(new DownloadLocationDialogBridgeImpl);
...@@ -961,10 +962,49 @@ void ChromeDownloadManagerDelegate::RequestConfirmation( ...@@ -961,10 +962,49 @@ void ChromeDownloadManagerDelegate::RequestConfirmation(
#else // !OS_ANDROID #else // !OS_ANDROID
// Desktop Chrome displays a file picker for all confirmation needs. We can do // Desktop Chrome displays a file picker for all confirmation needs. We can do
// better. // better.
DownloadFilePicker::ShowFilePicker(download, suggested_path, callback); if (is_file_picker_showing_) {
file_picker_callbacks_.emplace_back(
base::BindOnce(&ChromeDownloadManagerDelegate::ShowFilePicker,
weak_ptr_factory_.GetWeakPtr(), download->GetGuid(),
suggested_path, callback));
} else {
is_file_picker_showing_ = true;
ShowFilePicker(download->GetGuid(), suggested_path, callback);
}
#endif // !OS_ANDROID #endif // !OS_ANDROID
} }
void ChromeDownloadManagerDelegate::OnConfirmationCallbackComplete(
const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback,
DownloadConfirmationResult result,
const base::FilePath& virtual_path) {
callback.Run(result, virtual_path);
if (!file_picker_callbacks_.empty()) {
base::OnceClosure callback = std::move(file_picker_callbacks_.front());
std::move(callback).Run();
file_picker_callbacks_.pop_front();
} else {
is_file_picker_showing_ = false;
}
}
void ChromeDownloadManagerDelegate::ShowFilePicker(
const std::string& guid,
const base::FilePath& suggested_path,
const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback) {
DownloadItem* download = download_manager_->GetDownloadByGuid(guid);
if (download) {
DownloadFilePicker::ShowFilePicker(
download, suggested_path,
base::BindRepeating(
&ChromeDownloadManagerDelegate::OnConfirmationCallbackComplete,
weak_ptr_factory_.GetWeakPtr(), callback));
} else {
OnConfirmationCallbackComplete(
callback, DownloadConfirmationResult::CANCELED, base::FilePath());
}
}
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
void ChromeDownloadManagerDelegate::GenerateUniqueFileNameDone( void ChromeDownloadManagerDelegate::GenerateUniqueFileNameDone(
gfx::NativeWindow native_window, gfx::NativeWindow native_window,
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stdint.h> #include <stdint.h>
#include <deque>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -133,6 +134,12 @@ class ChromeDownloadManagerDelegate ...@@ -133,6 +134,12 @@ class ChromeDownloadManagerDelegate
virtual safe_browsing::DownloadProtectionService* virtual safe_browsing::DownloadProtectionService*
GetDownloadProtectionService(); GetDownloadProtectionService();
// Called to show a file picker
virtual void ShowFilePicker(
const std::string& guid,
const base::FilePath& suggested_path,
const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback);
// DownloadTargetDeterminerDelegate. Protected for testing. // DownloadTargetDeterminerDelegate. Protected for testing.
void NotifyExtensions(download::DownloadItem* download, void NotifyExtensions(download::DownloadItem* download,
const base::FilePath& suggested_virtual_path, const base::FilePath& suggested_virtual_path,
...@@ -162,6 +169,12 @@ class ChromeDownloadManagerDelegate ...@@ -162,6 +169,12 @@ class ChromeDownloadManagerDelegate
DownloadController::DownloadCancelReason reason); DownloadController::DownloadCancelReason reason);
#endif #endif
// Called when the file picker returns the confirmation result.
void OnConfirmationCallbackComplete(
const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback,
DownloadConfirmationResult result,
const base::FilePath& virtual_path);
// So that test classes that inherit from this for override purposes // So that test classes that inherit from this for override purposes
// can call back into the DownloadManager. // can call back into the DownloadManager.
content::DownloadManager* download_manager_; content::DownloadManager* download_manager_;
...@@ -257,6 +270,12 @@ class ChromeDownloadManagerDelegate ...@@ -257,6 +270,12 @@ class ChromeDownloadManagerDelegate
CrxInstallerMap crx_installers_; CrxInstallerMap crx_installers_;
#endif #endif
// Outstanding callbacks to open file selection dialog.
std::deque<base::OnceClosure> file_picker_callbacks_;
// Whether a file picker dialog is showing.
bool is_file_picker_showing_;
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
base::WeakPtrFactory<ChromeDownloadManagerDelegate> weak_ptr_factory_; base::WeakPtrFactory<ChromeDownloadManagerDelegate> weak_ptr_factory_;
......
...@@ -63,15 +63,23 @@ DownloadFilePicker::DownloadFilePicker(DownloadItem* item, ...@@ -63,15 +63,23 @@ DownloadFilePicker::DownloadFilePicker(DownloadItem* item,
should_record_file_picker_result_ = !prefs->PromptForDownload(); should_record_file_picker_result_ = !prefs->PromptForDownload();
WebContents* web_contents = content::DownloadItemUtils::GetWebContents(item); WebContents* web_contents = content::DownloadItemUtils::GetWebContents(item);
if (!web_contents || !web_contents->GetNativeView()) if (!web_contents || !web_contents->GetNativeView()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&DownloadFilePicker::FileSelectionCanceled,
base::Unretained(this), nullptr));
return; return;
}
select_file_dialog_ = ui::SelectFileDialog::Create( select_file_dialog_ = ui::SelectFileDialog::Create(
this, std::make_unique<ChromeSelectFilePolicy>(web_contents)); this, std::make_unique<ChromeSelectFilePolicy>(web_contents));
// |select_file_dialog_| could be null in Linux. See CreateSelectFileDialog() // |select_file_dialog_| could be null in Linux. See CreateSelectFileDialog()
// in shell_dialog_linux.cc. // in shell_dialog_linux.cc.
if (!select_file_dialog_.get()) if (!select_file_dialog_.get()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&DownloadFilePicker::FileSelectionCanceled,
base::Unretained(this), nullptr));
return; return;
}
ui::SelectFileDialog::FileTypeInfo file_type_info; ui::SelectFileDialog::FileTypeInfo file_type_info;
// Platform file pickers, notably on Mac and Windows, tend to break // Platform file pickers, notably on Mac and Windows, tend to break
......
...@@ -52,17 +52,20 @@ class DownloadTestFileActivityObserver::MockDownloadManagerDelegate ...@@ -52,17 +52,20 @@ class DownloadTestFileActivityObserver::MockDownloadManagerDelegate
} }
protected: protected:
void RequestConfirmation(download::DownloadItem* item, void ShowFilePicker(
const base::FilePath& suggested_path, const std::string& guid,
DownloadConfirmationReason reason, const base::FilePath& suggested_path,
const ConfirmationCallback& callback) override { const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback)
override {
file_chooser_displayed_ = true; file_chooser_displayed_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(callback, FROM_HERE,
(file_chooser_enabled_ base::BindOnce(
? DownloadConfirmationResult::CONFIRMED &MockDownloadManagerDelegate::OnConfirmationCallbackComplete,
: DownloadConfirmationResult::CANCELED), base::Unretained(this), callback,
suggested_path)); (file_chooser_enabled_ ? DownloadConfirmationResult::CONFIRMED
: DownloadConfirmationResult::CANCELED),
suggested_path));
} }
void OpenDownload(download::DownloadItem* item) override {} void OpenDownload(download::DownloadItem* item) override {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment