electron/shell/browser/electron_download_manager_delegate.cc
electron-roller[bot] 8532e1239e
chore: bump chromium to 93.0.4530.0 (master) (#29256)
* chore: bump chromium in DEPS to 92.0.4512.6

* 2887336: [CaptureHandle][#2] Propagate CaptureHandleConfig in browser process

https://chromium-review.googlesource.com/c/chromium/src/+/2887336

* refactor: base::Optional -> absl::optional

* chore: fixup patch indices

* chore: bump chromium in DEPS to 92.0.4514.0

* 2899417: Make build work when enable_pdf is set to false.

https://chromium-review.googlesource.com/c/chromium/src/+/2899417

* 2904731: use BrowserContext instead of Profile in PreconnectManager

https://chromium-review.googlesource.com/c/chromium/src/+/2904731

* 2295749: fix: check IsSecureEventInputEnabled in constructor before setting SetPasswordInputEnabled to true

https://chromium-review.googlesource.com/c/chromium/src/+/2295749

* 2893803: Add a GetWebView to RenderFrame.

https://chromium-review.googlesource.com/c/chromium/src/+/2893803

* 2892345: Implement WebContents::ForEachRenderFrameHost

https://chromium-review.googlesource.com/c/chromium/src/+/2892345

* chore: fixup patch indices

* 2892048: Real instance methods for BrowserContext: remaining 5 methods.

https://chromium-review.googlesource.com/c/chromium/src/+/2892048

* 2902821: [mojo] Don't require full header includes for referenced interfaces

https://chromium-review.googlesource.com/c/chromium/src/+/2902821

* 2496500: Remove last deprecated extension Event ctor.

https://chromium-review.googlesource.com/c/chromium/src/+/2496500

* chore: fixup malformed pepper support patch

* chore: bump chromium in DEPS to 92.0.4515.0

* 2908461: Add CreateEmptyPrintPagesParamsPtr() inside print_view_manager_base.cc.

https://chromium-review.googlesource.com/c/chromium/src/+/2908461

* 2880838: viz: add optional HDRMetadata to TransferableResource

https://chromium-review.googlesource.com/c/chromium/src/+/2880838

* chore: fixup patch indices

* chore: bump chromium in DEPS to 92.0.4515.5

* chore: update patches

* chore: bump chromium in DEPS to 92.0.4515.7

* chore: bump chromium in DEPS to 92.0.4515.9

* chore: bump chromium in DEPS to 93.0.4522.0

* chore: bump chromium in DEPS to 93.0.4523.0

* chore: bump chromium in DEPS to 93.0.4524.0

* chore: update patches

* chore: enable_pak_file_integrity_checks was reverted

* chore: update patches

* refactor: base/optional was replaced with absl::optional

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2910202

* refactor: replace all usages of base::nullopt with absl::nullopt

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2910202

* chore: add missing base::Contains include

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2910202

* refactor: replace all usages of base::make_optional with
absl::make_optional

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2910202

* refactor: replace WorldScriptContext() with GetScriptContextFromWorldId

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2893213

* chore: clean up left over opening namespace

Refs: 95bfe6d08f

* chore: add missing base::Contains include

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2910202

* refactor: replace GetCurrentDisplayIterator with the hard checker
GetCurrentDisplay

This code looks suspicious but if the iterator was invalid before it
will also be invalid now.

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2893191

* refactor: headers are now passed directly in extensions client

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2918906

* refactor: base::DictionaryValue::empty() has been removed

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2912424

* chore: add missing includes for network URLLoaderFactory

Refs: unknown, probably a side effect of header changes

* refactor: make convenience wrapper around AppendArg

There is no converter FromV8 for base::StringPiece (apparently its not
possible).  So we now take in an std::string and use the construct for
StringPiece to do implicit conversion.

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2905544

* chore: add patch

* chore: bump chromium in DEPS to 93.0.4525.0

* chore: update patches

* refactor: CanResize has been de-virtualized

Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2485774

* chore: update resource integrity patch

* chore: add character encoding idl patch

* chore: bump chromium in DEPS to 93.0.4526.0

* chore: update patches

* chore: bump chromium in DEPS to 93.0.4527.0

* chore: bump chromium in DEPS to 93.0.4528.0

* chore: update patches

* chore: update idl encoding patch

* chore: bump chromium in DEPS to 93.0.4529.0

* chore: update patches

* chore: bump chromium in DEPS to 93.0.4530.0

* chore: update patches

* fix: only SetCanResize after the widget has been initialized

* chore: add patch for vr on windows gn gen

* spec: fix focus related tests on linux due to delay in focus swap

* chore: remove new usages of base::Optional from main

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <sattard@slack-corp.com>
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-06-03 01:05:04 -07:00

254 lines
9.1 KiB
C++

// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/electron_download_manager_delegate.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "chrome/common/pref_names.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/download_manager.h"
#include "net/base/filename_util.h"
#include "shell/browser/api/electron_api_download_item.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/javascript_environment.h"
#include "shell/browser/native_window.h"
#include "shell/browser/ui/file_dialog.h"
#include "shell/browser/web_contents_preferences.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/options_switches.h"
namespace electron {
namespace {
// Generate default file path to save the download.
base::FilePath CreateDownloadPath(const GURL& url,
const std::string& content_disposition,
const std::string& suggested_filename,
const std::string& mime_type,
const base::FilePath& last_saved_directory,
const base::FilePath& default_download_path) {
auto generated_name =
net::GenerateFileName(url, content_disposition, std::string(),
suggested_filename, mime_type, "download");
base::FilePath download_path;
// If the last saved directory is a non-empty existent path, use it as the
// default.
if (last_saved_directory.empty() || !base::PathExists(last_saved_directory)) {
download_path = default_download_path;
if (!base::PathExists(download_path))
base::CreateDirectory(download_path);
} else {
// Otherwise use the global default.
download_path = last_saved_directory;
}
return download_path.Append(generated_name);
}
} // namespace
ElectronDownloadManagerDelegate::ElectronDownloadManagerDelegate(
content::DownloadManager* manager)
: download_manager_(manager) {}
ElectronDownloadManagerDelegate::~ElectronDownloadManagerDelegate() {
if (download_manager_) {
DCHECK_EQ(static_cast<content::DownloadManagerDelegate*>(this),
download_manager_->GetDelegate());
download_manager_->SetDelegate(nullptr);
download_manager_ = nullptr;
}
}
void ElectronDownloadManagerDelegate::GetItemSavePath(
download::DownloadItem* item,
base::FilePath* path) {
api::DownloadItem* download = api::DownloadItem::FromDownloadItem(item);
if (download)
*path = download->GetSavePath();
}
void ElectronDownloadManagerDelegate::GetItemSaveDialogOptions(
download::DownloadItem* item,
file_dialog::DialogSettings* options) {
api::DownloadItem* download = api::DownloadItem::FromDownloadItem(item);
if (download)
*options = download->GetSaveDialogOptions();
}
void ElectronDownloadManagerDelegate::OnDownloadPathGenerated(
uint32_t download_id,
content::DownloadTargetCallback callback,
const base::FilePath& default_path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::ThreadRestrictions::ScopedAllowIO allow_io;
auto* item = download_manager_->GetDownload(download_id);
if (!item)
return;
NativeWindow* window = nullptr;
content::WebContents* web_contents =
content::DownloadItemUtils::GetWebContents(item);
auto* relay =
web_contents ? NativeWindowRelay::FromWebContents(web_contents) : nullptr;
if (relay)
window = relay->GetNativeWindow();
// Show save dialog if save path was not set already on item
base::FilePath path;
GetItemSavePath(item, &path);
if (path.empty()) {
file_dialog::DialogSettings settings;
GetItemSaveDialogOptions(item, &settings);
if (!settings.parent_window)
settings.parent_window = window;
if (settings.title.empty())
settings.title = item->GetURL().spec();
if (settings.default_path.empty())
settings.default_path = default_path;
auto* web_preferences = WebContentsPreferences::From(web_contents);
const bool offscreen =
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
settings.force_detached = offscreen;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
gin_helper::Promise<gin_helper::Dictionary> dialog_promise(isolate);
auto dialog_callback = base::BindOnce(
&ElectronDownloadManagerDelegate::OnDownloadSaveDialogDone,
base::Unretained(this), download_id, std::move(callback));
ignore_result(dialog_promise.Then(std::move(dialog_callback)));
file_dialog::ShowSaveDialog(settings, std::move(dialog_promise));
} else {
std::move(callback).Run(path,
download::DownloadItem::TARGET_DISPOSITION_PROMPT,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
item->GetMixedContentStatus(), path, absl::nullopt,
download::DOWNLOAD_INTERRUPT_REASON_NONE);
}
}
void ElectronDownloadManagerDelegate::OnDownloadSaveDialogDone(
uint32_t download_id,
content::DownloadTargetCallback download_callback,
gin_helper::Dictionary result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* item = download_manager_->GetDownload(download_id);
if (!item)
return;
bool canceled = true;
result.Get("canceled", &canceled);
base::FilePath path;
if (!canceled) {
if (result.Get("filePath", &path)) {
// Remember the last selected download directory.
last_saved_directory_ = path.DirName();
api::DownloadItem* download = api::DownloadItem::FromDownloadItem(item);
if (download)
download->SetSavePath(path);
}
}
// Running the DownloadTargetCallback with an empty FilePath signals that the
// download should be cancelled. If user cancels the file save dialog, run
// the callback with empty FilePath.
const auto interrupt_reason =
path.empty() ? download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
: download::DOWNLOAD_INTERRUPT_REASON_NONE;
std::move(download_callback)
.Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
item->GetMixedContentStatus(), path, absl::nullopt,
interrupt_reason);
}
void ElectronDownloadManagerDelegate::Shutdown() {
weak_ptr_factory_.InvalidateWeakPtrs();
download_manager_ = nullptr;
}
bool ElectronDownloadManagerDelegate::DetermineDownloadTarget(
download::DownloadItem* download,
content::DownloadTargetCallback* callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!download->GetForcedFilePath().empty()) {
std::move(*callback).Run(
download->GetForcedFilePath(),
download::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download::DownloadItem::MixedContentStatus::UNKNOWN,
download->GetForcedFilePath(), absl::nullopt,
download::DOWNLOAD_INTERRUPT_REASON_NONE);
return true;
}
// Try to get the save path from JS wrapper.
base::FilePath save_path;
GetItemSavePath(download, &save_path);
if (!save_path.empty()) {
std::move(*callback).Run(
save_path, download::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download::DownloadItem::MixedContentStatus::UNKNOWN, save_path,
absl::nullopt, download::DOWNLOAD_INTERRUPT_REASON_NONE);
return true;
}
auto* browser_context = static_cast<ElectronBrowserContext*>(
download_manager_->GetBrowserContext());
base::FilePath default_download_path =
browser_context->prefs()->GetFilePath(prefs::kDownloadDefaultDirectory);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&CreateDownloadPath, download->GetURL(),
download->GetContentDisposition(),
download->GetSuggestedFilename(), download->GetMimeType(),
last_saved_directory_, default_download_path),
base::BindOnce(&ElectronDownloadManagerDelegate::OnDownloadPathGenerated,
weak_ptr_factory_.GetWeakPtr(), download->GetId(),
std::move(*callback)));
return true;
}
bool ElectronDownloadManagerDelegate::ShouldOpenDownload(
download::DownloadItem* download,
content::DownloadOpenDelayedCallback callback) {
return true;
}
void ElectronDownloadManagerDelegate::GetNextId(
content::DownloadIdCallback callback) {
static uint32_t next_id = download::DownloadItem::kInvalidId + 1;
std::move(callback).Run(next_id++);
}
} // namespace electron