cef/libcef/browser/extensions/extensions_browser_client.cc

417 lines
13 KiB
C++

// 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 <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 "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);
if (!web_contents) {
return;
}
auto* guest_view =
extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
if (!guest_view) {
return;
}
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);
if (!web_contents) {
return;
}
auto* guest_view =
extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
if (!guest_view) {
return;
}
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() {}
// 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(BrowserContext* context) {
return GetOriginalContext(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);
if (cef_browser_context) {
return cef_browser_context->AsBrowserContext();
}
return nullptr;
}
content::BrowserContext*
CefExtensionsBrowserClient::GetRedirectedContextInIncognito(
content::BrowserContext* context,
bool force_guest_profile,
bool force_system_profile) {
return context;
}
content::BrowserContext*
CefExtensionsBrowserClient::GetContextForRegularAndIncognito(
content::BrowserContext* context,
bool force_guest_profile,
bool force_system_profile) {
return context;
}
content::BrowserContext* CefExtensionsBrowserClient::GetRegularProfile(
content::BrowserContext* context,
bool force_guest_profile,
bool force_system_profile) {
return context;
}
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;
}
std::unique_ptr<ExtensionHostDelegate>
CefExtensionsBrowserClient::CreateExtensionHostDelegate() {
// CEF does not use the ExtensionHost constructor that calls this method.
NOTREACHED();
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;
}
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.
NOTREACHED();
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.
NOTREACHED();
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() {
if (!kiosk_delegate_) {
kiosk_delegate_.reset(new CefKioskDelegate());
}
return kiosk_delegate_.get();
}
bool CefExtensionsBrowserClient::IsLockScreenContext(
content::BrowserContext* context) {
return false;
}
std::string CefExtensionsBrowserClient::GetApplicationLocale() {
return g_browser_process->GetApplicationLocale();
}
} // namespace extensions