blob: 9883630d54a7ee0ea04af5b0fc7cbc1a3dc4dafa [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/shell/browser/shell_content_browser_client.h"
#include <stddef.h>
#include <utility>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "components/embedder_support/user_agent_utils.h"
#include "components/guest_view/common/guest_view.mojom.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_throttle_registry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/service_worker_version_base_info.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_descriptors.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_devtools_manager_delegate.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_navigation_throttle.h"
#include "extensions/browser/extension_navigation_ui_data.h"
#include "extensions/browser/extension_protocols.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_web_contents_observer.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/guest_view/extensions_guest_view.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "extensions/browser/process_map.h"
#include "extensions/browser/renderer_startup_helper.h"
#include "extensions/browser/url_loader_factory_manager.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/sandboxed_page_info.h"
#include "extensions/common/mojom/event_router.mojom.h"
#include "extensions/common/mojom/guest_view.mojom.h"
#include "extensions/common/mojom/renderer_host.mojom.h"
#include "extensions/common/switches.h"
#include "extensions/shell/browser/shell_browser_context.h"
#include "extensions/shell/browser/shell_browser_main_parts.h"
#include "extensions/shell/browser/shell_extension_system.h"
#include "extensions/shell/browser/shell_navigation_ui_data.h"
#include "extensions/shell/browser/shell_speech_recognition_manager_delegate.h"
#include "extensions/shell/common/version.h" // Generated file.
#include "net/base/isolation_info.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "url/gurl.h"
using base::CommandLine;
using content::BrowserContext;
namespace extensions {
namespace {
ShellContentBrowserClient* g_instance = nullptr;
} // namespace
ShellContentBrowserClient::ShellContentBrowserClient(
ShellBrowserMainDelegate* browser_main_delegate)
: browser_main_parts_(nullptr),
browser_main_delegate_(browser_main_delegate) {
DCHECK(!g_instance);
g_instance = this;
}
ShellContentBrowserClient::~ShellContentBrowserClient() {
g_instance = nullptr;
}
// static
ShellContentBrowserClient* ShellContentBrowserClient::Get() {
return g_instance;
}
content::BrowserContext* ShellContentBrowserClient::GetBrowserContext() {
return browser_main_parts_->browser_context();
}
std::unique_ptr<content::BrowserMainParts>
ShellContentBrowserClient::CreateBrowserMainParts(bool is_integration_test) {
auto browser_main_parts =
CreateShellBrowserMainParts(browser_main_delegate_, is_integration_test);
browser_main_parts_ = browser_main_parts.get();
return browser_main_parts;
}
bool ShellContentBrowserClient::ShouldUseProcessPerSite(
content::BrowserContext* browser_context,
const GURL& site_url) {
// This ensures that all render views created for a single app will use the
// same render process (see content::SiteInstance::GetOrCreateProcess).
// Otherwise the default behavior of ContentBrowserClient will lead to
// separate render processes for the background page and each app window view.
return true;
}
bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
if (!url.is_valid())
return false;
// Keep in sync with ProtocolHandlers added in
// ShellBrowserContext::CreateRequestContext() and in
// content::ShellURLRequestContextGetter::GetURLRequestContext().
static const char* const kProtocolList[] = {
url::kBlobScheme,
content::kChromeDevToolsScheme,
content::kChromeUIScheme,
url::kDataScheme,
url::kFileScheme,
url::kFileSystemScheme,
kExtensionScheme,
};
for (const char* scheme : kProtocolList) {
if (url.SchemeIs(scheme))
return true;
}
return false;
}
void ShellContentBrowserClient::SiteInstanceGotProcessAndSite(
content::SiteInstance* site_instance) {
// If this isn't an extension renderer there's nothing to do.
const Extension* extension = GetExtension(site_instance);
if (!extension)
return;
if (site_instance->IsSandboxed()) {
return;
}
ProcessMap::Get(browser_main_parts_->browser_context())
->Insert(extension->id(), site_instance->GetProcess()->GetDeprecatedID());
}
void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int child_process_id) {
std::string process_type =
command_line->GetSwitchValueASCII(::switches::kProcessType);
if (process_type == ::switches::kRendererProcess)
AppendRendererSwitches(command_line);
}
content::SpeechRecognitionManagerDelegate*
ShellContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
return new speech::ShellSpeechRecognitionManagerDelegate();
}
void ShellContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_allowed_schemes) {
ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
additional_allowed_schemes);
additional_allowed_schemes->push_back(kExtensionScheme);
}
std::unique_ptr<content::DevToolsManagerDelegate>
ShellContentBrowserClient::CreateDevToolsManagerDelegate() {
return std::make_unique<content::ShellDevToolsManagerDelegate>(
GetBrowserContext());
}
void ShellContentBrowserClient::ExposeInterfacesToRenderer(
service_manager::BinderRegistry* registry,
blink::AssociatedInterfaceRegistry* associated_registry,
content::RenderProcessHost* render_process_host) {
associated_registry->AddInterface<mojom::RendererHost>(
base::BindRepeating(&RendererStartupHelper::BindForRenderer,
render_process_host->GetDeprecatedID()));
}
void ShellContentBrowserClient::
RegisterAssociatedInterfaceBindersForRenderFrameHost(
content::RenderFrameHost& render_frame_host,
blink::AssociatedInterfaceRegistry& associated_registry) {
int render_process_id = render_frame_host.GetProcess()->GetDeprecatedID();
associated_registry.AddInterface<mojom::EventRouter>(
base::BindRepeating(&EventRouter::BindForRenderer, render_process_id));
associated_registry.AddInterface<mojom::RendererHost>(base::BindRepeating(
&RendererStartupHelper::BindForRenderer, render_process_id));
associated_registry.AddInterface<extensions::mojom::LocalFrameHost>(
base::BindRepeating(
[](content::RenderFrameHost* render_frame_host,
mojo::PendingAssociatedReceiver<extensions::mojom::LocalFrameHost>
receiver) {
ExtensionWebContentsObserver::BindLocalFrameHost(
std::move(receiver), render_frame_host);
},
&render_frame_host));
associated_registry.AddInterface<guest_view::mojom::GuestViewHost>(
base::BindRepeating(&ExtensionsGuestView::CreateForComponents,
render_frame_host.GetGlobalId()));
associated_registry.AddInterface<mojom::GuestView>(
base::BindRepeating(&ExtensionsGuestView::CreateForExtensions,
render_frame_host.GetGlobalId()));
}
void ShellContentBrowserClient::CreateThrottlesForNavigation(
content::NavigationThrottleRegistry& registry) {
content::NavigationHandle& navigation_handle =
registry.GetNavigationHandle();
if (!extensions::ExtensionsBrowserClient::Get()
->AreExtensionsDisabledForContext(
navigation_handle.GetWebContents()->GetBrowserContext())) {
registry.AddThrottle(
std::make_unique<ExtensionNavigationThrottle>(registry));
}
WebViewGuest::MaybeCreateAndAddNavigationThrottle(registry);
}
std::unique_ptr<content::NavigationUIData>
ShellContentBrowserClient::GetNavigationUIData(
content::NavigationHandle* navigation_handle) {
return std::make_unique<ShellNavigationUIData>(navigation_handle);
}
mojo::PendingRemote<network::mojom::URLLoaderFactory>
ShellContentBrowserClient::CreateNonNetworkNavigationURLLoaderFactory(
const std::string& scheme,
content::FrameTreeNodeId frame_tree_node_id) {
if (scheme == extensions::kExtensionScheme) {
content::WebContents* web_contents =
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
return extensions::CreateExtensionNavigationURLLoaderFactory(
web_contents->GetBrowserContext(),
!!extensions::WebViewGuest::FromFrameTreeNodeId(frame_tree_node_id));
}
return {};
}
void ShellContentBrowserClient::
RegisterNonNetworkWorkerMainResourceURLLoaderFactories(
content::BrowserContext* browser_context,
NonNetworkURLLoaderFactoryMap* factories) {
DCHECK(browser_context);
DCHECK(factories);
factories->emplace(
extensions::kExtensionScheme,
extensions::CreateExtensionWorkerMainResourceURLLoaderFactory(
browser_context));
}
void ShellContentBrowserClient::
RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories(
content::BrowserContext* browser_context,
NonNetworkURLLoaderFactoryMap* factories) {
DCHECK(browser_context);
DCHECK(factories);
factories->emplace(
extensions::kExtensionScheme,
extensions::CreateExtensionServiceWorkerScriptURLLoaderFactory(
browser_context));
}
void ShellContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
int render_process_id,
int render_frame_id,
const std::optional<url::Origin>& request_initiator_origin,
NonNetworkURLLoaderFactoryMap* factories) {
DCHECK(factories);
factories->emplace(extensions::kExtensionScheme,
extensions::CreateExtensionURLLoaderFactory(
render_process_id, render_frame_id));
}
void ShellContentBrowserClient::WillCreateURLLoaderFactory(
content::BrowserContext* browser_context,
content::RenderFrameHost* frame,
int render_process_id,
URLLoaderFactoryType type,
const url::Origin& request_initiator,
const net::IsolationInfo& isolation_info,
std::optional<int64_t> navigation_id,
ukm::SourceIdObj ukm_source_id,
network::URLLoaderFactoryBuilder& factory_builder,
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
header_client,
bool* bypass_redirect_checks,
bool* disable_secure_dns,
network::mojom::URLLoaderFactoryOverridePtr* factory_override,
scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) {
auto* web_request_api =
extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
browser_context);
bool use_proxy = web_request_api->MaybeProxyURLLoaderFactory(
browser_context, frame, render_process_id, type, std::move(navigation_id),
ukm_source_id, factory_builder, header_client,
std::move(navigation_response_task_runner));
if (bypass_redirect_checks)
*bypass_redirect_checks = use_proxy;
}
bool ShellContentBrowserClient::HandleExternalProtocol(
const GURL& url,
content::WebContents::Getter web_contents_getter,
content::FrameTreeNodeId frame_tree_node_id,
content::NavigationUIData* navigation_data,
bool is_primary_main_frame,
bool is_in_fenced_frame_tree,
network::mojom::WebSandboxFlags sandbox_flags,
ui::PageTransition page_transition,
bool has_user_gesture,
const std::optional<url::Origin>& initiating_origin,
content::RenderFrameHost* initiator_document,
const net::IsolationInfo& isolation_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
return false;
}
void ShellContentBrowserClient::OverrideURLLoaderFactoryParams(
content::BrowserContext* browser_context,
const url::Origin& origin,
bool is_for_isolated_world,
bool is_for_service_worker,
network::mojom::URLLoaderFactoryParams* factory_params) {
URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
browser_context, origin, is_for_isolated_world, is_for_service_worker,
factory_params);
}
base::FilePath
ShellContentBrowserClient::GetSandboxedStorageServiceDataDirectory() {
return GetBrowserContext()->GetPath();
}
std::string ShellContentBrowserClient::GetUserAgent() {
// Must contain a user agent string for version sniffing. For example,
// pluginless WebRTC Hangouts checks the Chrome version number.
return embedder_support::GetUserAgent();
}
std::unique_ptr<ShellBrowserMainParts>
ShellContentBrowserClient::CreateShellBrowserMainParts(
ShellBrowserMainDelegate* browser_main_delegate,
bool is_integration_test) {
return std::make_unique<ShellBrowserMainParts>(browser_main_delegate,
is_integration_test);
}
void ShellContentBrowserClient::AppendRendererSwitches(
base::CommandLine* command_line) {
static const char* const kSwitchNames[] = {
switches::kAllowlistedExtensionID,
// TODO(jamescook): Should we check here if the process is in the
// extension service process map, or can we assume all renderers are
// extension renderers?
switches::kExtensionProcess,
};
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
kSwitchNames);
}
const Extension* ShellContentBrowserClient::GetExtension(
content::SiteInstance* site_instance) {
ExtensionRegistry* registry =
ExtensionRegistry::Get(site_instance->GetBrowserContext());
return registry->enabled_extensions().GetExtensionOrAppByURL(
site_instance->GetSiteURL());
}
} // namespace extensions