chrome: Add CefDownloadHandler support (see #3681)
Behaves the same as Alloy runtime except that CanDownload is not called for invalid protocol schemes.
This commit is contained in:
parent
ed079792b6
commit
be6642df3f
4
BUILD.gn
4
BUILD.gn
|
@ -465,6 +465,8 @@ source_set("libcef_static") {
|
|||
"libcef/browser/alloy/alloy_browser_main.h",
|
||||
"libcef/browser/alloy/alloy_content_browser_client.cc",
|
||||
"libcef/browser/alloy/alloy_content_browser_client.h",
|
||||
"libcef/browser/alloy/alloy_download_manager_delegate.cc",
|
||||
"libcef/browser/alloy/alloy_download_manager_delegate.h",
|
||||
"libcef/browser/alloy/alloy_download_util.cc",
|
||||
"libcef/browser/alloy/alloy_download_util.h",
|
||||
"libcef/browser/alloy/alloy_web_contents_view_delegate.cc",
|
||||
|
@ -576,6 +578,8 @@ source_set("libcef_static") {
|
|||
"libcef/browser/download_item_impl.h",
|
||||
"libcef/browser/download_manager_delegate.cc",
|
||||
"libcef/browser/download_manager_delegate.h",
|
||||
"libcef/browser/download_manager_delegate_impl.cc",
|
||||
"libcef/browser/download_manager_delegate_impl.h",
|
||||
"libcef/browser/extension_impl.cc",
|
||||
"libcef/browser/extension_impl.h",
|
||||
"libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc",
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
// by hand. See the translator.README.txt file in the tools directory for
|
||||
// more information.
|
||||
//
|
||||
// $hash=60a08a60be70e8fe5df17f18f8e5758e1830d5e1$
|
||||
// $hash=7ecfb07a95315ff81937e9f68d419122fc88f1b7$
|
||||
//
|
||||
|
||||
#ifndef CEF_INCLUDE_CAPI_CEF_DOWNLOAD_HANDLER_CAPI_H_
|
||||
|
@ -117,12 +117,13 @@ typedef struct _cef_download_handler_t {
|
|||
|
||||
///
|
||||
/// Called before a download begins. |suggested_name| is the suggested name
|
||||
/// for the download file. By default the download will be canceled. Execute
|
||||
/// |callback| either asynchronously or in this function to continue the
|
||||
/// download if desired. Do not keep a reference to |download_item| outside of
|
||||
/// this function.
|
||||
/// for the download file. Return true (1) and execute |callback| either
|
||||
/// asynchronously or in this function to continue or cancel the download.
|
||||
/// Return false (0) to proceed with default handling (cancel with Alloy
|
||||
/// style, download shelf with Chrome style). Do not keep a reference to
|
||||
/// |download_item| outside of this function.
|
||||
///
|
||||
void(CEF_CALLBACK* on_before_download)(
|
||||
int(CEF_CALLBACK* on_before_download)(
|
||||
struct _cef_download_handler_t* self,
|
||||
struct _cef_browser_t* browser,
|
||||
struct _cef_download_item_t* download_item,
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
// way that may cause binary incompatibility with other builds. The universal
|
||||
// hash value will change if any platform is affected whereas the platform hash
|
||||
// values will change only if that particular platform is affected.
|
||||
#define CEF_API_HASH_UNIVERSAL "faa8a52df058a26e1228da66052a9900a7120de4"
|
||||
#define CEF_API_HASH_UNIVERSAL "73e8743408bfeba0df3b567bfd04b2eb642df11d"
|
||||
#if defined(OS_WIN)
|
||||
#define CEF_API_HASH_PLATFORM "41a15a683e4a2b927f043c22d8a9f07671168170"
|
||||
#define CEF_API_HASH_PLATFORM "3a73f4c69062c6f413e00c1821f6e6df91a2a787"
|
||||
#elif defined(OS_MAC)
|
||||
#define CEF_API_HASH_PLATFORM "6933ff4566b919c045ff0743682889d45ffcba28"
|
||||
#define CEF_API_HASH_PLATFORM "f5fb92747082f06a9c42724b0b717accc29e3879"
|
||||
#elif defined(OS_LINUX)
|
||||
#define CEF_API_HASH_PLATFORM "b12778ab8fd0974e45a246484a31d12f097c7936"
|
||||
#define CEF_API_HASH_PLATFORM "8775d620c6b17725bddba2c1c3a21353b4d8acb1"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -106,17 +106,19 @@ class CefDownloadHandler : public virtual CefBaseRefCounted {
|
|||
|
||||
///
|
||||
/// Called before a download begins. |suggested_name| is the suggested name
|
||||
/// for the download file. By default the download will be canceled. Execute
|
||||
/// |callback| either asynchronously or in this method to continue the
|
||||
/// download if desired. Do not keep a reference to |download_item| outside of
|
||||
/// this method.
|
||||
/// for the download file. Return true and execute |callback| either
|
||||
/// asynchronously or in this method to continue or cancel the download.
|
||||
/// Return false to proceed with default handling (cancel with Alloy style,
|
||||
/// download shelf with Chrome style). Do not keep a reference to
|
||||
/// |download_item| outside of this method.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void OnBeforeDownload(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
virtual bool OnBeforeDownload(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
CefRefPtr<CefBeforeDownloadCallback> callback) = 0;
|
||||
CefRefPtr<CefBeforeDownloadCallback> callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
/// Called when a download's status or progress information has been updated.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "libcef/browser/download_manager_delegate.h"
|
||||
#include "libcef/browser/alloy/alloy_download_manager_delegate.h"
|
||||
#include "libcef/browser/extensions/extension_system.h"
|
||||
#include "libcef/browser/prefs/browser_prefs.h"
|
||||
#include "libcef/browser/ssl_host_state_delegate.h"
|
||||
|
@ -336,7 +336,7 @@ content::DownloadManagerDelegate*
|
|||
AlloyBrowserContext::GetDownloadManagerDelegate() {
|
||||
if (!download_manager_delegate_) {
|
||||
download_manager_delegate_ =
|
||||
std::make_unique<CefDownloadManagerDelegate>(GetDownloadManager());
|
||||
std::make_unique<AlloyDownloadManagerDelegate>(GetDownloadManager());
|
||||
}
|
||||
return download_manager_delegate_.get();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "components/proxy_config/pref_proxy_config_tracker.h"
|
||||
#include "components/visitedlink/browser/visitedlink_delegate.h"
|
||||
|
||||
class CefDownloadManagerDelegate;
|
||||
class AlloyDownloadManagerDelegate;
|
||||
class CefSSLHostStateDelegate;
|
||||
class CefVisitedLinkListener;
|
||||
class PrefService;
|
||||
|
@ -128,7 +128,7 @@ class AlloyBrowserContext : public ChromeProfileAlloy,
|
|||
std::unique_ptr<PrefService> pref_service_;
|
||||
std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
|
||||
|
||||
std::unique_ptr<CefDownloadManagerDelegate> download_manager_delegate_;
|
||||
std::unique_ptr<AlloyDownloadManagerDelegate> download_manager_delegate_;
|
||||
std::unique_ptr<CefSSLHostStateDelegate> ssl_host_state_delegate_;
|
||||
std::unique_ptr<visitedlink::VisitedLinkWriter> visitedlink_master_;
|
||||
// |visitedlink_listener_| is owned by visitedlink_master_.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/alloy/alloy_download_manager_delegate.h"
|
||||
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
#include "components/download/public/common/download_item.h"
|
||||
|
||||
AlloyDownloadManagerDelegate::AlloyDownloadManagerDelegate(
|
||||
content::DownloadManager* manager)
|
||||
: CefDownloadManagerDelegateImpl(manager, /*alloy_bootstrap=*/true) {}
|
||||
|
||||
void AlloyDownloadManagerDelegate::GetNextId(
|
||||
content::DownloadIdCallback callback) {
|
||||
static uint32_t next_id = download::DownloadItem::kInvalidId + 1;
|
||||
std::move(callback).Run(next_id++);
|
||||
}
|
||||
|
||||
std::string AlloyDownloadManagerDelegate::ApplicationClientIdForFileScanning() {
|
||||
return std::string(chrome::kApplicationClientIDStringForAVScanning);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
#pragma once
|
||||
|
||||
#include "libcef/browser/download_manager_delegate_impl.h"
|
||||
|
||||
// Specialization for the Alloy bootstrap.
|
||||
class AlloyDownloadManagerDelegate : public CefDownloadManagerDelegateImpl {
|
||||
public:
|
||||
explicit AlloyDownloadManagerDelegate(content::DownloadManager* manager);
|
||||
|
||||
AlloyDownloadManagerDelegate(const AlloyDownloadManagerDelegate&) = delete;
|
||||
AlloyDownloadManagerDelegate& operator=(const AlloyDownloadManagerDelegate&) =
|
||||
delete;
|
||||
|
||||
private:
|
||||
// DownloadManagerDelegate methods.
|
||||
void GetNextId(content::DownloadIdCallback callback) override;
|
||||
std::string ApplicationClientIdForFileScanning() override;
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DOWNLOAD_MANAGER_DELEGATE_H_
|
|
@ -1,479 +1,20 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/download_manager_delegate.h"
|
||||
|
||||
#include <tuple>
|
||||
#include "libcef/browser/download_manager_delegate_impl.h"
|
||||
#include "libcef/features/runtime_checks.h"
|
||||
|
||||
#include "include/cef_download_handler.h"
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/download_item_impl.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
namespace cef {
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/download_item_utils.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
|
||||
using content::DownloadManager;
|
||||
using content::WebContents;
|
||||
using download::DownloadItem;
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper function to retrieve the CefDownloadHandler.
|
||||
CefRefPtr<CefDownloadHandler> GetDownloadHandler(
|
||||
CefRefPtr<AlloyBrowserHostImpl> browser) {
|
||||
CefRefPtr<CefClient> client = browser->GetClient();
|
||||
if (client.get()) {
|
||||
return client->GetDownloadHandler();
|
||||
}
|
||||
return nullptr;
|
||||
// static
|
||||
std::unique_ptr<cef::DownloadManagerDelegate> DownloadManagerDelegate::Create(
|
||||
content::DownloadManager* download_manager) {
|
||||
REQUIRE_CHROME_RUNTIME();
|
||||
return std::make_unique<CefDownloadManagerDelegateImpl>(
|
||||
download_manager, /*alloy_bootstrap=*/false);
|
||||
}
|
||||
|
||||
void RunDownloadTargetCallback(download::DownloadTargetCallback callback,
|
||||
const base::FilePath& path) {
|
||||
download::DownloadTargetInfo target_info;
|
||||
target_info.target_path = path;
|
||||
target_info.intermediate_path = path;
|
||||
std::move(callback).Run(std::move(target_info));
|
||||
}
|
||||
|
||||
// CefBeforeDownloadCallback implementation.
|
||||
class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
||||
public:
|
||||
CefBeforeDownloadCallbackImpl(const base::WeakPtr<DownloadManager>& manager,
|
||||
uint32_t download_id,
|
||||
const base::FilePath& suggested_name,
|
||||
download::DownloadTargetCallback callback)
|
||||
: manager_(manager),
|
||||
download_id_(download_id),
|
||||
suggested_name_(suggested_name),
|
||||
callback_(std::move(callback)) {}
|
||||
|
||||
CefBeforeDownloadCallbackImpl(const CefBeforeDownloadCallbackImpl&) = delete;
|
||||
CefBeforeDownloadCallbackImpl& operator=(
|
||||
const CefBeforeDownloadCallbackImpl&) = delete;
|
||||
|
||||
void Continue(const CefString& download_path, bool show_dialog) override {
|
||||
if (CEF_CURRENTLY_ON_UIT()) {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
base::FilePath path = base::FilePath(download_path);
|
||||
CEF_POST_USER_VISIBLE_TASK(
|
||||
base::BindOnce(&CefBeforeDownloadCallbackImpl::GenerateFilename,
|
||||
manager_, download_id_, suggested_name_, path,
|
||||
show_dialog, std::move(callback_)));
|
||||
}
|
||||
|
||||
download_id_ = 0;
|
||||
} else {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefBeforeDownloadCallbackImpl::Continue,
|
||||
this, download_path, show_dialog));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void GenerateFilename(base::WeakPtr<DownloadManager> manager,
|
||||
uint32_t download_id,
|
||||
const base::FilePath& suggested_name,
|
||||
const base::FilePath& download_path,
|
||||
bool show_dialog,
|
||||
download::DownloadTargetCallback callback) {
|
||||
CEF_REQUIRE_BLOCKING();
|
||||
|
||||
base::FilePath suggested_path = download_path;
|
||||
if (!suggested_path.empty()) {
|
||||
// Create the directory if necessary.
|
||||
base::FilePath dir_path = suggested_path.DirName();
|
||||
if (!base::DirectoryExists(dir_path) &&
|
||||
!base::CreateDirectory(dir_path)) {
|
||||
DCHECK(false) << "failed to create the download directory";
|
||||
suggested_path.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (suggested_path.empty()) {
|
||||
if (base::PathService::Get(base::DIR_TEMP, &suggested_path)) {
|
||||
// Use the temp directory.
|
||||
suggested_path = suggested_path.Append(suggested_name);
|
||||
} else {
|
||||
// Use the current working directory.
|
||||
suggested_path = suggested_name;
|
||||
}
|
||||
}
|
||||
|
||||
CEF_POST_TASK(
|
||||
CEF_UIT,
|
||||
base::BindOnce(&CefBeforeDownloadCallbackImpl::ChooseDownloadPath,
|
||||
manager, download_id, suggested_path, show_dialog,
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
static void ChooseDownloadPath(base::WeakPtr<DownloadManager> manager,
|
||||
uint32_t download_id,
|
||||
const base::FilePath& suggested_path,
|
||||
bool show_dialog,
|
||||
download::DownloadTargetCallback callback) {
|
||||
if (!manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadItem* item = manager->GetDownload(download_id);
|
||||
if (!item || item->GetState() != DownloadItem::IN_PROGRESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
if (show_dialog) {
|
||||
WebContents* web_contents =
|
||||
content::DownloadItemUtils::GetWebContents(item);
|
||||
CefRefPtr<AlloyBrowserHostImpl> browser =
|
||||
AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
|
||||
if (browser.get()) {
|
||||
handled = true;
|
||||
|
||||
blink::mojom::FileChooserParams params;
|
||||
params.mode = blink::mojom::FileChooserParams::Mode::kSave;
|
||||
if (!suggested_path.empty()) {
|
||||
params.default_file_name = suggested_path;
|
||||
if (!suggested_path.Extension().empty()) {
|
||||
params.accept_types.push_back(
|
||||
CefString(suggested_path.Extension()));
|
||||
}
|
||||
}
|
||||
|
||||
browser->RunFileChooserForBrowser(
|
||||
params,
|
||||
base::BindOnce(
|
||||
&CefBeforeDownloadCallbackImpl::ChooseDownloadPathCallback,
|
||||
std::move(callback)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
RunDownloadTargetCallback(std::move(callback), suggested_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void ChooseDownloadPathCallback(
|
||||
download::DownloadTargetCallback callback,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
DCHECK_LE(file_paths.size(), (size_t)1);
|
||||
|
||||
base::FilePath path;
|
||||
if (file_paths.size() > 0) {
|
||||
path = file_paths.front();
|
||||
}
|
||||
|
||||
// The download will be cancelled if |path| is empty.
|
||||
RunDownloadTargetCallback(std::move(callback), path);
|
||||
}
|
||||
|
||||
base::WeakPtr<DownloadManager> manager_;
|
||||
uint32_t download_id_;
|
||||
base::FilePath suggested_name_;
|
||||
download::DownloadTargetCallback callback_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CefBeforeDownloadCallbackImpl);
|
||||
};
|
||||
|
||||
// CefDownloadItemCallback implementation.
|
||||
class CefDownloadItemCallbackImpl : public CefDownloadItemCallback {
|
||||
public:
|
||||
explicit CefDownloadItemCallbackImpl(
|
||||
const base::WeakPtr<DownloadManager>& manager,
|
||||
uint32_t download_id)
|
||||
: manager_(manager), download_id_(download_id) {}
|
||||
|
||||
CefDownloadItemCallbackImpl(const CefDownloadItemCallbackImpl&) = delete;
|
||||
CefDownloadItemCallbackImpl& operator=(const CefDownloadItemCallbackImpl&) =
|
||||
delete;
|
||||
|
||||
void Cancel() override {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefDownloadItemCallbackImpl::DoCancel, this));
|
||||
}
|
||||
|
||||
void Pause() override {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefDownloadItemCallbackImpl::DoPause, this));
|
||||
}
|
||||
|
||||
void Resume() override {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefDownloadItemCallbackImpl::DoResume, this));
|
||||
}
|
||||
|
||||
private:
|
||||
void DoCancel() {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
DownloadItem* item = manager_->GetDownload(download_id_);
|
||||
if (item && item->GetState() == DownloadItem::IN_PROGRESS) {
|
||||
item->Cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
download_id_ = 0;
|
||||
}
|
||||
|
||||
void DoPause() {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
DownloadItem* item = manager_->GetDownload(download_id_);
|
||||
if (item && item->GetState() == DownloadItem::IN_PROGRESS) {
|
||||
item->Pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoResume() {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
DownloadItem* item = manager_->GetDownload(download_id_);
|
||||
if (item && item->CanResume()) {
|
||||
item->Resume(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base::WeakPtr<DownloadManager> manager_;
|
||||
uint32_t download_id_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CefDownloadItemCallbackImpl);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
CefDownloadManagerDelegate::CefDownloadManagerDelegate(DownloadManager* manager)
|
||||
: manager_(manager), manager_ptr_factory_(manager) {
|
||||
DCHECK(manager);
|
||||
manager->AddObserver(this);
|
||||
|
||||
DownloadManager::DownloadVector items;
|
||||
manager->GetAllDownloads(&items);
|
||||
DownloadManager::DownloadVector::const_iterator it = items.begin();
|
||||
for (; it != items.end(); ++it) {
|
||||
OnDownloadCreated(manager, *it);
|
||||
}
|
||||
}
|
||||
|
||||
CefDownloadManagerDelegate::~CefDownloadManagerDelegate() {
|
||||
if (manager_) {
|
||||
manager_->SetDelegate(nullptr);
|
||||
manager_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
while (!item_browser_map_.empty()) {
|
||||
OnDownloadDestroyed(item_browser_map_.begin()->first);
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::OnDownloadUpdated(DownloadItem* download) {
|
||||
CefRefPtr<AlloyBrowserHostImpl> browser = GetBrowser(download);
|
||||
CefRefPtr<CefDownloadHandler> handler;
|
||||
if (browser.get()) {
|
||||
handler = GetDownloadHandler(browser);
|
||||
}
|
||||
|
||||
if (handler.get()) {
|
||||
CefRefPtr<CefDownloadItemImpl> download_item(
|
||||
new CefDownloadItemImpl(download));
|
||||
CefRefPtr<CefDownloadItemCallback> callback(new CefDownloadItemCallbackImpl(
|
||||
manager_ptr_factory_.GetWeakPtr(), download->GetId()));
|
||||
|
||||
handler->OnDownloadUpdated(browser.get(), download_item.get(), callback);
|
||||
|
||||
std::ignore = download_item->Detach(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::OnDownloadDestroyed(DownloadItem* item) {
|
||||
item->RemoveObserver(this);
|
||||
|
||||
AlloyBrowserHostImpl* browser = nullptr;
|
||||
|
||||
ItemBrowserMap::iterator it = item_browser_map_.find(item);
|
||||
DCHECK(it != item_browser_map_.end());
|
||||
if (it != item_browser_map_.end()) {
|
||||
browser = it->second;
|
||||
item_browser_map_.erase(it);
|
||||
}
|
||||
|
||||
if (browser) {
|
||||
// Determine if any remaining DownloadItems are associated with the same
|
||||
// browser. If not, then unregister as an observer.
|
||||
bool has_remaining = false;
|
||||
ItemBrowserMap::const_iterator it2 = item_browser_map_.begin();
|
||||
for (; it2 != item_browser_map_.end(); ++it2) {
|
||||
if (it2->second == browser) {
|
||||
has_remaining = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_remaining) {
|
||||
browser->RemoveObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::OnDownloadCreated(DownloadManager* manager,
|
||||
DownloadItem* item) {
|
||||
// This callback may arrive after DetermineDownloadTarget, so we allow
|
||||
// association from either method.
|
||||
CefRefPtr<AlloyBrowserHostImpl> browser = GetOrAssociateBrowser(item);
|
||||
if (!browser) {
|
||||
// If the download is rejected (e.g. ALT+click on an invalid protocol link)
|
||||
// then an "interrupted" download will be started via DownloadManagerImpl::
|
||||
// StartDownloadWithId (originating from CreateInterruptedDownload) with no
|
||||
// associated WebContents and consequently no associated CEF browser. In
|
||||
// that case DetermineDownloadTarget will be called before this method.
|
||||
// TODO(cef): Figure out how to expose this via a client callback.
|
||||
const std::vector<GURL>& url_chain = item->GetUrlChain();
|
||||
if (!url_chain.empty()) {
|
||||
LOG(INFO) << "Rejected download of " << url_chain.back().spec();
|
||||
}
|
||||
item->Cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::ManagerGoingDown(DownloadManager* manager) {
|
||||
DCHECK_EQ(manager, manager_);
|
||||
manager->SetDelegate(nullptr);
|
||||
manager->RemoveObserver(this);
|
||||
manager_ptr_factory_.InvalidateWeakPtrs();
|
||||
manager_ = nullptr;
|
||||
}
|
||||
|
||||
bool CefDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
DownloadItem* item,
|
||||
download::DownloadTargetCallback* callback) {
|
||||
const auto& forced_path = item->GetForcedFilePath();
|
||||
if (!forced_path.empty()) {
|
||||
RunDownloadTargetCallback(std::move(*callback), forced_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This callback may arrive before OnDownloadCreated, so we allow association
|
||||
// from either method.
|
||||
CefRefPtr<AlloyBrowserHostImpl> browser = GetOrAssociateBrowser(item);
|
||||
CefRefPtr<CefDownloadHandler> handler;
|
||||
if (browser.get()) {
|
||||
handler = GetDownloadHandler(browser);
|
||||
}
|
||||
|
||||
if (handler.get()) {
|
||||
base::FilePath suggested_name = net::GenerateFileName(
|
||||
item->GetURL(), item->GetContentDisposition(), std::string(),
|
||||
item->GetSuggestedFilename(), item->GetMimeType(), "download");
|
||||
|
||||
CefRefPtr<CefDownloadItemImpl> download_item(new CefDownloadItemImpl(item));
|
||||
CefRefPtr<CefBeforeDownloadCallback> callbackObj(
|
||||
new CefBeforeDownloadCallbackImpl(manager_ptr_factory_.GetWeakPtr(),
|
||||
item->GetId(), suggested_name,
|
||||
std::move(*callback)));
|
||||
|
||||
handler->OnBeforeDownload(browser.get(), download_item.get(),
|
||||
suggested_name.value(), callbackObj);
|
||||
|
||||
std::ignore = download_item->Detach(nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::GetNextId(
|
||||
content::DownloadIdCallback callback) {
|
||||
static uint32_t next_id = DownloadItem::kInvalidId + 1;
|
||||
std::move(callback).Run(next_id++);
|
||||
}
|
||||
|
||||
std::string CefDownloadManagerDelegate::ApplicationClientIdForFileScanning() {
|
||||
return std::string(chrome::kApplicationClientIDStringForAVScanning);
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::OnBrowserDestroyed(
|
||||
CefBrowserHostBase* browser) {
|
||||
ItemBrowserMap::iterator it = item_browser_map_.begin();
|
||||
for (; it != item_browser_map_.end(); ++it) {
|
||||
if (it->second == browser) {
|
||||
// Don't call back into browsers that have been destroyed. We're not
|
||||
// canceling the download so it will continue silently until it completes
|
||||
// or until the associated browser context is destroyed.
|
||||
it->second = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlloyBrowserHostImpl* CefDownloadManagerDelegate::GetOrAssociateBrowser(
|
||||
download::DownloadItem* item) {
|
||||
ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
|
||||
if (it != item_browser_map_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
AlloyBrowserHostImpl* browser = nullptr;
|
||||
content::WebContents* contents =
|
||||
content::DownloadItemUtils::GetWebContents(item);
|
||||
if (contents) {
|
||||
browser = AlloyBrowserHostImpl::GetBrowserForContents(contents).get();
|
||||
DCHECK(browser);
|
||||
}
|
||||
if (!browser) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
item->AddObserver(this);
|
||||
|
||||
item_browser_map_.insert(std::make_pair(item, browser));
|
||||
|
||||
// Register as an observer so that we can cancel associated DownloadItems when
|
||||
// the browser is destroyed.
|
||||
if (!browser->HasObserver(this)) {
|
||||
browser->AddObserver(this);
|
||||
}
|
||||
|
||||
return browser;
|
||||
}
|
||||
|
||||
AlloyBrowserHostImpl* CefDownloadManagerDelegate::GetBrowser(
|
||||
DownloadItem* item) {
|
||||
ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
|
||||
if (it != item_browser_map_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// If the download is rejected (e.g. ALT+click on an invalid protocol link)
|
||||
// then an "interrupted" download will be started via DownloadManagerImpl::
|
||||
// StartDownloadWithId (originating from CreateInterruptedDownload) with no
|
||||
// associated WebContents and consequently no associated CEF browser. In that
|
||||
// case DetermineDownloadTarget will be called before OnDownloadCreated.
|
||||
DCHECK(!content::DownloadItemUtils::GetWebContents(item));
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace cef
|
||||
|
|
|
@ -1,68 +1,33 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
#define CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "components/download/public/common/download_item.h"
|
||||
#include "components/download/public/common/download_target_info.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/download_manager_delegate.h"
|
||||
|
||||
class AlloyBrowserHostImpl;
|
||||
namespace content {
|
||||
class DownloadManager;
|
||||
} // namespace content
|
||||
|
||||
class CefDownloadManagerDelegate : public download::DownloadItem::Observer,
|
||||
public content::DownloadManager::Observer,
|
||||
public content::DownloadManagerDelegate,
|
||||
public CefBrowserHostBase::Observer {
|
||||
namespace cef {
|
||||
|
||||
class DownloadManagerDelegate : public content::DownloadManagerDelegate {
|
||||
public:
|
||||
explicit CefDownloadManagerDelegate(content::DownloadManager* manager);
|
||||
|
||||
CefDownloadManagerDelegate(const CefDownloadManagerDelegate&) = delete;
|
||||
CefDownloadManagerDelegate& operator=(const CefDownloadManagerDelegate&) =
|
||||
delete;
|
||||
|
||||
~CefDownloadManagerDelegate() override;
|
||||
// Called from the ChromeDownloadManagerDelegate constructor for Chrome
|
||||
// bootstrap. Alloy bootstrap uses AlloyDownloadManagerDelegate directly.
|
||||
static std::unique_ptr<DownloadManagerDelegate> Create(
|
||||
content::DownloadManager* download_manager);
|
||||
|
||||
private:
|
||||
// DownloadItem::Observer methods.
|
||||
void OnDownloadUpdated(download::DownloadItem* item) override;
|
||||
void OnDownloadDestroyed(download::DownloadItem* item) override;
|
||||
|
||||
// DownloadManager::Observer methods.
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
download::DownloadItem* item) override;
|
||||
void ManagerGoingDown(content::DownloadManager* manager) override;
|
||||
|
||||
// DownloadManagerDelegate methods.
|
||||
bool DetermineDownloadTarget(
|
||||
download::DownloadItem* item,
|
||||
download::DownloadTargetCallback* callback) override;
|
||||
void GetNextId(content::DownloadIdCallback callback) override;
|
||||
std::string ApplicationClientIdForFileScanning() override;
|
||||
|
||||
// CefBrowserHostBase::Observer methods.
|
||||
void OnBrowserDestroyed(CefBrowserHostBase* browser) override;
|
||||
|
||||
AlloyBrowserHostImpl* GetOrAssociateBrowser(download::DownloadItem* item);
|
||||
AlloyBrowserHostImpl* GetBrowser(download::DownloadItem* item);
|
||||
|
||||
content::DownloadManager* manager_;
|
||||
base::WeakPtrFactory<content::DownloadManager> manager_ptr_factory_;
|
||||
|
||||
// Map of DownloadItem to originating AlloyBrowserHostImpl. Maintaining this
|
||||
// map is necessary because DownloadItem::GetWebContents() may return NULL if
|
||||
// the browser navigates while the download is in progress.
|
||||
using ItemBrowserMap =
|
||||
std::map<download::DownloadItem*, AlloyBrowserHostImpl*>;
|
||||
ItemBrowserMap item_browser_map_;
|
||||
// Allow deletion via std::unique_ptr only.
|
||||
friend std::default_delete<DownloadManagerDelegate>;
|
||||
};
|
||||
|
||||
} // namespace cef
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
|
|
|
@ -0,0 +1,498 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/download_manager_delegate_impl.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "include/cef_download_handler.h"
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/download_item_impl.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/download_item_utils.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
|
||||
using content::DownloadManager;
|
||||
using content::WebContents;
|
||||
using download::DownloadItem;
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper function to retrieve the CefDownloadHandler.
|
||||
CefRefPtr<CefDownloadHandler> GetDownloadHandler(
|
||||
CefRefPtr<CefBrowserHostBase> browser) {
|
||||
CefRefPtr<CefClient> client = browser->GetClient();
|
||||
if (client.get()) {
|
||||
return client->GetDownloadHandler();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RunDownloadTargetCallback(download::DownloadTargetCallback callback,
|
||||
const base::FilePath& path) {
|
||||
download::DownloadTargetInfo target_info;
|
||||
target_info.target_path = path;
|
||||
target_info.intermediate_path = path;
|
||||
std::move(callback).Run(std::move(target_info));
|
||||
}
|
||||
|
||||
// CefBeforeDownloadCallback implementation.
|
||||
class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
||||
public:
|
||||
CefBeforeDownloadCallbackImpl(const base::WeakPtr<DownloadManager>& manager,
|
||||
uint32_t download_id,
|
||||
const base::FilePath& suggested_name,
|
||||
download::DownloadTargetCallback callback)
|
||||
: manager_(manager),
|
||||
download_id_(download_id),
|
||||
suggested_name_(suggested_name),
|
||||
callback_(std::move(callback)) {}
|
||||
|
||||
CefBeforeDownloadCallbackImpl(const CefBeforeDownloadCallbackImpl&) = delete;
|
||||
CefBeforeDownloadCallbackImpl& operator=(
|
||||
const CefBeforeDownloadCallbackImpl&) = delete;
|
||||
|
||||
void Continue(const CefString& download_path, bool show_dialog) override {
|
||||
if (CEF_CURRENTLY_ON_UIT()) {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
base::FilePath path = base::FilePath(download_path);
|
||||
CEF_POST_USER_VISIBLE_TASK(
|
||||
base::BindOnce(&CefBeforeDownloadCallbackImpl::GenerateFilename,
|
||||
manager_, download_id_, suggested_name_, path,
|
||||
show_dialog, std::move(callback_)));
|
||||
}
|
||||
|
||||
download_id_ = 0;
|
||||
} else {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefBeforeDownloadCallbackImpl::Continue,
|
||||
this, download_path, show_dialog));
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDetached() const { return callback_.is_null(); }
|
||||
[[nodiscard]] download::DownloadTargetCallback Detach() {
|
||||
return std::move(callback_);
|
||||
}
|
||||
|
||||
private:
|
||||
static void GenerateFilename(base::WeakPtr<DownloadManager> manager,
|
||||
uint32_t download_id,
|
||||
const base::FilePath& suggested_name,
|
||||
const base::FilePath& download_path,
|
||||
bool show_dialog,
|
||||
download::DownloadTargetCallback callback) {
|
||||
CEF_REQUIRE_BLOCKING();
|
||||
|
||||
base::FilePath suggested_path = download_path;
|
||||
if (!suggested_path.empty()) {
|
||||
// Create the directory if necessary.
|
||||
base::FilePath dir_path = suggested_path.DirName();
|
||||
if (!base::DirectoryExists(dir_path) &&
|
||||
!base::CreateDirectory(dir_path)) {
|
||||
DCHECK(false) << "failed to create the download directory";
|
||||
suggested_path.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (suggested_path.empty()) {
|
||||
if (base::PathService::Get(base::DIR_TEMP, &suggested_path)) {
|
||||
// Use the temp directory.
|
||||
suggested_path = suggested_path.Append(suggested_name);
|
||||
} else {
|
||||
// Use the current working directory.
|
||||
suggested_path = suggested_name;
|
||||
}
|
||||
}
|
||||
|
||||
CEF_POST_TASK(
|
||||
CEF_UIT,
|
||||
base::BindOnce(&CefBeforeDownloadCallbackImpl::ChooseDownloadPath,
|
||||
manager, download_id, suggested_path, show_dialog,
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
static void ChooseDownloadPath(base::WeakPtr<DownloadManager> manager,
|
||||
uint32_t download_id,
|
||||
const base::FilePath& suggested_path,
|
||||
bool show_dialog,
|
||||
download::DownloadTargetCallback callback) {
|
||||
if (!manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadItem* item = manager->GetDownload(download_id);
|
||||
if (!item || item->GetState() != DownloadItem::IN_PROGRESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
if (show_dialog) {
|
||||
WebContents* web_contents =
|
||||
content::DownloadItemUtils::GetWebContents(item);
|
||||
CefRefPtr<CefBrowserHostBase> browser =
|
||||
CefBrowserHostBase::GetBrowserForContents(web_contents);
|
||||
if (browser.get()) {
|
||||
handled = true;
|
||||
|
||||
blink::mojom::FileChooserParams params;
|
||||
params.mode = blink::mojom::FileChooserParams::Mode::kSave;
|
||||
if (!suggested_path.empty()) {
|
||||
params.default_file_name = suggested_path;
|
||||
if (!suggested_path.Extension().empty()) {
|
||||
params.accept_types.push_back(
|
||||
CefString(suggested_path.Extension()));
|
||||
}
|
||||
}
|
||||
|
||||
browser->RunFileChooserForBrowser(
|
||||
params,
|
||||
base::BindOnce(
|
||||
&CefBeforeDownloadCallbackImpl::ChooseDownloadPathCallback,
|
||||
std::move(callback)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
RunDownloadTargetCallback(std::move(callback), suggested_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void ChooseDownloadPathCallback(
|
||||
download::DownloadTargetCallback callback,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
DCHECK_LE(file_paths.size(), (size_t)1);
|
||||
|
||||
base::FilePath path;
|
||||
if (file_paths.size() > 0) {
|
||||
path = file_paths.front();
|
||||
}
|
||||
|
||||
// The download will be cancelled if |path| is empty.
|
||||
RunDownloadTargetCallback(std::move(callback), path);
|
||||
}
|
||||
|
||||
base::WeakPtr<DownloadManager> manager_;
|
||||
uint32_t download_id_;
|
||||
base::FilePath suggested_name_;
|
||||
download::DownloadTargetCallback callback_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CefBeforeDownloadCallbackImpl);
|
||||
};
|
||||
|
||||
// CefDownloadItemCallback implementation.
|
||||
class CefDownloadItemCallbackImpl : public CefDownloadItemCallback {
|
||||
public:
|
||||
explicit CefDownloadItemCallbackImpl(
|
||||
const base::WeakPtr<DownloadManager>& manager,
|
||||
uint32_t download_id)
|
||||
: manager_(manager), download_id_(download_id) {}
|
||||
|
||||
CefDownloadItemCallbackImpl(const CefDownloadItemCallbackImpl&) = delete;
|
||||
CefDownloadItemCallbackImpl& operator=(const CefDownloadItemCallbackImpl&) =
|
||||
delete;
|
||||
|
||||
void Cancel() override {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefDownloadItemCallbackImpl::DoCancel, this));
|
||||
}
|
||||
|
||||
void Pause() override {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefDownloadItemCallbackImpl::DoPause, this));
|
||||
}
|
||||
|
||||
void Resume() override {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefDownloadItemCallbackImpl::DoResume, this));
|
||||
}
|
||||
|
||||
private:
|
||||
void DoCancel() {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
DownloadItem* item = manager_->GetDownload(download_id_);
|
||||
if (item && item->GetState() == DownloadItem::IN_PROGRESS) {
|
||||
item->Cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
download_id_ = 0;
|
||||
}
|
||||
|
||||
void DoPause() {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
DownloadItem* item = manager_->GetDownload(download_id_);
|
||||
if (item && item->GetState() == DownloadItem::IN_PROGRESS) {
|
||||
item->Pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoResume() {
|
||||
if (download_id_ <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager_) {
|
||||
DownloadItem* item = manager_->GetDownload(download_id_);
|
||||
if (item && item->CanResume()) {
|
||||
item->Resume(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base::WeakPtr<DownloadManager> manager_;
|
||||
uint32_t download_id_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CefDownloadItemCallbackImpl);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
CefDownloadManagerDelegateImpl::CefDownloadManagerDelegateImpl(
|
||||
DownloadManager* manager,
|
||||
bool alloy_bootstrap)
|
||||
: manager_(manager),
|
||||
manager_ptr_factory_(manager),
|
||||
alloy_bootstrap_(alloy_bootstrap) {
|
||||
DCHECK(manager);
|
||||
manager->AddObserver(this);
|
||||
|
||||
DownloadManager::DownloadVector items;
|
||||
manager->GetAllDownloads(&items);
|
||||
DownloadManager::DownloadVector::const_iterator it = items.begin();
|
||||
for (; it != items.end(); ++it) {
|
||||
OnDownloadCreated(manager, *it);
|
||||
}
|
||||
}
|
||||
|
||||
CefDownloadManagerDelegateImpl::~CefDownloadManagerDelegateImpl() {
|
||||
ResetManager();
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegateImpl::OnDownloadUpdated(DownloadItem* download) {
|
||||
CefRefPtr<CefBrowserHostBase> browser = GetBrowser(download);
|
||||
CefRefPtr<CefDownloadHandler> handler;
|
||||
if (browser.get()) {
|
||||
handler = GetDownloadHandler(browser);
|
||||
}
|
||||
|
||||
if (handler.get()) {
|
||||
CefRefPtr<CefDownloadItemImpl> download_item(
|
||||
new CefDownloadItemImpl(download));
|
||||
CefRefPtr<CefDownloadItemCallback> callback(new CefDownloadItemCallbackImpl(
|
||||
manager_ptr_factory_.GetWeakPtr(), download->GetId()));
|
||||
|
||||
handler->OnDownloadUpdated(browser.get(), download_item.get(), callback);
|
||||
|
||||
std::ignore = download_item->Detach(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegateImpl::OnDownloadDestroyed(DownloadItem* item) {
|
||||
item->RemoveObserver(this);
|
||||
|
||||
CefBrowserHostBase* browser = nullptr;
|
||||
|
||||
ItemBrowserMap::iterator it = item_browser_map_.find(item);
|
||||
DCHECK(it != item_browser_map_.end());
|
||||
if (it != item_browser_map_.end()) {
|
||||
browser = it->second;
|
||||
item_browser_map_.erase(it);
|
||||
}
|
||||
|
||||
if (browser) {
|
||||
// Determine if any remaining DownloadItems are associated with the same
|
||||
// browser. If not, then unregister as an observer.
|
||||
bool has_remaining = false;
|
||||
ItemBrowserMap::const_iterator it2 = item_browser_map_.begin();
|
||||
for (; it2 != item_browser_map_.end(); ++it2) {
|
||||
if (it2->second == browser) {
|
||||
has_remaining = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_remaining) {
|
||||
browser->RemoveObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegateImpl::OnDownloadCreated(DownloadManager* manager,
|
||||
DownloadItem* item) {
|
||||
// This callback may arrive after DetermineDownloadTarget, so we allow
|
||||
// association from either method.
|
||||
CefRefPtr<CefBrowserHostBase> browser = GetOrAssociateBrowser(item);
|
||||
if (!browser) {
|
||||
// If the download is rejected (e.g. ALT+click on an invalid protocol link)
|
||||
// then an "interrupted" download will be started via DownloadManagerImpl::
|
||||
// StartDownloadWithId (originating from CreateInterruptedDownload) with no
|
||||
// associated WebContents and consequently no associated CEF browser. In
|
||||
// that case DetermineDownloadTarget will be called before this method.
|
||||
// TODO(cef): Figure out how to expose this via a client callback.
|
||||
const std::vector<GURL>& url_chain = item->GetUrlChain();
|
||||
if (!url_chain.empty()) {
|
||||
LOG(INFO) << "Rejected download of " << url_chain.back().spec();
|
||||
}
|
||||
item->Cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegateImpl::ManagerGoingDown(
|
||||
DownloadManager* manager) {
|
||||
DCHECK_EQ(manager, manager_);
|
||||
ResetManager();
|
||||
}
|
||||
|
||||
bool CefDownloadManagerDelegateImpl::DetermineDownloadTarget(
|
||||
DownloadItem* item,
|
||||
download::DownloadTargetCallback* callback) {
|
||||
if (alloy_bootstrap_) {
|
||||
const auto& forced_path = item->GetForcedFilePath();
|
||||
if (!forced_path.empty()) {
|
||||
RunDownloadTargetCallback(std::move(*callback), forced_path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// This callback may arrive before OnDownloadCreated, so we allow association
|
||||
// from either method.
|
||||
CefRefPtr<CefBrowserHostBase> browser = GetOrAssociateBrowser(item);
|
||||
if (!browser) {
|
||||
// Cancel by default with Alloy bootstrap.
|
||||
return alloy_bootstrap_;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
CefRefPtr<CefDownloadHandler> handler = GetDownloadHandler(browser);
|
||||
if (handler) {
|
||||
base::FilePath suggested_name = net::GenerateFileName(
|
||||
item->GetURL(), item->GetContentDisposition(), std::string(),
|
||||
item->GetSuggestedFilename(), item->GetMimeType(), "download");
|
||||
|
||||
CefRefPtr<CefDownloadItemImpl> download_item(new CefDownloadItemImpl(item));
|
||||
CefRefPtr<CefBeforeDownloadCallbackImpl> callbackObj(
|
||||
new CefBeforeDownloadCallbackImpl(manager_ptr_factory_.GetWeakPtr(),
|
||||
item->GetId(), suggested_name,
|
||||
std::move(*callback)));
|
||||
|
||||
handled =
|
||||
handler->OnBeforeDownload(browser.get(), download_item.get(),
|
||||
suggested_name.value(), callbackObj.get());
|
||||
if (!handled && callbackObj->IsDetached()) {
|
||||
LOG(ERROR) << "Should return true from OnBeforeDownload when executing "
|
||||
"the callback";
|
||||
handled = true;
|
||||
}
|
||||
if (!handled) {
|
||||
*callback = callbackObj->Detach();
|
||||
}
|
||||
|
||||
std::ignore = download_item->Detach(nullptr);
|
||||
}
|
||||
|
||||
// Cancel by default with Alloy style.
|
||||
return handled ? true : alloy_bootstrap_;
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegateImpl::OnBrowserDestroyed(
|
||||
CefBrowserHostBase* browser) {
|
||||
ItemBrowserMap::iterator it = item_browser_map_.begin();
|
||||
for (; it != item_browser_map_.end(); ++it) {
|
||||
if (it->second == browser) {
|
||||
// Don't call back into browsers that have been destroyed. We're not
|
||||
// canceling the download so it will continue silently until it completes
|
||||
// or until the associated browser context is destroyed.
|
||||
it->second = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserHostBase>
|
||||
CefDownloadManagerDelegateImpl::GetOrAssociateBrowser(
|
||||
download::DownloadItem* item) {
|
||||
ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
|
||||
if (it != item_browser_map_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> browser;
|
||||
content::WebContents* contents =
|
||||
content::DownloadItemUtils::GetWebContents(item);
|
||||
if (contents) {
|
||||
browser = CefBrowserHostBase::GetBrowserForContents(contents);
|
||||
LOG_IF(WARNING, !browser) << "No CefBrowser for download item";
|
||||
}
|
||||
if (!browser) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
item->AddObserver(this);
|
||||
|
||||
item_browser_map_.insert(std::make_pair(item, browser.get()));
|
||||
|
||||
// Register as an observer so that we can cancel associated DownloadItems when
|
||||
// the browser is destroyed.
|
||||
if (!browser->HasObserver(this)) {
|
||||
browser->AddObserver(this);
|
||||
}
|
||||
|
||||
return browser;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> CefDownloadManagerDelegateImpl::GetBrowser(
|
||||
DownloadItem* item) {
|
||||
ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
|
||||
if (it != item_browser_map_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// If the download is rejected (e.g. ALT+click on an invalid protocol link)
|
||||
// then an "interrupted" download will be started via DownloadManagerImpl::
|
||||
// StartDownloadWithId (originating from CreateInterruptedDownload) with no
|
||||
// associated WebContents and consequently no associated CEF browser. In that
|
||||
// case DetermineDownloadTarget will be called before OnDownloadCreated.
|
||||
DCHECK(!content::DownloadItemUtils::GetWebContents(item));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegateImpl::ResetManager() {
|
||||
if (manager_) {
|
||||
if (alloy_bootstrap_) {
|
||||
manager_->SetDelegate(nullptr);
|
||||
}
|
||||
manager_->RemoveObserver(this);
|
||||
manager_ptr_factory_.InvalidateWeakPtrs();
|
||||
manager_ = nullptr;
|
||||
}
|
||||
|
||||
while (!item_browser_map_.empty()) {
|
||||
OnDownloadDestroyed(item_browser_map_.begin()->first);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_IMPL_H_
|
||||
#define CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_IMPL_H_
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
#include "libcef/browser/download_manager_delegate.h"
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "components/download/public/common/download_item.h"
|
||||
#include "components/download/public/common/download_target_info.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
|
||||
class CefBrowserHostBase;
|
||||
|
||||
class CefDownloadManagerDelegateImpl
|
||||
: public download::DownloadItem::Observer,
|
||||
public content::DownloadManager::Observer,
|
||||
public cef::DownloadManagerDelegate,
|
||||
public CefBrowserHostBase::Observer {
|
||||
public:
|
||||
CefDownloadManagerDelegateImpl(content::DownloadManager* manager,
|
||||
bool alloy_bootstrap);
|
||||
|
||||
CefDownloadManagerDelegateImpl(const CefDownloadManagerDelegateImpl&) =
|
||||
delete;
|
||||
CefDownloadManagerDelegateImpl& operator=(
|
||||
const CefDownloadManagerDelegateImpl&) = delete;
|
||||
|
||||
~CefDownloadManagerDelegateImpl() override;
|
||||
|
||||
private:
|
||||
// DownloadItem::Observer methods.
|
||||
void OnDownloadUpdated(download::DownloadItem* item) override;
|
||||
void OnDownloadDestroyed(download::DownloadItem* item) override;
|
||||
|
||||
// DownloadManager::Observer methods.
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
download::DownloadItem* item) override;
|
||||
void ManagerGoingDown(content::DownloadManager* manager) override;
|
||||
|
||||
// DownloadManagerDelegate methods.
|
||||
bool DetermineDownloadTarget(
|
||||
download::DownloadItem* item,
|
||||
download::DownloadTargetCallback* callback) override;
|
||||
|
||||
// CefBrowserHostBase::Observer methods.
|
||||
void OnBrowserDestroyed(CefBrowserHostBase* browser) override;
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> GetOrAssociateBrowser(
|
||||
download::DownloadItem* item);
|
||||
CefRefPtr<CefBrowserHostBase> GetBrowser(download::DownloadItem* item);
|
||||
|
||||
void ResetManager();
|
||||
|
||||
content::DownloadManager* manager_;
|
||||
base::WeakPtrFactory<content::DownloadManager> manager_ptr_factory_;
|
||||
const bool alloy_bootstrap_;
|
||||
|
||||
// Map of DownloadItem to originating CefBrowserHostBase. Maintaining this
|
||||
// map is necessary because DownloadItem::GetWebContents() may return NULL if
|
||||
// the browser navigates while the download is in progress.
|
||||
using ItemBrowserMap = std::map<download::DownloadItem*, CefBrowserHostBase*>;
|
||||
ItemBrowserMap item_browser_map_;
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_IMPL_H_
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=c70a949d129e47d660f9fd4200db05e2f5721bed$
|
||||
// $hash=f310399ebf0026717b1d733a34dd51b90623c452$
|
||||
//
|
||||
|
||||
#include "libcef_dll/cpptoc/download_handler_cpptoc.h"
|
||||
|
@ -61,7 +61,7 @@ download_handler_can_download(struct _cef_download_handler_t* self,
|
|||
return _retval;
|
||||
}
|
||||
|
||||
void CEF_CALLBACK
|
||||
int CEF_CALLBACK
|
||||
download_handler_on_before_download(struct _cef_download_handler_t* self,
|
||||
cef_browser_t* browser,
|
||||
struct _cef_download_item_t* download_item,
|
||||
|
@ -73,34 +73,37 @@ download_handler_on_before_download(struct _cef_download_handler_t* self,
|
|||
|
||||
DCHECK(self);
|
||||
if (!self) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
// Verify param: browser; type: refptr_diff
|
||||
DCHECK(browser);
|
||||
if (!browser) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
// Verify param: download_item; type: refptr_diff
|
||||
DCHECK(download_item);
|
||||
if (!download_item) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
// Verify param: suggested_name; type: string_byref_const
|
||||
DCHECK(suggested_name);
|
||||
if (!suggested_name) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback);
|
||||
if (!callback) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Execute
|
||||
CefDownloadHandlerCppToC::Get(self)->OnBeforeDownload(
|
||||
bool _retval = CefDownloadHandlerCppToC::Get(self)->OnBeforeDownload(
|
||||
CefBrowserCToCpp::Wrap(browser),
|
||||
CefDownloadItemCToCpp::Wrap(download_item), CefString(suggested_name),
|
||||
CefBeforeDownloadCallbackCToCpp::Wrap(callback));
|
||||
|
||||
// Return type: bool
|
||||
return _retval;
|
||||
}
|
||||
|
||||
void CEF_CALLBACK
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=690401fe62e7a96ea1c2d72b48144f789207e204$
|
||||
// $hash=6c28836de30002d764d9dcab7f51260cc447f639$
|
||||
//
|
||||
|
||||
#include "libcef_dll/ctocpp/download_handler_ctocpp.h"
|
||||
|
@ -60,7 +60,7 @@ bool CefDownloadHandlerCToCpp::CanDownload(CefRefPtr<CefBrowser> browser,
|
|||
}
|
||||
|
||||
NO_SANITIZE("cfi-icall")
|
||||
void CefDownloadHandlerCToCpp::OnBeforeDownload(
|
||||
bool CefDownloadHandlerCToCpp::OnBeforeDownload(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
|
@ -69,7 +69,7 @@ void CefDownloadHandlerCToCpp::OnBeforeDownload(
|
|||
|
||||
cef_download_handler_t* _struct = GetStruct();
|
||||
if (CEF_MEMBER_MISSING(_struct, on_before_download)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
@ -77,29 +77,32 @@ void CefDownloadHandlerCToCpp::OnBeforeDownload(
|
|||
// Verify param: browser; type: refptr_diff
|
||||
DCHECK(browser.get());
|
||||
if (!browser.get()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Verify param: download_item; type: refptr_diff
|
||||
DCHECK(download_item.get());
|
||||
if (!download_item.get()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Verify param: suggested_name; type: string_byref_const
|
||||
DCHECK(!suggested_name.empty());
|
||||
if (suggested_name.empty()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Execute
|
||||
_struct->on_before_download(_struct, CefBrowserCppToC::Wrap(browser),
|
||||
CefDownloadItemCppToC::Wrap(download_item),
|
||||
suggested_name.GetStruct(),
|
||||
int _retval = _struct->on_before_download(
|
||||
_struct, CefBrowserCppToC::Wrap(browser),
|
||||
CefDownloadItemCppToC::Wrap(download_item), suggested_name.GetStruct(),
|
||||
CefBeforeDownloadCallbackCppToC::Wrap(callback));
|
||||
|
||||
// Return type: bool
|
||||
return _retval ? true : false;
|
||||
}
|
||||
|
||||
NO_SANITIZE("cfi-icall")
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=13fc7d443a6c044598f0683e235f682d91798042$
|
||||
// $hash=fbf27fd04a17a31cb8d279b8a8e1381c7858bc2c$
|
||||
//
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_HANDLER_CTOCPP_H_
|
||||
|
@ -38,7 +38,7 @@ class CefDownloadHandlerCToCpp
|
|||
bool CanDownload(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& url,
|
||||
const CefString& request_method) override;
|
||||
void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
|
||||
bool OnBeforeDownload(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
CefRefPtr<CefBeforeDownloadCallback> callback) override;
|
||||
|
|
|
@ -279,6 +279,12 @@ patches = [
|
|||
# https://chromium-review.googlesource.com/c/chromium/src/+/5006355
|
||||
'name': 'chrome_browser_dialogs_widget',
|
||||
},
|
||||
{
|
||||
# alloy: Support override of DownloadPrefs::FromBrowserContext
|
||||
# chrome: Support custom DownloadManagerDelegate handling.
|
||||
# https://github.com/chromiumembedded/cef/issues/3681
|
||||
'name': 'chrome_browser_download',
|
||||
},
|
||||
{
|
||||
# chrome: Support override of ChromeMimeHandlerViewGuestDelegate.
|
||||
# https://github.com/chromiumembedded/cef/issues/2969
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
diff --git chrome/browser/download/chrome_download_manager_delegate.cc chrome/browser/download/chrome_download_manager_delegate.cc
|
||||
index 447e7d0d5dc6d..7bba632f1331c 100644
|
||||
--- chrome/browser/download/chrome_download_manager_delegate.cc
|
||||
+++ chrome/browser/download/chrome_download_manager_delegate.cc
|
||||
@@ -146,6 +146,10 @@
|
||||
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
|
||||
#endif
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+#include "cef/libcef/browser/download_manager_delegate.h"
|
||||
+#endif
|
||||
+
|
||||
using content::BrowserThread;
|
||||
using content::DownloadManager;
|
||||
using download::DownloadItem;
|
||||
@@ -490,6 +494,11 @@ ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile)
|
||||
download_dialog_bridge_ = std::make_unique<DownloadDialogBridge>();
|
||||
download_message_bridge_ = std::make_unique<DownloadMessageBridge>();
|
||||
#endif
|
||||
+
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ cef_delegate_ =
|
||||
+ cef::DownloadManagerDelegate::Create(profile_->GetDownloadManager());
|
||||
+#endif
|
||||
}
|
||||
|
||||
ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
|
||||
@@ -549,6 +558,9 @@ void ChromeDownloadManagerDelegate::Shutdown() {
|
||||
download_manager_->RemoveObserver(this);
|
||||
download_manager_ = nullptr;
|
||||
}
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ cef_delegate_.reset();
|
||||
+#endif
|
||||
}
|
||||
|
||||
void ChromeDownloadManagerDelegate::OnDownloadCanceledAtShutdown(
|
||||
@@ -617,6 +629,12 @@ bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
ReportPDFLoadStatus(PDFLoadStatus::kTriggeredNoGestureDriveByDownload);
|
||||
}
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef_delegate_->DetermineDownloadTarget(download, callback)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
DownloadTargetDeterminer::CompletionCallback target_determined_callback =
|
||||
base::BindOnce(&ChromeDownloadManagerDelegate::OnDownloadTargetDetermined,
|
||||
weak_ptr_factory_.GetWeakPtr(), download->GetId(),
|
||||
diff --git chrome/browser/download/chrome_download_manager_delegate.h chrome/browser/download/chrome_download_manager_delegate.h
|
||||
index e2cf12d2c8fee..376818e28798c 100644
|
||||
--- chrome/browser/download/chrome_download_manager_delegate.h
|
||||
+++ chrome/browser/download/chrome_download_manager_delegate.h
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/unguessable_token.h"
|
||||
#include "build/build_config.h"
|
||||
+#include "cef/libcef/features/runtime.h"
|
||||
#include "chrome/browser/download/download_completion_blocker.h"
|
||||
#include "chrome/browser/download/download_target_determiner_delegate.h"
|
||||
#include "components/download/public/common/download_danger_type.h"
|
||||
@@ -57,6 +58,12 @@ class CrxInstallError;
|
||||
}
|
||||
#endif
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+namespace cef {
|
||||
+class DownloadManagerDelegate;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
// This is the Chrome side helper for the download system.
|
||||
class ChromeDownloadManagerDelegate
|
||||
: public content::DownloadManagerDelegate,
|
||||
@@ -387,6 +394,10 @@ class ChromeDownloadManagerDelegate
|
||||
// Whether a file picker dialog is showing.
|
||||
bool is_file_picker_showing_;
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ std::unique_ptr<cef::DownloadManagerDelegate> cef_delegate_;
|
||||
+#endif
|
||||
+
|
||||
base::WeakPtrFactory<ChromeDownloadManagerDelegate> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
diff --git chrome/browser/download/download_prefs.cc chrome/browser/download/download_prefs.cc
|
||||
index 773f72da82f90..6d0307988406f 100644
|
||||
--- chrome/browser/download/download_prefs.cc
|
||||
+++ chrome/browser/download/download_prefs.cc
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#include "cef/libcef/features/runtime.h"
|
||||
#include "chrome/browser/download/chrome_download_manager_delegate.h"
|
||||
#include "chrome/browser/download/download_core_service_factory.h"
|
||||
#include "chrome/browser/download/download_core_service_impl.h"
|
||||
@@ -64,6 +65,10 @@
|
||||
#include "chrome/browser/flags/android/chrome_feature_list.h"
|
||||
#endif
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+#include "cef/libcef/browser/alloy/alloy_download_util.h"
|
||||
+#endif
|
||||
+
|
||||
using content::BrowserContext;
|
||||
using content::BrowserThread;
|
||||
using content::DownloadManager;
|
||||
@@ -355,6 +360,11 @@ DownloadPrefs* DownloadPrefs::FromDownloadManager(
|
||||
// static
|
||||
DownloadPrefs* DownloadPrefs::FromBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef::IsAlloyRuntimeEnabled()) {
|
||||
+ return alloy::GetDownloadPrefsFromBrowserContext(context);
|
||||
+ }
|
||||
+#endif
|
||||
return FromDownloadManager(context->GetDownloadManager());
|
||||
}
|
||||
|
|
@ -186,3 +186,18 @@ index 2f769363f8519..228c20926634b 100644
|
|||
// FYI: Do NOT add any more friends here. The functions above are the ONLY
|
||||
// ones that need to call AttachTabHelpers; if you think you do, re-read the
|
||||
// design document linked above, especially the section "Reusing tab helpers".
|
||||
diff --git chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
|
||||
index a76c331ec5344..ffe3cbe7ce37c 100644
|
||||
--- chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
|
||||
+++ chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
|
||||
@@ -850,6 +850,10 @@ void DownloadToolbarButtonView::ShowPendingDownloadStartedAnimation() {
|
||||
if (!gfx::Animation::ShouldRenderRichAnimation()) {
|
||||
return;
|
||||
}
|
||||
+ if (!IsDrawn()) {
|
||||
+ // Don't animate with a hidden download button.
|
||||
+ return;
|
||||
+ }
|
||||
content::WebContents* const web_contents =
|
||||
browser_->tab_strip_model()->GetActiveWebContents();
|
||||
if (!web_contents ||
|
||||
|
|
|
@ -1,38 +1,3 @@
|
|||
diff --git chrome/browser/download/download_prefs.cc chrome/browser/download/download_prefs.cc
|
||||
index 773f72da82f90..6d0307988406f 100644
|
||||
--- chrome/browser/download/download_prefs.cc
|
||||
+++ chrome/browser/download/download_prefs.cc
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#include "cef/libcef/features/runtime.h"
|
||||
#include "chrome/browser/download/chrome_download_manager_delegate.h"
|
||||
#include "chrome/browser/download/download_core_service_factory.h"
|
||||
#include "chrome/browser/download/download_core_service_impl.h"
|
||||
@@ -64,6 +65,10 @@
|
||||
#include "chrome/browser/flags/android/chrome_feature_list.h"
|
||||
#endif
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+#include "cef/libcef/browser/alloy/alloy_download_util.h"
|
||||
+#endif
|
||||
+
|
||||
using content::BrowserContext;
|
||||
using content::BrowserThread;
|
||||
using content::DownloadManager;
|
||||
@@ -355,6 +360,11 @@ DownloadPrefs* DownloadPrefs::FromDownloadManager(
|
||||
// static
|
||||
DownloadPrefs* DownloadPrefs::FromBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef::IsAlloyRuntimeEnabled()) {
|
||||
+ return alloy::GetDownloadPrefsFromBrowserContext(context);
|
||||
+ }
|
||||
+#endif
|
||||
return FromDownloadManager(context->GetDownloadManager());
|
||||
}
|
||||
|
||||
diff --git chrome/browser/printing/print_preview_dialog_controller.cc chrome/browser/printing/print_preview_dialog_controller.cc
|
||||
index 54efe456fd86e..a685c4e0722cc 100644
|
||||
--- chrome/browser/printing/print_preview_dialog_controller.cc
|
||||
|
|
|
@ -858,7 +858,7 @@ bool ClientHandler::CanDownload(CefRefPtr<CefBrowser> browser,
|
|||
return true;
|
||||
}
|
||||
|
||||
void ClientHandler::OnBeforeDownload(
|
||||
bool ClientHandler::OnBeforeDownload(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
|
@ -867,6 +867,7 @@ void ClientHandler::OnBeforeDownload(
|
|||
|
||||
// Continue the download and show the "Save As" dialog.
|
||||
callback->Continue(MainContext::Get()->GetDownloadPath(suggested_name), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientHandler::OnDownloadUpdated(
|
||||
|
|
|
@ -182,7 +182,7 @@ class ClientHandler : public BaseClientHandler,
|
|||
bool CanDownload(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& url,
|
||||
const CefString& request_method) override;
|
||||
void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
|
||||
bool OnBeforeDownload(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
CefRefPtr<CefBeforeDownloadCallback> callback) override;
|
||||
|
|
|
@ -49,7 +49,7 @@ class DownloadSchemeHandler : public CefResourceHandler {
|
|||
content_disposition_ = kTestContentDisposition;
|
||||
should_delay_ = true;
|
||||
} else {
|
||||
EXPECT_TRUE(false); // Not reached.
|
||||
EXPECT_TRUE(IgnoreURL(url)) << url;
|
||||
|
||||
// Cancel immediately.
|
||||
handle_request = true;
|
||||
|
@ -187,6 +187,8 @@ class DownloadTestHandler : public TestHandler {
|
|||
test_mode_ == CLICKED_BLOCKED;
|
||||
}
|
||||
|
||||
bool is_clicked_invalid() const { return test_mode_ == CLICKED_INVALID; }
|
||||
|
||||
bool is_clicked_and_downloaded() const { return test_mode_ == CLICKED; }
|
||||
|
||||
bool is_downloaded() const {
|
||||
|
@ -276,6 +278,14 @@ class DownloadTestHandler : public TestHandler {
|
|||
// ALT key will trigger download of custom protocol links.
|
||||
SendClick(browser,
|
||||
test_mode_ == CLICKED_INVALID ? EVENTFLAG_ALT_DOWN : 0);
|
||||
|
||||
if (IsChromeBootstrap() && is_clicked_invalid()) {
|
||||
// Destroy the test after a bit because there will be no further
|
||||
// callbacks.
|
||||
CefPostDelayedTask(
|
||||
TID_UI, base::BindOnce(&DownloadTestHandler::DestroyTest, this),
|
||||
200);
|
||||
}
|
||||
} else {
|
||||
// Begin the download progammatically.
|
||||
browser->GetHost()->StartDownload(kTestDownloadUrl);
|
||||
|
@ -343,7 +353,7 @@ class DownloadTestHandler : public TestHandler {
|
|||
return test_mode_ != CLICKED_BLOCKED;
|
||||
}
|
||||
|
||||
void OnBeforeDownload(
|
||||
bool OnBeforeDownload(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
|
@ -393,6 +403,8 @@ class DownloadTestHandler : public TestHandler {
|
|||
} else if (test_mode_ == PENDING) {
|
||||
ContinuePendingIfReady();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
|
||||
|
@ -500,7 +512,14 @@ class DownloadTestHandler : public TestHandler {
|
|||
CefRegisterSchemeHandlerFactory("https", kTestDomain, nullptr);
|
||||
}
|
||||
|
||||
if (is_clicked()) {
|
||||
if (is_clicked_invalid()) {
|
||||
if (IsChromeBootstrap()) {
|
||||
// No CanDownload for invalid protocol links.
|
||||
EXPECT_FALSE(got_can_download_);
|
||||
} else {
|
||||
EXPECT_TRUE(got_can_download_);
|
||||
}
|
||||
} else if (is_clicked()) {
|
||||
EXPECT_TRUE(got_can_download_);
|
||||
} else {
|
||||
EXPECT_FALSE(got_can_download_);
|
||||
|
|
|
@ -150,13 +150,6 @@ class TestHandler : public CefClient,
|
|||
CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
|
||||
CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
|
||||
|
||||
// CefDownloadHandler methods
|
||||
void OnBeforeDownload(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDownloadItem> download_item,
|
||||
const CefString& suggested_name,
|
||||
CefRefPtr<CefBeforeDownloadCallback> callback) override {}
|
||||
|
||||
// CefLifeSpanHandler methods
|
||||
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
|
||||
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
|
||||
|
|
Loading…
Reference in New Issue