diff options
author | Inna Palant <ipalant@google.com> | 2023-12-12 19:56:22 -0800 |
---|---|---|
committer | Inna Palant <ipalant@google.com> | 2023-12-12 19:56:22 -0800 |
commit | 1ee1f36e3b492d7a6a0bf2367fe509365853aeaa (patch) | |
tree | a5790e155ff0d998639beb6172dfa0feb294aac9 /libcef/browser/alloy/alloy_content_browser_client.cc | |
parent | 1e76199e6f0ded437fca14eb9e512e0c6bd0fc1e (diff) | |
parent | c33b736614ef77e4048cee551999a656a5ef465f (diff) | |
download | cef-1ee1f36e3b492d7a6a0bf2367fe509365853aeaa.tar.gz |
Merge remote-tracking branch 'origin/upstream'main
Import b/312293934
Diffstat (limited to 'libcef/browser/alloy/alloy_content_browser_client.cc')
-rw-r--r-- | libcef/browser/alloy/alloy_content_browser_client.cc | 1419 |
1 files changed, 1419 insertions, 0 deletions
diff --git a/libcef/browser/alloy/alloy_content_browser_client.cc b/libcef/browser/alloy/alloy_content_browser_client.cc new file mode 100644 index 00000000..55711ca3 --- /dev/null +++ b/libcef/browser/alloy/alloy_content_browser_client.cc @@ -0,0 +1,1419 @@ +// 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_content_browser_client.h" + +#include <algorithm> +#include <tuple> +#include <utility> + +#include "include/cef_version.h" +#include "libcef/browser/alloy/alloy_browser_context.h" +#include "libcef/browser/alloy/alloy_browser_host_impl.h" +#include "libcef/browser/alloy/alloy_browser_main.h" +#include "libcef/browser/alloy/alloy_web_contents_view_delegate.h" +#include "libcef/browser/browser_context.h" +#include "libcef/browser/browser_frame.h" +#include "libcef/browser/browser_info.h" +#include "libcef/browser/browser_info_manager.h" +#include "libcef/browser/browser_manager.h" +#include "libcef/browser/browser_platform_delegate.h" +#include "libcef/browser/certificate_query.h" +#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/throttle_handler.h" +#include "libcef/browser/net_service/cookie_manager_impl.h" +#include "libcef/browser/net_service/login_delegate.h" +#include "libcef/browser/net_service/proxy_url_loader_factory.h" +#include "libcef/browser/net_service/resource_request_handler_wrapper.h" +#include "libcef/browser/prefs/renderer_prefs.h" +#include "libcef/browser/speech_recognition_manager_delegate.h" +#include "libcef/browser/thread_util.h" +#include "libcef/browser/x509_certificate_impl.h" +#include "libcef/common/alloy/alloy_content_client.h" +#include "libcef/common/app_manager.h" +#include "libcef/common/cef_switches.h" +#include "libcef/common/command_line_impl.h" +#include "libcef/common/extensions/extensions_util.h" +#include "libcef/common/frame_util.h" +#include "libcef/common/net/scheme_registration.h" +#include "libcef/common/request_impl.h" + +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/json/json_reader.h" +#include "base/path_service.h" +#include "base/stl_util.h" +#include "base/threading/thread_restrictions.h" +#include "cef/grit/cef_resources.h" +#include "chrome/browser/accessibility/live_caption_unavailability_notifier.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/content_settings/cookie_settings_factory.h" +#include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h" +#include "chrome/browser/net/profile_network_context_service.h" +#include "chrome/browser/net/profile_network_context_service_factory.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/browser/pdf/chrome_pdf_stream_delegate.h" +#include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h" +#include "chrome/browser/plugins/plugin_info_host_impl.h" +#include "chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h" +#include "chrome/browser/plugins/plugin_utils.h" +#include "chrome/browser/predictors/network_hints_handler_impl.h" +#include "chrome/browser/printing/print_view_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/renderer_updater.h" +#include "chrome/browser/profiles/renderer_updater_factory.h" +#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" +#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" +#include "chrome/browser/ui/chrome_select_file_policy.h" +#include "chrome/common/chrome_content_client.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/google_url_loader_throttle.h" +#include "chrome/common/pdf_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/browser_resources.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/services/printing/printing_service.h" +#include "components/content_settings/core/browser/cookie_settings.h" +#include "components/embedder_support/switches.h" +#include "components/embedder_support/user_agent_utils.h" +#include "components/pdf/browser/pdf_navigation_throttle.h" +#include "components/pdf/browser/pdf_url_loader_request_interceptor.h" +#include "components/pdf/browser/pdf_web_contents_helper.h" +#include "components/pdf/common/internal_plugin_helpers.h" +#include "components/spellcheck/common/spellcheck.mojom.h" +#include "components/version_info/version_info.h" +#include "content/browser/plugin_service_impl.h" +#include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/client_certificate_delegate.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/overlay_window.h" +#include "content/public/browser/page_navigator.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/browser/render_widget_host_view.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/url_constants.h" +#include "content/public/common/user_agent.h" +#include "crypto/crypto_buildflags.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_message_filter.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/info_map.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/switches.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" +#include "net/base/auth.h" +#include "net/ssl/ssl_cert_request_info.h" +#include "net/ssl/ssl_private_key.h" +#include "pdf/pdf_features.h" +#include "ppapi/host/ppapi_host.h" +#include "sandbox/policy/switches.h" +#include "services/network/public/cpp/network_switches.h" +#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h" +#include "services/service_manager/public/mojom/connector.mojom.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" +#include "third_party/blink/public/common/web_preferences/web_preferences.h" +#include "third_party/blink/public/mojom/badging/badging.mojom.h" +#include "third_party/blink/public/mojom/prerender/prerender.mojom.h" +#include "third_party/blink/public/web/web_window_features.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_switches.h" +#include "url/gurl.h" + +#if BUILDFLAG(IS_MAC) +#include "net/ssl/client_cert_store_mac.h" +#include "services/video_capture/public/mojom/constants.mojom.h" +#elif BUILDFLAG(IS_POSIX) +#include "components/crash/core/app/crash_switches.h" +#include "components/crash/core/app/crashpad.h" +#include "content/public/common/content_descriptors.h" +#include "libcef/common/crash_reporting.h" +#endif + +#if BUILDFLAG(IS_WIN) +#include "net/ssl/client_cert_store_win.h" +#include "sandbox/win/src/sandbox_policy.h" +#endif + +#if BUILDFLAG(USE_NSS_CERTS) +#include "net/ssl/client_cert_store_nss.h" +#endif + +#if BUILDFLAG(HAS_SPELLCHECK_PANEL) +#include "chrome/browser/spellchecker/spell_check_panel_host_impl.h" +#endif + +namespace { + +class CefSelectClientCertificateCallbackImpl + : public CefSelectClientCertificateCallback { + public: + explicit CefSelectClientCertificateCallbackImpl( + std::unique_ptr<content::ClientCertificateDelegate> delegate) + : delegate_(std::move(delegate)) {} + + CefSelectClientCertificateCallbackImpl( + const CefSelectClientCertificateCallbackImpl&) = delete; + CefSelectClientCertificateCallbackImpl& operator=( + const CefSelectClientCertificateCallbackImpl&) = delete; + + ~CefSelectClientCertificateCallbackImpl() { + // If Select has not been called, call it with NULL to continue without any + // client certificate. + if (delegate_) { + DoSelect(nullptr); + } + } + + void Select(CefRefPtr<CefX509Certificate> cert) override { + if (delegate_) { + DoSelect(cert); + } + } + + private: + void DoSelect(CefRefPtr<CefX509Certificate> cert) { + if (CEF_CURRENTLY_ON_UIT()) { + RunNow(std::move(delegate_), cert); + } else { + CEF_POST_TASK( + CEF_UIT, + base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunNow, + std::move(delegate_), cert)); + } + } + + static void RunNow( + std::unique_ptr<content::ClientCertificateDelegate> delegate, + CefRefPtr<CefX509Certificate> cert) { + CEF_REQUIRE_UIT(); + + if (cert) { + CefX509CertificateImpl* certImpl = + static_cast<CefX509CertificateImpl*>(cert.get()); + certImpl->AcquirePrivateKey(base::BindOnce( + &CefSelectClientCertificateCallbackImpl::RunWithPrivateKey, + std::move(delegate), cert)); + return; + } + + delegate->ContinueWithCertificate(nullptr, nullptr); + } + + static void RunWithPrivateKey( + std::unique_ptr<content::ClientCertificateDelegate> delegate, + CefRefPtr<CefX509Certificate> cert, + scoped_refptr<net::SSLPrivateKey> key) { + CEF_REQUIRE_UIT(); + DCHECK(cert); + + if (key) { + CefX509CertificateImpl* certImpl = + static_cast<CefX509CertificateImpl*>(cert.get()); + delegate->ContinueWithCertificate(certImpl->GetInternalCertObject(), key); + } else { + delegate->ContinueWithCertificate(nullptr, nullptr); + } + } + + std::unique_ptr<content::ClientCertificateDelegate> delegate_; + + IMPLEMENT_REFCOUNTING(CefSelectClientCertificateCallbackImpl); +}; + +#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) +int GetCrashSignalFD() { + if (!crash_reporting::Enabled()) { + return -1; + } + + int fd; + pid_t pid; + return crash_reporter::GetHandlerSocket(&fd, &pid) ? fd : -1; +} +#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) + +// From chrome/browser/plugins/chrome_content_browser_client_plugins_part.cc. +void BindPluginInfoHost( + int render_process_id, + mojo::PendingAssociatedReceiver<chrome::mojom::PluginInfoHost> receiver) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::RenderProcessHost* host = + content::RenderProcessHost::FromID(render_process_id); + if (!host) { + return; + } + + Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); + mojo::MakeSelfOwnedAssociatedReceiver( + std::make_unique<PluginInfoHostImpl>(render_process_id, profile), + std::move(receiver)); +} + +void BindBadgeService( + content::RenderFrameHost* frame_host, + mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {} + +void BindBadgeServiceForServiceWorker( + const content::ServiceWorkerVersionBaseInfo& info, + mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {} + +void BindMediaFoundationRendererNotifierHandler( + content::RenderFrameHost* frame_host, + mojo::PendingReceiver<media::mojom::MediaFoundationRendererNotifier> + receiver) {} + +void BindNetworkHintsHandler( + content::RenderFrameHost* frame_host, + mojo::PendingReceiver<network_hints::mojom::NetworkHintsHandler> receiver) { + predictors::NetworkHintsHandlerImpl::Create(frame_host, std::move(receiver)); +} + +base::FilePath GetRootCachePath() { + // The CefContext::ValidateCachePath method enforces the requirement that all + // cache_path values be either equal to or a child of root_cache_path. + return base::FilePath( + CefString(&CefContext::Get()->settings().root_cache_path)); +} + +const extensions::Extension* GetEnabledExtensionFromSiteURL( + content::BrowserContext* context, + const GURL& site_url) { + if (!site_url.SchemeIs(extensions::kExtensionScheme)) { + return nullptr; + } + + auto registry = extensions::ExtensionRegistry::Get(context); + if (!registry) { + return nullptr; + } + + return registry->enabled_extensions().GetByID(site_url.host()); +} + +} // namespace + +AlloyContentBrowserClient::AlloyContentBrowserClient() = default; + +AlloyContentBrowserClient::~AlloyContentBrowserClient() = default; + +std::unique_ptr<content::BrowserMainParts> +AlloyContentBrowserClient::CreateBrowserMainParts( + bool /* is_integration_test */) { + auto browser_main_parts = std::make_unique<AlloyBrowserMainParts>(); + browser_main_parts_ = browser_main_parts.get(); + return browser_main_parts; +} + +void AlloyContentBrowserClient::RenderProcessWillLaunch( + content::RenderProcessHost* host) { + const int id = host->GetID(); + Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); + + if (extensions::ExtensionsEnabled()) { + host->AddFilter(new extensions::ExtensionMessageFilter(id, profile)); + } + + // If the renderer process crashes then the host may already have + // CefBrowserInfoManager as an observer. Try to remove it first before adding + // to avoid DCHECKs. + host->RemoveObserver(CefBrowserInfoManager::GetInstance()); + host->AddObserver(CefBrowserInfoManager::GetInstance()); + + // Forwards dynamic parameters to CefRenderThreadObserver. + Profile* original_profile = profile->GetOriginalProfile(); + RendererUpdaterFactory::GetForProfile(original_profile) + ->InitializeRenderer(host); +} + +bool AlloyContentBrowserClient::ShouldUseProcessPerSite( + content::BrowserContext* browser_context, + const GURL& site_url) { + if (extensions::ExtensionsEnabled()) { + if (auto profile = Profile::FromBrowserContext(browser_context)) { + return extensions::ChromeContentBrowserClientExtensionsPart:: + ShouldUseProcessPerSite(profile, site_url); + } + } + + return content::ContentBrowserClient::ShouldUseProcessPerSite(browser_context, + site_url); +} + +bool AlloyContentBrowserClient::ShouldUseSpareRenderProcessHost( + content::BrowserContext* browser_context, + const GURL& site_url) { + if (extensions::ExtensionsEnabled()) { + if (auto profile = Profile::FromBrowserContext(browser_context)) { + return extensions::ChromeContentBrowserClientExtensionsPart:: + ShouldUseSpareRenderProcessHost(profile, site_url); + } + } + + return content::ContentBrowserClient::ShouldUseSpareRenderProcessHost( + browser_context, site_url); +} + +bool AlloyContentBrowserClient::DoesSiteRequireDedicatedProcess( + content::BrowserContext* browser_context, + const GURL& effective_site_url) { + if (extensions::ExtensionsEnabled()) { + return extensions::ChromeContentBrowserClientExtensionsPart:: + DoesSiteRequireDedicatedProcess(browser_context, effective_site_url); + } + + return content::ContentBrowserClient::DoesSiteRequireDedicatedProcess( + browser_context, effective_site_url); +} + +bool AlloyContentBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel( + base::StringPiece scheme, + bool is_embedded_origin_secure) { + // This is needed to bypass the normal SameSite rules for any chrome:// page + // embedding a secure origin, regardless of the registrable domains of any + // intervening frames. For example, this is needed for browser UI to interact + // with SameSite cookies on accounts.google.com, which are used for logging + // into Cloud Print from chrome://print, for displaying a list of available + // accounts on the NTP (chrome://new-tab-page), etc. + if (is_embedded_origin_secure && scheme == content::kChromeUIScheme) { + return true; + } + + if (extensions::ExtensionsEnabled()) { + return scheme == extensions::kExtensionScheme; + } + + return false; +} + +bool AlloyContentBrowserClient:: + ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel( + base::StringPiece scheme, + bool is_embedded_origin_secure) { + return is_embedded_origin_secure && scheme == content::kChromeUIScheme; +} + +void AlloyContentBrowserClient::OverrideURLLoaderFactoryParams( + content::BrowserContext* browser_context, + const url::Origin& origin, + bool is_for_isolated_world, + network::mojom::URLLoaderFactoryParams* factory_params) { + if (extensions::ExtensionsEnabled()) { + extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams( + browser_context, origin, is_for_isolated_world, factory_params); + } +} + +void AlloyContentBrowserClient::GetAdditionalWebUISchemes( + std::vector<std::string>* additional_schemes) { + // Any schemes listed here are treated as WebUI schemes but do not get WebUI + // bindings. Also, view-source is allowed for these schemes. WebUI schemes + // will not be passed to HandleExternalProtocol. +} + +void AlloyContentBrowserClient::GetAdditionalViewSourceSchemes( + std::vector<std::string>* additional_schemes) { + GetAdditionalWebUISchemes(additional_schemes); + + additional_schemes->push_back(extensions::kExtensionScheme); +} + +std::unique_ptr<ui::SelectFilePolicy> +AlloyContentBrowserClient::CreateSelectFilePolicy( + content::WebContents* web_contents) { + return std::make_unique<ChromeSelectFilePolicy>(web_contents); +} + +void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( + std::vector<std::string>* additional_allowed_schemes) { + ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( + additional_allowed_schemes); + additional_allowed_schemes->push_back(content::kChromeDevToolsScheme); + additional_allowed_schemes->push_back(content::kChromeUIScheme); + additional_allowed_schemes->push_back(content::kChromeUIUntrustedScheme); +} + +bool AlloyContentBrowserClient::IsWebUIAllowedToMakeNetworkRequests( + const url::Origin& origin) { + return scheme::IsWebUIAllowedToMakeNetworkRequests(origin); +} + +bool AlloyContentBrowserClient::IsHandledURL(const GURL& url) { + if (!url.is_valid()) { + return false; + } + const std::string& scheme = url.scheme(); + DCHECK_EQ(scheme, base::ToLowerASCII(scheme)); + + if (scheme::IsInternalHandledScheme(scheme)) { + return true; + } + + return CefAppManager::Get()->HasCustomScheme(scheme); +} + +void AlloyContentBrowserClient::SiteInstanceGotProcess( + content::SiteInstance* site_instance) { + if (!extensions::ExtensionsEnabled()) { + return; + } + + CHECK(site_instance->HasProcess()); + + auto context = site_instance->GetBrowserContext(); + + // Only add the process to the map if the SiteInstance's site URL is already + // a chrome-extension:// URL. This includes hosted apps, except in rare cases + // that a URL in the hosted app's extent is not treated as a hosted app (e.g., + // for isolated origins or cross-site iframes). For that case, don't look up + // the hosted app's Extension from the site URL using GetExtensionOrAppByURL, + // since it isn't treated as a hosted app. + const auto extension = + GetEnabledExtensionFromSiteURL(context, site_instance->GetSiteURL()); + if (!extension) { + return; + } + + extensions::ProcessMap::Get(context)->Insert( + extension->id(), site_instance->GetProcess()->GetID(), + site_instance->GetId()); +} + +void AlloyContentBrowserClient::SiteInstanceDeleting( + content::SiteInstance* site_instance) { + if (!extensions::ExtensionsEnabled()) { + return; + } + + if (!site_instance->HasProcess()) { + return; + } + + auto context = site_instance->GetBrowserContext(); + auto registry = extensions::ExtensionRegistry::Get(context); + if (!registry) { + return; + } + + auto extension = registry->enabled_extensions().GetExtensionOrAppByURL( + site_instance->GetSiteURL()); + if (!extension) { + return; + } + + extensions::ProcessMap::Get(context)->Remove( + extension->id(), site_instance->GetProcess()->GetID(), + site_instance->GetId()); +} + +void AlloyContentBrowserClient::BindHostReceiverForRenderer( + content::RenderProcessHost* render_process_host, + mojo::GenericPendingReceiver receiver) { + if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) { + SpellCheckHostChromeImpl::Create(render_process_host->GetID(), + std::move(host_receiver)); + return; + } + +#if BUILDFLAG(HAS_SPELLCHECK_PANEL) + if (auto panel_host_receiver = + receiver.As<spellcheck::mojom::SpellCheckPanelHost>()) { + SpellCheckPanelHostImpl::Create(render_process_host->GetID(), + std::move(panel_host_receiver)); + return; + } +#endif // BUILDFLAG(HAS_SPELLCHECK_PANEL) +} + +void AlloyContentBrowserClient::AppendExtraCommandLineSwitches( + base::CommandLine* command_line, + int child_process_id) { + const base::CommandLine* browser_cmd = base::CommandLine::ForCurrentProcess(); + + { + // Propagate the following switches to all command lines (along with any + // associated values) if present in the browser command line. + static const char* const kSwitchNames[] = { + switches::kDisablePackLoading, +#if BUILDFLAG(IS_MAC) + switches::kFrameworkDirPath, + switches::kMainBundlePath, +#endif + switches::kLocalesDirPath, + switches::kLogSeverity, + switches::kResourcesDirPath, + embedder_support::kUserAgent, + switches::kUserAgentProductAndVersion, + }; + command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, + std::size(kSwitchNames)); + } + + const std::string& process_type = + command_line->GetSwitchValueASCII(switches::kProcessType); + if (process_type == switches::kRendererProcess) { + // Propagate the following switches to the renderer command line (along with + // any associated values) if present in the browser command line. + static const char* const kSwitchNames[] = { + switches::kDisableExtensions, + switches::kDisablePdfExtension, + switches::kDisablePrintPreview, + switches::kDisableScrollBounce, + switches::kDisableSpellChecking, + switches::kEnableSpeechInput, + switches::kUncaughtExceptionStackSize, + network::switches::kUnsafelyTreatInsecureOriginAsSecure, + }; + command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, + std::size(kSwitchNames)); + + if (extensions::ExtensionsEnabled()) { + content::RenderProcessHost* process = + content::RenderProcessHost::FromID(child_process_id); + auto browser_context = process->GetBrowserContext(); + CefBrowserContext* cef_browser_context = + process ? CefBrowserContext::FromBrowserContext(browser_context) + : nullptr; + if (cef_browser_context) { + if (cef_browser_context->IsPrintPreviewSupported()) { + command_line->AppendSwitch(switches::kEnablePrintPreview); + } + + // Based on ChromeContentBrowserClientExtensionsPart:: + // AppendExtraRendererCommandLineSwitches + if (extensions::ProcessMap::Get(browser_context) + ->Contains(process->GetID())) { + command_line->AppendSwitch(extensions::switches::kExtensionProcess); + } + } + } + } else { + // Propagate the following switches to non-renderer command line (along with + // any associated values) if present in the browser command line. + static const char* const kSwitchNames[] = { + switches::kLang, + }; + command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, + std::size(kSwitchNames)); + } + + // Necessary to populate DIR_USER_DATA in sub-processes. + // See resource_util.cc GetUserDataPath. + base::FilePath user_data_dir; + if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) { + command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir); + } + +#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) + if (process_type == switches::kZygoteProcess) { + if (browser_cmd->HasSwitch(switches::kBrowserSubprocessPath)) { + // Force use of the sub-process executable path for the zygote process. + const base::FilePath& subprocess_path = + browser_cmd->GetSwitchValuePath(switches::kBrowserSubprocessPath); + if (!subprocess_path.empty()) { + command_line->SetProgram(subprocess_path); + } + } + + // Propagate the following switches to the zygote command line (along with + // any associated values) if present in the browser command line. + static const char* const kSwitchNames[] = { + switches::kLogFile, + }; + command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, + std::size(kSwitchNames)); + } + + if (crash_reporting::Enabled()) { + int fd; + pid_t pid; + if (crash_reporter::GetHandlerSocket(&fd, &pid)) { + command_line->AppendSwitchASCII( + crash_reporter::switches::kCrashpadHandlerPid, + base::NumberToString(pid)); + } + } +#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) + + CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication(); + if (app.get()) { + CefRefPtr<CefBrowserProcessHandler> handler = + app->GetBrowserProcessHandler(); + if (handler.get()) { + CefRefPtr<CefCommandLineImpl> commandLinePtr( + new CefCommandLineImpl(command_line, false, false)); + handler->OnBeforeChildProcessLaunch(commandLinePtr.get()); + std::ignore = commandLinePtr->Detach(nullptr); + } + } +} + +std::string AlloyContentBrowserClient::GetApplicationLocale() { + return g_browser_process->GetApplicationLocale(); +} + +scoped_refptr<network::SharedURLLoaderFactory> +AlloyContentBrowserClient::GetSystemSharedURLLoaderFactory() { + DCHECK( + content::BrowserThread::CurrentlyOn(content::BrowserThread::UI) || + !content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI)); + + if (!SystemNetworkContextManager::GetInstance()) { + return nullptr; + } + + return SystemNetworkContextManager::GetInstance() + ->GetSharedURLLoaderFactory(); +} + +network::mojom::NetworkContext* +AlloyContentBrowserClient::GetSystemNetworkContext() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(SystemNetworkContextManager::GetInstance()); + return SystemNetworkContextManager::GetInstance()->GetContext(); +} + +content::MediaObserver* AlloyContentBrowserClient::GetMediaObserver() { + return CefMediaCaptureDevicesDispatcher::GetInstance(); +} + +content::SpeechRecognitionManagerDelegate* +AlloyContentBrowserClient::CreateSpeechRecognitionManagerDelegate() { + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kEnableSpeechInput)) { + return new CefSpeechRecognitionManagerDelegate(); + } + + return nullptr; +} + +content::GeneratedCodeCacheSettings +AlloyContentBrowserClient::GetGeneratedCodeCacheSettings( + content::BrowserContext* context) { + // If we pass 0 for size, disk_cache will pick a default size using the + // heuristics based on available disk size. These are implemented in + // disk_cache::PreferredCacheSize in net/disk_cache/cache_util.cc. + const base::FilePath& cache_path = context->GetPath(); + return content::GeneratedCodeCacheSettings(!cache_path.empty() /* enabled */, + 0 /* size */, cache_path); +} + +void AlloyContentBrowserClient::AllowCertificateError( + content::WebContents* web_contents, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + bool is_main_frame_request, + bool strict_enforcement, + base::OnceCallback<void(content::CertificateRequestResultType)> callback) { + auto returned_callback = certificate_query::AllowCertificateError( + web_contents, cert_error, ssl_info, request_url, is_main_frame_request, + strict_enforcement, std::move(callback), /*default_disallow=*/true); + // Callback should not be returned. + DCHECK(returned_callback.is_null()); +} + +base::OnceClosure AlloyContentBrowserClient::SelectClientCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + net::ClientCertIdentityList client_certs, + std::unique_ptr<content::ClientCertificateDelegate> delegate) { + CEF_REQUIRE_UIT(); + + CefRefPtr<CefRequestHandler> handler; + CefRefPtr<AlloyBrowserHostImpl> browser = + AlloyBrowserHostImpl::GetBrowserForContents(web_contents); + if (browser.get()) { + CefRefPtr<CefClient> client = browser->GetClient(); + if (client.get()) { + handler = client->GetRequestHandler(); + } + } + + if (!handler.get()) { + delegate->ContinueWithCertificate(nullptr, nullptr); + return base::OnceClosure(); + } + + CefRequestHandler::X509CertificateList certs; + for (net::ClientCertIdentityList::iterator iter = client_certs.begin(); + iter != client_certs.end(); iter++) { + certs.push_back(new CefX509CertificateImpl(std::move(*iter))); + } + + CefRefPtr<CefSelectClientCertificateCallbackImpl> callbackImpl( + new CefSelectClientCertificateCallbackImpl(std::move(delegate))); + + bool proceed = handler->OnSelectClientCertificate( + browser.get(), cert_request_info->is_proxy, + cert_request_info->host_and_port.host(), + cert_request_info->host_and_port.port(), certs, callbackImpl.get()); + + if (!proceed && !certs.empty()) { + callbackImpl->Select(certs[0]); + } + return base::OnceClosure(); +} + +bool AlloyContentBrowserClient::CanCreateWindow( + content::RenderFrameHost* opener, + const GURL& opener_url, + const GURL& opener_top_level_frame_url, + const url::Origin& source_origin, + content::mojom::WindowContainerType container_type, + const GURL& target_url, + const content::Referrer& referrer, + const std::string& frame_name, + WindowOpenDisposition disposition, + const blink::mojom::WindowFeatures& features, + bool user_gesture, + bool opener_suppressed, + bool* no_javascript_access) { + CEF_REQUIRE_UIT(); + *no_javascript_access = false; + + return CefBrowserInfoManager::GetInstance()->CanCreateWindow( + opener, target_url, referrer, frame_name, disposition, features, + user_gesture, opener_suppressed, no_javascript_access); +} + +void AlloyContentBrowserClient::OverrideWebkitPrefs( + content::WebContents* web_contents, + blink::web_pref::WebPreferences* prefs) { + auto rvh = web_contents->GetRenderViewHost(); + + // Using RVH instead of RFH here because rvh->GetMainFrame() may be nullptr + // when this method is called. + SkColor base_background_color; + renderer_prefs::PopulateWebPreferences(rvh, *prefs, base_background_color); + + web_contents->SetPageBaseBackgroundColor(base_background_color); +} + +bool AlloyContentBrowserClient::OverrideWebPreferencesAfterNavigation( + content::WebContents* web_contents, + blink::web_pref::WebPreferences* prefs) { + return renderer_prefs::PopulateWebPreferencesAfterNavigation(web_contents, + *prefs); +} + +void AlloyContentBrowserClient::BrowserURLHandlerCreated( + content::BrowserURLHandler* handler) { + scheme::BrowserURLHandlerCreated(handler); +} + +std::string AlloyContentBrowserClient::GetDefaultDownloadName() { + return "download"; +} + +void AlloyContentBrowserClient::DidCreatePpapiPlugin( + content::BrowserPpapiHost* browser_host) { + browser_host->GetPpapiHost()->AddHostFactoryFilter( + std::unique_ptr<ppapi::host::HostFactory>( + new ChromeBrowserPepperHostFactory(browser_host))); +} + +std::unique_ptr<content::DevToolsManagerDelegate> +AlloyContentBrowserClient::CreateDevToolsManagerDelegate() { + return std::make_unique<CefDevToolsManagerDelegate>(); +} + +void AlloyContentBrowserClient:: + RegisterAssociatedInterfaceBindersForRenderFrameHost( + content::RenderFrameHost& render_frame_host, + blink::AssociatedInterfaceRegistry& associated_registry) { + associated_registry.AddInterface<extensions::mojom::LocalFrameHost>( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver<extensions::mojom::LocalFrameHost> + receiver) { + extensions::ExtensionWebContentsObserver::BindLocalFrameHost( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); + + associated_registry.AddInterface<printing::mojom::PrintManagerHost>( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost> + receiver) { + printing::PrintViewManager::BindPrintManagerHost( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); + + associated_registry.AddInterface<pdf::mojom::PdfService>(base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver<pdf::mojom::PdfService> receiver) { + pdf::PDFWebContentsHelper::BindPdfService(std::move(receiver), + render_frame_host); + }, + &render_frame_host)); +} + +std::vector<std::unique_ptr<content::NavigationThrottle>> +AlloyContentBrowserClient::CreateThrottlesForNavigation( + content::NavigationHandle* navigation_handle) { + throttle::NavigationThrottleList throttles; + + if (extensions::ExtensionsEnabled()) { + auto pdf_iframe_throttle = + PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(navigation_handle); + if (pdf_iframe_throttle) { + throttles.push_back(std::move(pdf_iframe_throttle)); + } + + auto pdf_throttle = pdf::PdfNavigationThrottle::MaybeCreateThrottleFor( + navigation_handle, std::make_unique<ChromePdfStreamDelegate>()); + if (pdf_throttle) { + throttles.push_back(std::move(pdf_throttle)); + } + } + + throttle::CreateThrottlesForNavigation(navigation_handle, throttles); + + return throttles; +} + +std::vector<std::unique_ptr<blink::URLLoaderThrottle>> +AlloyContentBrowserClient::CreateURLLoaderThrottles( + const network::ResourceRequest& request, + content::BrowserContext* browser_context, + const base::RepeatingCallback<content::WebContents*()>& wc_getter, + content::NavigationUIData* navigation_ui_data, + int frame_tree_node_id) { + std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result; + + // Used to substitute View ID for PDF contents when using the PDF plugin. + result.push_back(std::make_unique<PluginResponseInterceptorURLLoaderThrottle>( + request.destination, frame_tree_node_id)); + + Profile* profile = Profile::FromBrowserContext(browser_context); + + chrome::mojom::DynamicParams dynamic_params = { + profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch), + profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict), + profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)}; + result.push_back( + std::make_unique<GoogleURLLoaderThrottle>(std::move(dynamic_params))); + + return result; +} + +std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> +AlloyContentBrowserClient::WillCreateURLLoaderRequestInterceptors( + content::NavigationUIData* navigation_ui_data, + int frame_tree_node_id) { + std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> + interceptors; + + if (extensions::ExtensionsEnabled()) { + auto pdf_interceptor = + pdf::PdfURLLoaderRequestInterceptor::MaybeCreateInterceptor( + frame_tree_node_id, std::make_unique<ChromePdfStreamDelegate>()); + if (pdf_interceptor) { + interceptors.push_back(std::move(pdf_interceptor)); + } + } + + return interceptors; +} + +#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) +void AlloyContentBrowserClient::GetAdditionalMappedFilesForChildProcess( + const base::CommandLine& command_line, + int child_process_id, + content::PosixFileDescriptorInfo* mappings) { + int crash_signal_fd = GetCrashSignalFD(); + if (crash_signal_fd >= 0) { + mappings->Share(kCrashDumpSignal, crash_signal_fd); + } +} +#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) + +void AlloyContentBrowserClient::ExposeInterfacesToRenderer( + service_manager::BinderRegistry* registry, + blink::AssociatedInterfaceRegistry* associated_registry, + content::RenderProcessHost* host) { + associated_registry->AddInterface<chrome::mojom::PluginInfoHost>( + base::BindRepeating(&BindPluginInfoHost, host->GetID())); + + if (extensions::ExtensionsEnabled()) { + associated_registry->AddInterface<extensions::mojom::EventRouter>( + base::BindRepeating(&extensions::EventRouter::BindForRenderer, + host->GetID())); + associated_registry->AddInterface<guest_view::mojom::GuestViewHost>( + base::BindRepeating( + &extensions::ExtensionsGuestView::CreateForComponents, + host->GetID())); + associated_registry->AddInterface<extensions::mojom::GuestView>( + base::BindRepeating( + &extensions::ExtensionsGuestView::CreateForExtensions, + host->GetID())); + associated_registry->AddInterface<extensions::mojom::RendererHost>( + base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer, + host->GetID())); + } + + CefBrowserManager::ExposeInterfacesToRenderer(registry, associated_registry, + host); +} + +std::unique_ptr<net::ClientCertStore> +AlloyContentBrowserClient::CreateClientCertStore( + content::BrowserContext* browser_context) { + // Match the logic in ProfileNetworkContextService::CreateClientCertStore. +#if BUILDFLAG(USE_NSS_CERTS) + // TODO: Add support for client implementation of crypto password dialog. + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS( + net::ClientCertStoreNSS::PasswordDelegateFactory())); +#elif BUILDFLAG(IS_WIN) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin()); +#elif BUILDFLAG(IS_MAC) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac()); +#else +#error Unknown platform. +#endif +} + +std::unique_ptr<content::LoginDelegate> +AlloyContentBrowserClient::CreateLoginDelegate( + const net::AuthChallengeInfo& auth_info, + content::WebContents* web_contents, + const content::GlobalRequestID& request_id, + bool is_request_for_main_frame, + const GURL& url, + scoped_refptr<net::HttpResponseHeaders> response_headers, + bool first_auth_attempt, + LoginAuthRequiredCallback auth_required_callback) { + return std::make_unique<net_service::LoginDelegate>( + auth_info, web_contents, request_id, url, + std::move(auth_required_callback)); +} + +void AlloyContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories( + int frame_tree_node_id, + ukm::SourceIdObj ukm_source_id, + NonNetworkURLLoaderFactoryMap* factories) { + if (!extensions::ExtensionsEnabled()) { + return; + } + + content::WebContents* web_contents = + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); + factories->emplace( + extensions::kExtensionScheme, + extensions::CreateExtensionNavigationURLLoaderFactory( + web_contents->GetBrowserContext(), ukm_source_id, + !!extensions::WebViewGuest::FromWebContents(web_contents))); +} + +void AlloyContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories( + int render_process_id, + int render_frame_id, + const absl::optional<url::Origin>& request_initiator_origin, + NonNetworkURLLoaderFactoryMap* factories) { + if (!extensions::ExtensionsEnabled()) { + return; + } + + auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id, + 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. + // See also HasCrossOriginWhitelistEntry. + allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost); + allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost); + } + if (!allowed_webui_hosts.empty()) { + factories->emplace(content::kChromeUIScheme, + content::CreateWebUIURLLoaderFactory( + frame_host, content::kChromeUIScheme, + std::move(allowed_webui_hosts))); + } +} + +bool AlloyContentBrowserClient::WillCreateURLLoaderFactory( + content::BrowserContext* browser_context, + content::RenderFrameHost* frame, + int render_process_id, + URLLoaderFactoryType type, + const url::Origin& request_initiator, + absl::optional<int64_t> navigation_id, + ukm::SourceIdObj ukm_source_id, + mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver, + mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>* + header_client, + bool* bypass_redirect_checks, + bool* disable_secure_dns, + network::mojom::URLLoaderFactoryOverridePtr* factory_override) { + auto request_handler = net_service::CreateInterceptedRequestHandler( + browser_context, frame, render_process_id, + type == URLLoaderFactoryType::kNavigation, + type == URLLoaderFactoryType::kDownload, request_initiator); + + net_service::ProxyURLLoaderFactory::CreateProxy( + browser_context, factory_receiver, header_client, + std::move(request_handler)); + return true; +} + +void AlloyContentBrowserClient::OnNetworkServiceCreated( + network::mojom::NetworkService* network_service) { + DCHECK(g_browser_process); + PrefService* local_state = g_browser_process->local_state(); + DCHECK(local_state); + + // Need to set up global NetworkService state before anything else uses it. + DCHECK(SystemNetworkContextManager::GetInstance()); + SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated( + network_service); +} + +bool AlloyContentBrowserClient::ConfigureNetworkContextParams( + content::BrowserContext* context, + bool in_memory, + const base::FilePath& relative_partition_path, + network::mojom::NetworkContextParams* network_context_params, + cert_verifier::mojom::CertVerifierCreationParams* + cert_verifier_creation_params) { + // This method may be called during shutdown when using multi-threaded + // message loop mode. In that case exit early to avoid crashes. + if (!SystemNetworkContextManager::GetInstance()) { + // Cancel NetworkContext creation in + // StoragePartitionImpl::InitNetworkContext. + return false; + } + + auto cef_context = CefBrowserContext::FromBrowserContext(context); + + Profile* profile = cef_context->AsProfile(); + ProfileNetworkContextService* service = + ProfileNetworkContextServiceFactory::GetForContext(profile); + if (service) { + service->ConfigureNetworkContextParams(in_memory, relative_partition_path, + network_context_params, + cert_verifier_creation_params); + } else { + // Set default params. + network_context_params->user_agent = GetUserAgent(); + network_context_params->accept_language = GetApplicationLocale(); + } + + network_context_params->cookieable_schemes = + cef_context->GetCookieableSchemes(); + + // TODO(cef): Remove this and add required NetworkIsolationKeys, + // this is currently not the case and this was not required pre M84. + network_context_params->require_network_isolation_key = false; + + return true; +} + +// The sandbox may block read/write access from the NetworkService to +// directories that are not returned by this method. +std::vector<base::FilePath> +AlloyContentBrowserClient::GetNetworkContextsParentDirectory() { + base::FilePath user_data_path; + base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path); + DCHECK(!user_data_path.empty()); + + const auto& root_cache_path = GetRootCachePath(); + + // root_cache_path may sometimes be empty or a child of user_data_path, so + // only return the one path in that case. + if (root_cache_path.empty() || user_data_path.IsParent(root_cache_path)) { + return {user_data_path}; + } + + return {user_data_path, root_cache_path}; +} + +bool AlloyContentBrowserClient::HandleExternalProtocol( + const GURL& url, + content::WebContents::Getter web_contents_getter, + int 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 absl::optional<url::Origin>& initiating_origin, + content::RenderFrameHost* initiator_document, + mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) { + // Call the other HandleExternalProtocol variant. + return false; +} + +bool AlloyContentBrowserClient::HandleExternalProtocol( + content::WebContents::Getter web_contents_getter, + int frame_tree_node_id, + content::NavigationUIData* navigation_data, + bool is_primary_main_frame, + bool is_in_fenced_frame_tree, + network::mojom::WebSandboxFlags sandbox_flags, + const network::ResourceRequest& resource_request, + const absl::optional<url::Origin>& initiating_origin, + content::RenderFrameHost* initiator_document, + mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) { + mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver = + out_factory->InitWithNewPipeAndPassReceiver(); + + // CefBrowserPlatformDelegate::HandleExternalProtocol may be called if + // nothing handles the request. + auto request_handler = net_service::CreateInterceptedRequestHandler( + web_contents_getter, frame_tree_node_id, resource_request, + base::BindRepeating(CefBrowserPlatformDelegate::HandleExternalProtocol, + resource_request.url)); + + net_service::ProxyURLLoaderFactory::CreateProxy( + web_contents_getter, std::move(receiver), std::move(request_handler)); + return true; +} + +std::unique_ptr<content::VideoOverlayWindow> +AlloyContentBrowserClient::CreateWindowForVideoPictureInPicture( + content::VideoPictureInPictureWindowController* controller) { + // Note: content::VideoOverlayWindow::Create() is defined by platform-specific + // implementation in chrome/browser/ui/views. This layering hack, which goes + // through //content and ContentBrowserClient, allows us to work around the + // dependency constraints that disallow directly calling + // chrome/browser/ui/views code either from here or from other code in + // chrome/browser. + return content::VideoOverlayWindow::Create(controller); +} + +void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForFrame( + content::RenderFrameHost* render_frame_host, + mojo::BinderMapWithContext<content::RenderFrameHost*>* map) { + CefBrowserFrame::RegisterBrowserInterfaceBindersForFrame(render_frame_host, + map); + + map->Add<blink::mojom::BadgeService>(base::BindRepeating(&BindBadgeService)); + map->Add<media::mojom::MediaFoundationRendererNotifier>( + base::BindRepeating(&BindMediaFoundationRendererNotifierHandler)); + map->Add<network_hints::mojom::NetworkHintsHandler>( + base::BindRepeating(&BindNetworkHintsHandler)); + + if (!extensions::ExtensionsEnabled()) { + return; + } + + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host); + if (!web_contents) { + return; + } + + const GURL& site = render_frame_host->GetSiteInstance()->GetSiteURL(); + if (!site.SchemeIs(extensions::kExtensionScheme)) { + return; + } + + content::BrowserContext* browser_context = + render_frame_host->GetProcess()->GetBrowserContext(); + auto* extension = extensions::ExtensionRegistry::Get(browser_context) + ->enabled_extensions() + .GetByID(site.host()); + if (!extension) { + return; + } + extensions::ExtensionsBrowserClient::Get() + ->RegisterBrowserInterfaceBindersForFrame(map, render_frame_host, + extension); +} + +void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForServiceWorker( + content::BrowserContext* browser_context, + const content::ServiceWorkerVersionBaseInfo& service_worker_version_info, + mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>* + map) { + map->Add<blink::mojom::BadgeService>( + base::BindRepeating(&BindBadgeServiceForServiceWorker)); +} + +base::FilePath +AlloyContentBrowserClient::GetSandboxedStorageServiceDataDirectory() { + return GetRootCachePath(); +} + +std::string AlloyContentBrowserClient::GetProduct() { + return GetChromeProduct(); +} + +std::string AlloyContentBrowserClient::GetChromeProduct() { + return version_info::GetProductNameAndVersionForUserAgent(); +} + +std::string AlloyContentBrowserClient::GetUserAgent() { + return embedder_support::GetUserAgent(); +} + +std::string AlloyContentBrowserClient::GetFullUserAgent() { + return embedder_support::GetFullUserAgent(); +} + +std::string AlloyContentBrowserClient::GetReducedUserAgent() { + return embedder_support::GetReducedUserAgent(); +} + +std::unique_ptr<content::WebContentsViewDelegate> +AlloyContentBrowserClient::GetWebContentsViewDelegate( + content::WebContents* web_contents) { + return std::make_unique<AlloyWebContentsViewDelegate>(web_contents); +} + +blink::UserAgentMetadata AlloyContentBrowserClient::GetUserAgentMetadata() { + blink::UserAgentMetadata metadata; + + metadata.brand_version_list = {blink::UserAgentBrandVersion{ + version_info::GetProductName(), version_info::GetMajorVersionNumber()}}; + metadata.full_version = version_info::GetVersionNumber(); + metadata.platform = version_info::GetOSType(); + + // TODO(mkwst): Poke at BuildUserAgentFromProduct to split out these pieces. + metadata.architecture = ""; + metadata.model = ""; + + return metadata; +} + +base::flat_set<std::string> +AlloyContentBrowserClient::GetPluginMimeTypesWithExternalHandlers( + content::BrowserContext* browser_context) { + base::flat_set<std::string> mime_types; + auto map = PluginUtils::GetMimeTypeToExtensionIdMap(browser_context); + for (const auto& pair : map) { + mime_types.insert(pair.first); + } + mime_types.insert(pdf::kInternalPluginMimeType); + return mime_types; +} + +bool AlloyContentBrowserClient::ArePersistentMediaDeviceIDsAllowed( + content::BrowserContext* browser_context, + const GURL& url, + const net::SiteForCookies& site_for_cookies, + const absl::optional<url::Origin>& top_frame_origin) { + // Persistent MediaDevice IDs are allowed if cookies are allowed. + return CookieSettingsFactory::GetForProfile( + Profile::FromBrowserContext(browser_context)) + ->IsFullCookieAccessAllowed( + url, site_for_cookies, top_frame_origin, + net::CookieSettingOverrides(), + content_settings::CookieSettings::QueryReason::kSiteStorage); +} + +void AlloyContentBrowserClient::OnWebContentsCreated( + content::WebContents* web_contents) { + // Attach universal WebContentsObservers. These are quite rare, and in most + // cases CefBrowserPlatformDelegateAlloy::BrowserCreated and/or + // CefExtensionsAPIClient::AttachWebContentsHelpers should be used instead. + + if (extensions::ExtensionsEnabled()) { + extensions::CefExtensionWebContentsObserver::CreateForWebContents( + web_contents); + } +} + +bool AlloyContentBrowserClient::IsFindInPageDisabledForOrigin( + const url::Origin& origin) { + // For PDF viewing with the PPAPI-free PDF Viewer, find-in-page should only + // display results from the PDF content, and not from the UI. + return IsPdfExtensionOrigin(origin); +} + +CefRefPtr<CefRequestContextImpl> AlloyContentBrowserClient::request_context() + const { + return browser_main_parts_->request_context(); +} + +CefDevToolsDelegate* AlloyContentBrowserClient::devtools_delegate() const { + return browser_main_parts_->devtools_delegate(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +AlloyContentBrowserClient::background_task_runner() const { + return browser_main_parts_->background_task_runner(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +AlloyContentBrowserClient::user_visible_task_runner() const { + return browser_main_parts_->user_visible_task_runner(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +AlloyContentBrowserClient::user_blocking_task_runner() const { + return browser_main_parts_->user_blocking_task_runner(); +} + +const extensions::Extension* AlloyContentBrowserClient::GetExtension( + content::SiteInstance* site_instance) { + extensions::ExtensionRegistry* registry = + extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext()); + if (!registry) { + return nullptr; + } + return registry->enabled_extensions().GetExtensionOrAppByURL( + site_instance->GetSiteURL()); +} |