cef/libcef/browser/extensions/extensions_browser_client.cc

434 lines
14 KiB
C++
Raw Normal View History

// Copyright 2015 The Chromium Embedded Framework Authors.
// Portions copyright 2014 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/extensions/extensions_browser_client.h"
#include <memory>
#include <utility>
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/browser_context.h"
#include "libcef/browser/extensions/component_extension_resource_manager.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/extensions/extension_system_factory.h"
#include "libcef/browser/extensions/extension_web_contents_observer.h"
#include "libcef/browser/extensions/extensions_api_client.h"
#include "libcef/browser/extensions/extensions_browser_api_provider.h"
#include "libcef/browser/request_context_impl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/chrome_url_request_util.h"
#include "chrome/browser/extensions/event_router_forwarder.h"
#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "extensions/browser/api/core_extensions_browser_api_provider.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
#include "extensions/browser/api/runtime/runtime_api_delegate.h"
#include "extensions/browser/app_sorting.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host_delegate.h"
#include "extensions/browser/extensions_browser_interface_binders.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/browser/kiosk/kiosk_delegate.h"
#include "extensions/browser/url_request_util.h"
#include "extensions/common/api/mime_handler.mojom.h"
#include "extensions/common/constants.h"
using content::BrowserContext;
using content::BrowserThread;
namespace extensions {
namespace {
void BindMimeHandlerService(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<extensions::mime_handler::MimeHandlerService>
receiver) {
auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
2023-01-02 23:59:03 +01:00
if (!web_contents) {
return;
2023-01-02 23:59:03 +01:00
}
auto* guest_view =
extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
2023-01-02 23:59:03 +01:00
if (!guest_view) {
return;
2023-01-02 23:59:03 +01:00
}
extensions::MimeHandlerServiceImpl::Create(guest_view->GetStreamWeakPtr(),
std::move(receiver));
}
void BindBeforeUnloadControl(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<extensions::mime_handler::BeforeUnloadControl>
receiver) {
auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
2023-01-02 23:59:03 +01:00
if (!web_contents) {
return;
2023-01-02 23:59:03 +01:00
}
auto* guest_view =
extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
2023-01-02 23:59:03 +01:00
if (!guest_view) {
return;
2023-01-02 23:59:03 +01:00
}
guest_view->FuseBeforeUnloadControl(std::move(receiver));
}
// Dummy KiosDelegate that always returns false
class CefKioskDelegate : public extensions::KioskDelegate {
public:
CefKioskDelegate() = default;
~CefKioskDelegate() override = default;
// KioskDelegate overrides:
bool IsAutoLaunchedKioskApp(const ExtensionId& id) const override {
return false;
}
};
} // namespace
CefExtensionsBrowserClient::CefExtensionsBrowserClient()
: api_client_(new CefExtensionsAPIClient) {
AddAPIProvider(std::make_unique<CoreExtensionsBrowserAPIProvider>());
AddAPIProvider(std::make_unique<CefExtensionsBrowserAPIProvider>());
}
CefExtensionsBrowserClient::~CefExtensionsBrowserClient() = default;
// static
CefExtensionsBrowserClient* CefExtensionsBrowserClient::Get() {
return static_cast<CefExtensionsBrowserClient*>(
ExtensionsBrowserClient::Get());
}
bool CefExtensionsBrowserClient::IsShuttingDown() {
return false;
}
bool CefExtensionsBrowserClient::AreExtensionsDisabled(
const base::CommandLine& command_line,
BrowserContext* context) {
return false;
}
bool CefExtensionsBrowserClient::IsValidContext(void* context) {
return GetOriginalContext(static_cast<BrowserContext*>(context)) != nullptr;
}
bool CefExtensionsBrowserClient::IsSameContext(BrowserContext* first,
BrowserContext* second) {
// Returns true if |first| and |second| share the same underlying
// CefBrowserContext.
return GetOriginalContext(first) == GetOriginalContext(second);
}
bool CefExtensionsBrowserClient::HasOffTheRecordContext(
BrowserContext* context) {
// CEF doesn't use incognito contexts.
return false;
}
BrowserContext* CefExtensionsBrowserClient::GetOffTheRecordContext(
BrowserContext* context) {
return nullptr;
}
BrowserContext* CefExtensionsBrowserClient::GetOriginalContext(
BrowserContext* context) {
auto cef_browser_context = CefBrowserContext::FromBrowserContext(context);
2023-01-02 23:59:03 +01:00
if (cef_browser_context) {
return cef_browser_context->AsBrowserContext();
2023-01-02 23:59:03 +01:00
}
return nullptr;
}
content::BrowserContext*
CefExtensionsBrowserClient::GetContextRedirectedToOriginal(
content::BrowserContext* context,
bool force_guest_profile) {
return context;
}
content::BrowserContext* CefExtensionsBrowserClient::GetContextOwnInstance(
content::BrowserContext* context,
bool force_guest_profile) {
return context;
}
content::BrowserContext* CefExtensionsBrowserClient::GetContextForOriginalOnly(
content::BrowserContext* context,
bool force_guest_profile) {
return context;
}
bool CefExtensionsBrowserClient::AreExtensionsDisabledForContext(
content::BrowserContext* context) {
return false;
}
bool CefExtensionsBrowserClient::IsGuestSession(BrowserContext* context) const {
return false;
}
bool CefExtensionsBrowserClient::IsExtensionIncognitoEnabled(
const std::string& extension_id,
content::BrowserContext* context) const {
return false;
}
bool CefExtensionsBrowserClient::CanExtensionCrossIncognito(
const Extension* extension,
content::BrowserContext* context) const {
return false;
}
base::FilePath CefExtensionsBrowserClient::GetBundleResourcePath(
const network::ResourceRequest& request,
const base::FilePath& extension_resources_path,
int* resource_id) const {
return chrome_url_request_util::GetBundleResourcePath(
request, extension_resources_path, resource_id);
}
void CefExtensionsBrowserClient::LoadResourceFromResourceBundle(
const network::ResourceRequest& request,
mojo::PendingReceiver<network::mojom::URLLoader> loader,
const base::FilePath& resource_relative_path,
const int resource_id,
scoped_refptr<net::HttpResponseHeaders> headers,
mojo::PendingRemote<network::mojom::URLLoaderClient> client) {
chrome_url_request_util::LoadResourceFromResourceBundle(
request, std::move(loader), resource_relative_path, resource_id,
std::move(headers), std::move(client));
}
bool CefExtensionsBrowserClient::AllowCrossRendererResourceLoad(
const network::ResourceRequest& request,
network::mojom::RequestDestination destination,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
const Extension* extension,
const ExtensionSet& extensions,
const ProcessMap& process_map) {
bool allowed = false;
if (url_request_util::AllowCrossRendererResourceLoad(
request, destination, page_transition, child_id, is_incognito,
extension, extensions, process_map, &allowed)) {
return allowed;
}
// Couldn't determine if resource is allowed. Block the load.
return false;
}
PrefService* CefExtensionsBrowserClient::GetPrefServiceForContext(
BrowserContext* context) {
return CefBrowserContext::FromBrowserContext(context)
->AsProfile()
->GetPrefs();
}
void CefExtensionsBrowserClient::GetEarlyExtensionPrefsObservers(
content::BrowserContext* context,
std::vector<EarlyExtensionPrefsObserver*>* observers) const {}
ProcessManagerDelegate* CefExtensionsBrowserClient::GetProcessManagerDelegate()
const {
return nullptr;
}
mojo::PendingRemote<network::mojom::URLLoaderFactory>
CefExtensionsBrowserClient::GetControlledFrameEmbedderURLLoader(
int frame_tree_node_id,
content::BrowserContext* browser_context) {
return mojo::PendingRemote<network::mojom::URLLoaderFactory>();
}
std::unique_ptr<ExtensionHostDelegate>
CefExtensionsBrowserClient::CreateExtensionHostDelegate() {
// CEF does not use the ExtensionHost constructor that calls this method.
DCHECK(false);
return std::unique_ptr<ExtensionHostDelegate>();
}
bool CefExtensionsBrowserClient::CreateBackgroundExtensionHost(
const Extension* extension,
content::BrowserContext* browser_context,
const GURL& url,
ExtensionHost** host) {
auto cef_browser_context =
CefBrowserContext::FromBrowserContext(browser_context);
// A CEF representation should always exist.
CefRefPtr<CefExtension> cef_extension =
cef_browser_context->GetExtension(extension->id());
DCHECK(cef_extension);
if (!cef_extension) {
// Cancel the background host creation.
return true;
}
// Always use the same request context that the extension was registered with.
// GetLoaderContext() will return NULL for internal extensions.
CefRefPtr<CefRequestContext> request_context =
cef_extension->GetLoaderContext();
if (!request_context) {
// Cancel the background host creation.
return true;
}
Add chrome runtime support for more callbacks and ceftests (see issue #2969) This change adds support for: - Protocol and request handling. - Loading and navigation events. - Display and focus events. - Mouse/keyboard events. - Popup browsers. - Callbacks in the renderer process. - Misc. functionality required for ceftests. This change also adds a new CefBrowserProcessHandler::GetCookieableSchemes callback for configuring global state that will be applied to all CefCookieManagers by default. This global callback is currently required by the chrome runtime because the primary ProfileImpl is created via ChromeBrowserMainParts::PreMainMessageLoopRun (CreatePrimaryProfile) before OnContextCreated can be called. ProfileImpl will use the "C:\Users\[user]\AppData\Local\CEF\User Data\Default" directory by default (on Windows). Cookies may persist in this directory when running ceftests and may need to be manually deleted if those tests fail. Remaining work includes: - Support for client-created request contexts. - Embedding the browser in a Views hierarchy (cefclient support). - TryCloseBrowser and DoClose support. - Most of the CefSettings configuration. - DevTools protocol and window control (ShowDevTools, ExecuteDevToolsMethod). - CEF-specific WebUI pages (about, license, webui-hosts). - Context menu customization (CefContextMenuHandler). - Auto resize (SetAutoResizeEnabled). - Zoom settings (SetZoomLevel). - File dialog runner (RunFileDialog). - File and JS dialog handlers (CefDialogHandler, CefJSDialogHandler). - Extension loading (LoadExtension, etc). - Plugin loading (OnBeforePluginLoad). - Widevine loading (CefRegisterWidevineCdm). - PDF and print preview does not display. - Crash reporting is untested. - Mac: Web content loads but does not display. The following ceftests are now passing when run with the "--enable-chrome-runtime" command-line flag: CorsTest.* DisplayTest.*:-DisplayTest.AutoResize DOMTest.* DraggableRegionsTest.* ImageTest.* MessageRouterTest.* NavigationTest.* ParserTest.* RequestContextTest.*Global* RequestTest.* ResourceManagerTest.* ResourceRequestHandlerTest.* ResponseTest.* SchemeHandlerTest.* ServerTest.* StreamResourceHandlerTest.* StreamTest.* StringTest.* TaskTest.* TestServerTest.* ThreadTest.* URLRequestTest.*Global* V8Test.*:-V8Test.OnUncaughtExceptionDevTools ValuesTest.* WaitableEventTest.* XmlReaderTest.* ZipReaderTest.*
2020-09-25 03:40:47 +02:00
CefBrowserCreateParams create_params;
create_params.url = url.spec();
create_params.request_context = request_context;
CefRefPtr<CefExtensionHandler> handler = cef_extension->GetHandler();
if (handler.get() && handler->OnBeforeBackgroundBrowser(
cef_extension, create_params.url,
create_params.client, create_params.settings)) {
// Cancel the background host creation.
return true;
}
// This triggers creation of the background host.
create_params.extension = extension;
create_params.extension_host_type = mojom::ViewType::kExtensionBackgroundPage;
// Browser creation may fail under certain rare circumstances. Fail the
// background host creation in that case.
CefRefPtr<AlloyBrowserHostImpl> browser =
AlloyBrowserHostImpl::Create(create_params);
if (browser) {
*host = browser->GetExtensionHost();
DCHECK(*host);
}
return true;
}
bool CefExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) {
// TODO(jamescook): We might want to tell extensions when app_shell updates.
return false;
}
void CefExtensionsBrowserClient::PermitExternalProtocolHandler() {}
bool CefExtensionsBrowserClient::IsInDemoMode() {
return false;
}
bool CefExtensionsBrowserClient::IsScreensaverInDemoMode(
const std::string& app_id) {
return false;
}
bool CefExtensionsBrowserClient::IsRunningInForcedAppMode() {
return false;
}
bool CefExtensionsBrowserClient::IsAppModeForcedForApp(
const ExtensionId& extension_id) {
return false;
}
bool CefExtensionsBrowserClient::IsLoggedInAsPublicAccount() {
return false;
}
ExtensionSystemProvider*
CefExtensionsBrowserClient::GetExtensionSystemFactory() {
return CefExtensionSystemFactory::GetInstance();
}
void CefExtensionsBrowserClient::RegisterBrowserInterfaceBindersForFrame(
mojo::BinderMapWithContext<content::RenderFrameHost*>* map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) const {
PopulateExtensionFrameBinders(map, render_frame_host, extension);
map->Add<extensions::mime_handler::MimeHandlerService>(
base::BindRepeating(&BindMimeHandlerService));
map->Add<extensions::mime_handler::BeforeUnloadControl>(
base::BindRepeating(&BindBeforeUnloadControl));
}
std::unique_ptr<RuntimeAPIDelegate>
CefExtensionsBrowserClient::CreateRuntimeAPIDelegate(
content::BrowserContext* context) const {
// TODO(extensions): Implement to support Apps.
DCHECK(false);
return nullptr;
}
const ComponentExtensionResourceManager*
CefExtensionsBrowserClient::GetComponentExtensionResourceManager() {
if (!resource_manager_) {
resource_manager_ =
std::make_unique<CefComponentExtensionResourceManager>();
}
return resource_manager_.get();
}
void CefExtensionsBrowserClient::BroadcastEventToRenderers(
events::HistogramValue histogram_value,
const std::string& event_name,
base::Value::List args,
bool dispatch_to_off_the_record_profiles) {
g_browser_process->extension_event_router_forwarder()
->BroadcastEventToRenderers(histogram_value, event_name, std::move(args),
GURL(), dispatch_to_off_the_record_profiles);
}
ExtensionCache* CefExtensionsBrowserClient::GetExtensionCache() {
// Only used by Chrome via ExtensionService.
DCHECK(false);
return nullptr;
}
bool CefExtensionsBrowserClient::IsBackgroundUpdateAllowed() {
return true;
}
bool CefExtensionsBrowserClient::IsMinBrowserVersionSupported(
const std::string& min_version) {
return true;
}
ExtensionWebContentsObserver*
CefExtensionsBrowserClient::GetExtensionWebContentsObserver(
content::WebContents* web_contents) {
return CefExtensionWebContentsObserver::FromWebContents(web_contents);
}
KioskDelegate* CefExtensionsBrowserClient::GetKioskDelegate() {
2023-01-02 23:59:03 +01:00
if (!kiosk_delegate_) {
kiosk_delegate_ = std::make_unique<CefKioskDelegate>();
2023-01-02 23:59:03 +01:00
}
return kiosk_delegate_.get();
}
bool CefExtensionsBrowserClient::IsLockScreenContext(
content::BrowserContext* context) {
return false;
}
std::string CefExtensionsBrowserClient::GetApplicationLocale() {
return g_browser_process->GetApplicationLocale();
}
media_device_salt::MediaDeviceSaltService*
CefExtensionsBrowserClient::GetMediaDeviceSaltService(
content::BrowserContext* context) {
return MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
context);
}
} // namespace extensions