mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-16 20:20:51 +01:00
Add NetworkService support for extensions and downloads (see issue #2622).
To test: - All tests pass with NetworkService disabled. DownloadTest.*, ExtensionTest.* and PluginTest.* tests pass with NetworkService enabled. - The PDF extension displays a file, and the download and print buttons work.
This commit is contained in:
parent
0193a3fe54
commit
5ce52bd775
@ -18,6 +18,7 @@
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/devtools/devtools_manager_delegate.h"
|
||||
#include "libcef/browser/extensions/extension_system.h"
|
||||
#include "libcef/browser/extensions/extension_web_contents_observer.h"
|
||||
#include "libcef/browser/media_capture_devices_dispatcher.h"
|
||||
#include "libcef/browser/net/chrome_scheme_handler.h"
|
||||
#include "libcef/browser/net/net_util.h"
|
||||
@ -58,11 +59,13 @@
|
||||
#include "chrome/browser/chrome_service.h"
|
||||
#include "chrome/browser/net/system_network_context_manager.h"
|
||||
#include "chrome/browser/plugins/plugin_info_host_impl.h"
|
||||
#include "chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "chrome/common/constants.mojom.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "chrome/grit/browser_resources.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "chrome/services/printing/public/mojom/constants.mojom.h"
|
||||
@ -88,6 +91,7 @@
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/resource_dispatcher_host.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "content/public/browser/web_ui_url_loader_factory.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/service_names.mojom.h"
|
||||
#include "content/public/common/storage_quota_params.h"
|
||||
@ -1116,6 +1120,26 @@ CefContentBrowserClient::CreateThrottlesForNavigation(
|
||||
return throttles;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<content::URLLoaderThrottle>>
|
||||
CefContentBrowserClient::CreateURLLoaderThrottles(
|
||||
const network::ResourceRequest& request,
|
||||
content::ResourceContext* resource_context,
|
||||
const base::RepeatingCallback<content::WebContents*()>& wc_getter,
|
||||
content::NavigationUIData* navigation_ui_data,
|
||||
int frame_tree_node_id) {
|
||||
CEF_REQUIRE_IOT();
|
||||
std::vector<std::unique_ptr<content::URLLoaderThrottle>> result;
|
||||
|
||||
if (net_service::IsEnabled()) {
|
||||
// Used to substitute View ID for PDF contents when using the PDF plugin.
|
||||
result.push_back(
|
||||
std::make_unique<PluginResponseInterceptorURLLoaderThrottle>(
|
||||
resource_context, request.resource_type, frame_tree_node_id));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
void CefContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
|
||||
const base::CommandLine& command_line,
|
||||
@ -1195,6 +1219,43 @@ void CefContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
||||
render_frame_id);
|
||||
if (factory)
|
||||
factories->emplace(extensions::kExtensionScheme, std::move(factory));
|
||||
|
||||
content::RenderFrameHost* frame_host =
|
||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||
content::WebContents* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(frame_host);
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
extensions::CefExtensionWebContentsObserver* web_observer =
|
||||
extensions::CefExtensionWebContentsObserver::FromWebContents(
|
||||
web_contents);
|
||||
|
||||
// There is nothing to do if no CefExtensionWebContentsObserver is attached
|
||||
// to the |web_contents|.
|
||||
if (!web_observer)
|
||||
return;
|
||||
|
||||
const extensions::Extension* extension =
|
||||
web_observer->GetExtensionFromFrame(frame_host, false);
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
std::vector<std::string> allowed_webui_hosts;
|
||||
// Support for chrome:// scheme if appropriate.
|
||||
if ((extension->is_extension() || extension->is_platform_app()) &&
|
||||
extensions::Manifest::IsComponentLocation(extension->location())) {
|
||||
// Components of chrome that are implemented as extensions or platform apps
|
||||
// are allowed to use chrome://resources/ and chrome://theme/ URLs.
|
||||
allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
|
||||
allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost);
|
||||
}
|
||||
if (!allowed_webui_hosts.empty()) {
|
||||
factories->emplace(
|
||||
content::kChromeUIScheme,
|
||||
content::CreateWebUIURLLoader(frame_host, content::kChromeUIScheme,
|
||||
std::move(allowed_webui_hosts)));
|
||||
}
|
||||
}
|
||||
|
||||
bool CefContentBrowserClient::WillCreateURLLoaderFactory(
|
||||
|
@ -124,6 +124,13 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
|
||||
std::vector<std::unique_ptr<content::NavigationThrottle>>
|
||||
CreateThrottlesForNavigation(
|
||||
content::NavigationHandle* navigation_handle) override;
|
||||
std::vector<std::unique_ptr<content::URLLoaderThrottle>>
|
||||
CreateURLLoaderThrottles(
|
||||
const network::ResourceRequest& request,
|
||||
content::ResourceContext* resource_context,
|
||||
const base::RepeatingCallback<content::WebContents*()>& wc_getter,
|
||||
content::NavigationUIData* navigation_ui_data,
|
||||
int frame_tree_node_id) override;
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
void GetAdditionalMappedFilesForChildProcess(
|
||||
|
@ -317,13 +317,9 @@ void CefDownloadManagerDelegate::OnDownloadDestroyed(DownloadItem* item) {
|
||||
|
||||
void CefDownloadManagerDelegate::OnDownloadCreated(DownloadManager* manager,
|
||||
DownloadItem* item) {
|
||||
CefBrowserHostImpl* browser = nullptr;
|
||||
content::WebContents* contents =
|
||||
content::DownloadItemUtils::GetWebContents(item);
|
||||
if (contents) {
|
||||
browser = CefBrowserHostImpl::GetBrowserForContents(contents).get();
|
||||
DCHECK(browser);
|
||||
}
|
||||
// When NetworkService is enabled this callback may arrive after
|
||||
// DetermineDownloadTarget, so we allow association from either method.
|
||||
CefRefPtr<CefBrowserHostImpl> 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::
|
||||
@ -336,17 +332,7 @@ void CefDownloadManagerDelegate::OnDownloadCreated(DownloadManager* manager,
|
||||
LOG(INFO) << "Rejected download of " << url_chain.back().spec();
|
||||
}
|
||||
item->Cancel(true);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void CefDownloadManagerDelegate::ManagerGoingDown(DownloadManager* manager) {
|
||||
@ -368,7 +354,9 @@ bool CefDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
return true;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserHostImpl> browser = GetBrowser(item);
|
||||
// When NetworkService is enabled this callback may arrive before
|
||||
// OnDownloadCreated, so we allow association from either method.
|
||||
CefRefPtr<CefBrowserHostImpl> browser = GetOrAssociateBrowser(item);
|
||||
CefRefPtr<CefDownloadHandler> handler;
|
||||
if (browser.get())
|
||||
handler = GetDownloadHandler(browser);
|
||||
@ -412,6 +400,34 @@ void CefDownloadManagerDelegate::OnBrowserDestroyed(
|
||||
}
|
||||
}
|
||||
|
||||
CefBrowserHostImpl* CefDownloadManagerDelegate::GetOrAssociateBrowser(
|
||||
download::DownloadItem* item) {
|
||||
ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
|
||||
if (it != item_browser_map_.end())
|
||||
return it->second;
|
||||
|
||||
CefBrowserHostImpl* browser = nullptr;
|
||||
content::WebContents* contents =
|
||||
content::DownloadItemUtils::GetWebContents(item);
|
||||
if (contents) {
|
||||
browser = CefBrowserHostImpl::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;
|
||||
}
|
||||
|
||||
CefBrowserHostImpl* CefDownloadManagerDelegate::GetBrowser(DownloadItem* item) {
|
||||
ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
|
||||
if (it != item_browser_map_.end())
|
||||
|
@ -43,6 +43,7 @@ class CefDownloadManagerDelegate : public download::DownloadItem::Observer,
|
||||
// CefBrowserHostImpl::Observer methods.
|
||||
void OnBrowserDestroyed(CefBrowserHostImpl* browser) override;
|
||||
|
||||
CefBrowserHostImpl* GetOrAssociateBrowser(download::DownloadItem* item);
|
||||
CefBrowserHostImpl* GetBrowser(download::DownloadItem* item);
|
||||
|
||||
content::DownloadManager* manager_;
|
||||
|
@ -191,6 +191,7 @@ void CefExtensionSystem::Init() {
|
||||
// 3. A page requests a resource with the "application/pdf" mime type. For
|
||||
// example, by loading a PDF file.
|
||||
// 4. CefResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream
|
||||
// or PluginResponseInterceptorURLLoaderThrottle (NetworkService)
|
||||
// intercepts the PDF resource load in the browser process, generates a
|
||||
// unique View ID that is associated with the resource request for later
|
||||
// retrieval via MimeHandlerStreamManager and the
|
||||
@ -212,8 +213,10 @@ void CefExtensionSystem::Init() {
|
||||
// 8. Access to PDF extension resources is checked by
|
||||
// CefExtensionsBrowserClient::AllowCrossRendererResourceLoad.
|
||||
// 9. PDF extension resources are provided from bundle via
|
||||
// CefExtensionsBrowserClient::MaybeCreateResourceBundleRequestJob and
|
||||
// CefComponentExtensionResourceManager.
|
||||
// CefExtensionsBrowserClient::MaybeCreateResourceBundleRequestJob or
|
||||
// CefExtensionsBrowserClient::LoadResourceFromResourceBundle,
|
||||
// CefContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories
|
||||
// (NetworkService) and CefComponentExtensionResourceManager.
|
||||
// 10.The PDF extension (chrome/browser/resources/pdf/browser_api.js) calls
|
||||
// chrome.mimeHandlerPrivate.getStreamInfo to retrieve the PDF resource
|
||||
// stream. This API is implemented using Mojo as described in
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "libcef/browser/extensions/extension_web_contents_observer.h"
|
||||
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
@ -40,11 +41,13 @@ void CefExtensionWebContentsObserver::RenderFrameCreated(
|
||||
auto policy = content::ChildProcessSecurityPolicy::GetInstance();
|
||||
|
||||
// Components of chrome that are implemented as extensions or platform apps
|
||||
// are allowed to use chrome://resources/ URLs.
|
||||
// are allowed to use chrome://resources/ and chrome://theme/ URLs.
|
||||
if ((extension->is_extension() || extension->is_platform_app()) &&
|
||||
Manifest::IsComponentLocation(extension->location())) {
|
||||
policy->GrantRequestOrigin(
|
||||
process_id, url::Origin::Create(GURL(content::kChromeUIResourcesURL)));
|
||||
policy->GrantRequestOrigin(
|
||||
process_id, url::Origin::Create(GURL(chrome::kChromeUIThemeURL)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,20 +122,22 @@ CefExtensionsBrowserClient::MaybeCreateResourceBundleRequestJob(
|
||||
base::FilePath CefExtensionsBrowserClient::GetBundleResourcePath(
|
||||
const network::ResourceRequest& request,
|
||||
const base::FilePath& extension_resources_path,
|
||||
ComponentExtensionResourceInfo* resource_id) const {
|
||||
*resource_id = {0};
|
||||
return base::FilePath();
|
||||
ComponentExtensionResourceInfo* resource_info) const {
|
||||
return chrome_url_request_util::GetBundleResourcePath(
|
||||
request, extension_resources_path, resource_info);
|
||||
}
|
||||
|
||||
void CefExtensionsBrowserClient::LoadResourceFromResourceBundle(
|
||||
const network::ResourceRequest& request,
|
||||
network::mojom::URLLoaderRequest loader,
|
||||
const base::FilePath& resource_relative_path,
|
||||
const ComponentExtensionResourceInfo& resource_id,
|
||||
const ComponentExtensionResourceInfo& resource_info,
|
||||
const std::string& content_security_policy,
|
||||
network::mojom::URLLoaderClientPtr client,
|
||||
bool send_cors_header) {
|
||||
NOTREACHED() << "Load resources from bundles not supported.";
|
||||
chrome_url_request_util::LoadResourceFromResourceBundle(
|
||||
request, std::move(loader), resource_relative_path, resource_info,
|
||||
content_security_policy, std::move(client), send_cors_header);
|
||||
}
|
||||
|
||||
bool CefExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
||||
@ -147,13 +149,6 @@ bool CefExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
||||
const Extension* extension,
|
||||
const ExtensionSet& extensions,
|
||||
const ProcessMap& process_map) {
|
||||
// TODO(cef): This bypasses additional checks added to
|
||||
// AllowCrossRendererResourceLoad() in https://crrev.com/5cf9d45c. Figure out
|
||||
// why permission is not being granted based on "web_accessible_resources"
|
||||
// specified in the PDF extension manifest.json file.
|
||||
if (extension && extension->id() == extension_misc::kPdfExtensionId)
|
||||
return true;
|
||||
|
||||
bool allowed = false;
|
||||
if (url_request_util::AllowCrossRendererResourceLoad(
|
||||
url, resource_type, page_transition, child_id, is_incognito,
|
||||
|
@ -52,12 +52,12 @@ class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
|
||||
base::FilePath GetBundleResourcePath(
|
||||
const network::ResourceRequest& request,
|
||||
const base::FilePath& extension_resources_path,
|
||||
ComponentExtensionResourceInfo* resource_id) const override;
|
||||
ComponentExtensionResourceInfo* resource_info) const override;
|
||||
void LoadResourceFromResourceBundle(
|
||||
const network::ResourceRequest& request,
|
||||
network::mojom::URLLoaderRequest loader,
|
||||
const base::FilePath& resource_relative_path,
|
||||
const ComponentExtensionResourceInfo& resource_id,
|
||||
const ComponentExtensionResourceInfo& resource_info,
|
||||
const std::string& content_security_policy,
|
||||
network::mojom::URLLoaderClientPtr client,
|
||||
bool send_cors_header) override;
|
||||
|
@ -888,8 +888,9 @@ std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
|
||||
}
|
||||
|
||||
// Flag subresource loads of custom schemes.
|
||||
const bool is_external = !is_navigation && !scheme::IsInternalHandledScheme(
|
||||
request_initiator.scheme());
|
||||
const bool is_external =
|
||||
!is_navigation && !is_download && !request_initiator.scheme().empty() &&
|
||||
!scheme::IsInternalHandledScheme(request_initiator.scheme());
|
||||
|
||||
wrapper->Initialize(browser_context, browserPtr, framePtr, render_process_id,
|
||||
render_frame_id, frame_tree_node_id, is_navigation,
|
||||
|
@ -124,6 +124,63 @@ index e699f1feb070..f5fcc878c246 100644
|
||||
|
||||
// If we broke out of the loop, we have found an enabled plugin.
|
||||
bool enabled = i < matching_plugins.size();
|
||||
diff --git chrome/browser/plugins/plugin_utils.cc chrome/browser/plugins/plugin_utils.cc
|
||||
index 68e7057b7cf6..102caf10e68c 100644
|
||||
--- chrome/browser/plugins/plugin_utils.cc
|
||||
+++ chrome/browser/plugins/plugin_utils.cc
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "chrome/browser/plugins/plugin_utils.h"
|
||||
|
||||
#include "base/values.h"
|
||||
+#include "cef/libcef/features/features.h"
|
||||
#include "chrome/browser/profiles/profile_io_data.h"
|
||||
#include "chrome/common/plugin_utils.h"
|
||||
#include "components/content_settings/core/browser/host_content_settings_map.h"
|
||||
@@ -14,6 +15,11 @@
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+#include "cef/libcef/browser/resource_context.h"
|
||||
+#include "cef/libcef/common/extensions/extensions_util.h"
|
||||
+#endif
|
||||
+
|
||||
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
#include "extensions/browser/info_map.h"
|
||||
#include "extensions/common/constants.h"
|
||||
@@ -158,10 +164,23 @@ PluginUtils::GetMimeTypeToExtensionIdMap(
|
||||
content::ResourceContext* resource_context) {
|
||||
base::flat_map<std::string, std::string> mime_type_to_extension_id_map;
|
||||
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
+
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ CefResourceContext* context =
|
||||
+ static_cast<CefResourceContext*>(resource_context);
|
||||
+ bool profile_is_off_the_record = context->IsOffTheRecord();
|
||||
+ const scoped_refptr<const extensions::InfoMap> extension_info_map(
|
||||
+ context->GetExtensionInfoMap());
|
||||
+ bool always_open_pdf_externally = !extensions::PdfExtensionEnabled();
|
||||
+#else
|
||||
ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
|
||||
bool profile_is_off_the_record = io_data->IsOffTheRecord();
|
||||
const scoped_refptr<const extensions::InfoMap> extension_info_map(
|
||||
io_data->GetExtensionInfoMap());
|
||||
+ bool always_open_pdf_externally =
|
||||
+ io_data->always_open_pdf_externally()->GetValue();
|
||||
+#endif
|
||||
+
|
||||
std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist();
|
||||
// Go through the white-listed extensions and try to use them to intercept
|
||||
// the URL request.
|
||||
@@ -176,7 +195,7 @@ PluginUtils::GetMimeTypeToExtensionIdMap(
|
||||
}
|
||||
|
||||
if (extension_id == extension_misc::kPdfExtensionId &&
|
||||
- io_data->always_open_pdf_externally()->GetValue()) {
|
||||
+ always_open_pdf_externally) {
|
||||
continue;
|
||||
}
|
||||
|
||||
diff --git chrome/renderer/chrome_content_renderer_client.cc chrome/renderer/chrome_content_renderer_client.cc
|
||||
index a838fabbdfcb..93ccc1cbdb35 100644
|
||||
--- chrome/renderer/chrome_content_renderer_client.cc
|
||||
|
Loading…
x
Reference in New Issue
Block a user