blob: 29b6e09ed0a20d4a5ecaa9f7338ba02344b98848 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "content_browser_client_qt.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
#include "base/message_loop/message_loop.h"
#include "base/task/post_task.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#if QT_CONFIG(webengine_spellchecker)
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
#endif
#include "components/guest_view/browser/guest_view_base.h"
#include "components/network_hints/browser/network_hints_message_filter.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/common/url_schemes.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/media_observer.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/resource_dispatcher_host.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h"
#include "media/media_buildflags.h"
#include "extensions/buildflags/buildflags.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "printing/buildflags/buildflags.h"
#include "qtwebengine/browser/qtwebengine_content_browser_overlay_manifest.h"
#include "qtwebengine/browser/qtwebengine_content_renderer_overlay_manifest.h"
#include "qtwebengine/browser/qtwebengine_packaged_service_manifest.h"
#include "qtwebengine/browser/qtwebengine_renderer_manifest.h"
#include "net/ssl/client_cert_identity.h"
#include "net/ssl/client_cert_store.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/sandbox/switches.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gpu_timing.h"
#include "url/url_util_qt.h"
#include "qtwebengine/common/renderer_configuration.mojom.h"
#include "qtwebengine/grit/qt_webengine_resources.h"
#include "profile_adapter.h"
#include "browser_main_parts_qt.h"
#include "browser_message_filter_qt.h"
#include "certificate_error_controller.h"
#include "certificate_error_controller_p.h"
#include "client_cert_select_controller.h"
#include "devtools_manager_delegate_qt.h"
#include "login_delegate_qt.h"
#include "media_capture_devices_dispatcher.h"
#include "net/network_delegate_qt.h"
#include "net/url_request_context_getter_qt.h"
#include "platform_notification_service_qt.h"
#if QT_CONFIG(webengine_printing_and_pdf)
#include "printing/printing_message_filter_qt.h"
#endif
#include "profile_qt.h"
#include "profile_io_data_qt.h"
#include "quota_permission_context_qt.h"
#include "renderer_host/user_resource_controller_host.h"
#include "service/service_qt.h"
#include "type_conversion.h"
#include "web_contents_delegate_qt.h"
#include "web_engine_context.h"
#include "web_engine_library_info.h"
#include "api/qwebenginecookiestore.h"
#include "api/qwebenginecookiestore_p.h"
#if defined(Q_OS_LINUX)
#include "global_descriptors_qt.h"
#include "ui/base/resource/resource_bundle.h"
#endif
#if QT_CONFIG(webengine_pepper_plugins)
#include "content/public/browser/browser_ppapi_host.h"
#include "ppapi/host/ppapi_host.h"
#include "renderer_host/pepper/pepper_host_factory_qt.h"
#endif
#if QT_CONFIG(webengine_geolocation)
#include "location_provider_qt.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/extensions_browser_client_qt.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
#include "extensions/browser/io_thread_extension_message_filter.h"
#include "extensions/common/constants.h"
#include "common/extensions/extensions_client_qt.h"
#include "renderer_host/resource_dispatcher_host_delegate_qt.h"
#endif
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
#include "media/mojo/interfaces/constants.mojom.h"
#include "media/mojo/services/media_service_factory.h"
#endif
#include <QGuiApplication>
#include <QLocale>
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
# include <QOpenGLExtraFunctions>
#endif
#include <qpa/qplatformnativeinterface.h>
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context();
QT_END_NAMESPACE
namespace QtWebEngineCore {
class QtShareGLContext : public gl::GLContext {
public:
QtShareGLContext(QOpenGLContext *qtContext)
: gl::GLContext(0)
, m_handle(0)
{
QString platform = qApp->platformName().toLower();
QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface();
if (platform == QLatin1String("xcb") || platform == QLatin1String("offscreen")) {
if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2)
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext);
else
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("glxcontext"), qtContext);
} else if (platform == QLatin1String("cocoa"))
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("cglcontextobj"), qtContext);
else if (platform == QLatin1String("qnx"))
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext);
else if (platform == QLatin1String("eglfs") || platform == QLatin1String("wayland")
|| platform == QLatin1String("wayland-egl"))
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext);
else if (platform == QLatin1String("windows")) {
if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2)
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglContext"), qtContext);
else
m_handle = pni->nativeResourceForContext(QByteArrayLiteral("renderingcontext"), qtContext);
} else {
qFatal("%s platform not yet supported", platform.toLatin1().constData());
// Add missing platforms once they work.
Q_UNREACHABLE();
}
}
void* GetHandle() override { return m_handle; }
unsigned int CheckStickyGraphicsResetStatus() override
{
#if QT_CONFIG(opengl)
if (QOpenGLContext *context = qt_gl_global_share_context()) {
if (context->format().testOption(QSurfaceFormat::ResetNotification))
return context->extraFunctions()->glGetGraphicsResetStatus();
}
#endif
return 0 /*GL_NO_ERROR*/;
}
// We don't care about the rest, this context shouldn't be used except for its handle.
bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override { Q_UNREACHABLE(); return false; }
bool MakeCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); return false; }
void ReleaseCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); }
bool IsCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); return false; }
scoped_refptr<gl::GPUTimingClient> CreateGPUTimingClient() override
{
return nullptr;
}
const gfx::ExtensionSet& GetExtensions() override
{
static const gfx::ExtensionSet s_emptySet;
return s_emptySet;
}
void ResetExtensions() override
{
}
private:
void *m_handle;
};
class ShareGroupQtQuick : public gl::GLShareGroup {
public:
gl::GLContext* GetContext() override { return m_shareContextQtQuick.get(); }
void AboutToAddFirstContext() override;
private:
scoped_refptr<QtShareGLContext> m_shareContextQtQuick;
};
void ShareGroupQtQuick::AboutToAddFirstContext()
{
#ifndef QT_NO_OPENGL
// This currently has to be setup by ::main in all applications using QQuickWebEngineView with delegated rendering.
QOpenGLContext *shareContext = qt_gl_global_share_context();
if (!shareContext) {
qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to call QtWebEngine::initialize() in your main() function before QCoreApplication is created.");
}
m_shareContextQtQuick = new QtShareGLContext(shareContext);
#endif
}
ContentBrowserClientQt::ContentBrowserClientQt()
{
}
ContentBrowserClientQt::~ContentBrowserClientQt()
{
}
std::unique_ptr<content::BrowserMainParts> ContentBrowserClientQt::CreateBrowserMainParts(const content::MainFunctionParams&)
{
return std::make_unique<BrowserMainPartsQt>();
}
void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* host,
service_manager::mojom::ServiceRequest *service_request)
{
const int id = host->GetID();
Profile *profile = Profile::FromBrowserContext(host->GetBrowserContext());
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&net::URLRequestContextGetter::GetURLRequestContext, base::Unretained(profile->GetRequestContext())),
base::BindOnce(&ContentBrowserClientQt::AddNetworkHintsMessageFilter, base::Unretained(this), id));
// FIXME: Add a settings variable to enable/disable the file scheme.
content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestScheme(id, url::kFileScheme);
static_cast<ProfileQt*>(host->GetBrowserContext())->m_profileAdapter->userResourceController()->renderProcessStartedWithHost(host);
host->AddFilter(new BrowserMessageFilterQt(id, profile));
#if QT_CONFIG(webengine_printing_and_pdf)
host->AddFilter(new PrintingMessageFilterQt(host->GetID()));
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
host->AddFilter(new extensions::ExtensionMessageFilter(host->GetID(), host->GetBrowserContext()));
host->AddFilter(new extensions::IOThreadExtensionMessageFilter(host->GetID(), host->GetBrowserContext()));
host->AddFilter(new extensions::ExtensionsGuestViewMessageFilter(host->GetID(), host->GetBrowserContext()));
#endif //ENABLE_EXTENSIONS
bool is_incognito_process = profile->IsOffTheRecord();
qtwebengine::mojom::RendererConfigurationAssociatedPtr renderer_configuration;
host->GetChannel()->GetRemoteAssociatedInterface(&renderer_configuration);
renderer_configuration->SetInitialConfiguration(is_incognito_process);
mojo::PendingRemote<service_manager::mojom::Service> service;
*service_request = service.InitWithNewPipeAndPassReceiver();
service_manager::Identity renderer_identity = host->GetChildIdentity();
mojo::Remote<service_manager::mojom::ProcessMetadata> metadata;
ServiceQt::GetInstance()->connector()->RegisterServiceInstance(
service_manager::Identity("qtwebengine_renderer",
renderer_identity.instance_group(),
renderer_identity.instance_id(),
base::Token::CreateRandom()),
std::move(service), metadata.BindNewPipeAndPassReceiver());
}
void ContentBrowserClientQt::ResourceDispatcherHostCreated()
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
m_resourceDispatcherHostDelegate.reset(new ResourceDispatcherHostDelegateQt);
#else
m_resourceDispatcherHostDelegate.reset(new content::ResourceDispatcherHostDelegate);
#endif
content::ResourceDispatcherHost::Get()->SetDelegate(m_resourceDispatcherHostDelegate.get());
}
gl::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup()
{
if (!m_shareGroupQtQuick.get())
m_shareGroupQtQuick = new ShareGroupQtQuick;
return m_shareGroupQtQuick.get();
}
content::MediaObserver *ContentBrowserClientQt::GetMediaObserver()
{
return MediaCaptureDevicesDispatcher::GetInstance();
}
void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, content::WebPreferences *web_prefs)
{
if (content::WebContents *webContents = rvh->GetDelegate()->GetAsWebContents()) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
if (guest_view::GuestViewBase::IsGuest(webContents))
return;
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
WebContentsDelegateQt* delegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
if (delegate)
delegate->overrideWebPreferences(webContents, web_prefs);
}
}
scoped_refptr<content::QuotaPermissionContext> ContentBrowserClientQt::CreateQuotaPermissionContext()
{
return new QuotaPermissionContextQt;
}
void ContentBrowserClientQt::GetQuotaSettings(content::BrowserContext* context,
content::StoragePartition* partition,
storage::OptionalQuotaSettingsCallback callback)
{
storage::GetNominalDynamicSettings(partition->GetPath(), context->IsOffTheRecord(), storage::GetDefaultDiskInfoHelper(), std::move(callback));
}
// Copied from chrome/browser/ssl/ssl_error_handler.cc:
static int IsCertErrorFatal(int cert_error)
{
switch (cert_error) {
case net::ERR_CERT_COMMON_NAME_INVALID:
case net::ERR_CERT_DATE_INVALID:
case net::ERR_CERT_AUTHORITY_INVALID:
case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
case net::ERR_CERT_WEAK_KEY:
case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
case net::ERR_CERT_VALIDITY_TOO_LONG:
case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
case net::ERR_CERT_SYMANTEC_LEGACY:
return false;
case net::ERR_CERT_CONTAINS_ERRORS:
case net::ERR_CERT_REVOKED:
case net::ERR_CERT_INVALID:
case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
return true;
default:
NOTREACHED();
}
return true;
}
void ContentBrowserClientQt::AllowCertificateError(content::WebContents *webContents,
int cert_error,
const net::SSLInfo &ssl_info,
const GURL &request_url,
bool is_main_frame_request,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(content::CertificateRequestResultType)> &callback)
{
WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
QSharedPointer<CertificateErrorController> errorController(
new CertificateErrorController(
new CertificateErrorControllerPrivate(
cert_error,
ssl_info,
request_url,
is_main_frame_request,
IsCertErrorFatal(cert_error),
strict_enforcement,
callback)));
contentsDelegate->allowCertificateError(errorController);
}
base::OnceClosure ContentBrowserClientQt::SelectClientCertificate(content::WebContents *webContents,
net::SSLCertRequestInfo *certRequestInfo,
net::ClientCertIdentityList clientCerts,
std::unique_ptr<content::ClientCertificateDelegate> delegate)
{
if (!clientCerts.empty()) {
WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
QSharedPointer<ClientCertSelectController> certSelectController(
new ClientCertSelectController(certRequestInfo, std::move(clientCerts), std::move(delegate)));
contentsDelegate->selectClientCert(certSelectController);
} else {
delegate->ContinueWithCertificate(nullptr, nullptr);
}
// This is consistent with AwContentBrowserClient and CastContentBrowserClient:
return base::OnceClosure();
}
std::unique_ptr<net::ClientCertStore> ContentBrowserClientQt::CreateClientCertStore(content::ResourceContext *resource_context)
{
if (!resource_context)
return nullptr;
return ProfileIODataQt::FromResourceContext(resource_context)->CreateClientCertStore();
}
std::string ContentBrowserClientQt::GetApplicationLocale()
{
return WebEngineLibraryInfo::getApplicationLocale();
}
std::string ContentBrowserClientQt::GetAcceptLangs(content::BrowserContext *context)
{
return static_cast<ProfileQt*>(context)->profileAdapter()->httpAcceptLanguage().toStdString();
}
void ContentBrowserClientQt::AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id)
{
Q_UNUSED(child_process_id);
url::CustomScheme::SaveSchemes(command_line);
std::string processType = command_line->GetSwitchValueASCII(switches::kProcessType);
if (processType == service_manager::switches::kZygoteProcess)
command_line->AppendSwitchASCII(switches::kLang, GetApplicationLocale());
}
void ContentBrowserClientQt::GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes)
{
additional_schemes->push_back(content::kChromeDevToolsScheme);
}
void ContentBrowserClientQt::GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes)
{
additional_schemes->push_back(content::kChromeDevToolsScheme);
}
#if defined(Q_OS_LINUX)
void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings)
{
const std::string &locale = GetApplicationLocale();
const base::FilePath &locale_file_path = ui::ResourceBundle::GetSharedInstance().GetLocaleFilePath(locale, true);
if (locale_file_path.empty())
return;
// Open pak file of the current locale in the Browser process and pass its file descriptor to the sandboxed
// Renderer Process. FileDescriptorInfo is responsible for closing the file descriptor.
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
base::File locale_file = base::File(locale_file_path, flags);
mappings->Transfer(kWebEngineLocale, base::ScopedFD(locale_file.TakePlatformFile()));
}
#endif
#if QT_CONFIG(webengine_pepper_plugins)
void ContentBrowserClientQt::DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host)
{
browser_host->GetPpapiHost()->AddHostFactoryFilter(
std::make_unique<QtWebEngineCore::PepperHostFactoryQt>(browser_host));
}
#endif
content::DevToolsManagerDelegate* ContentBrowserClientQt::GetDevToolsManagerDelegate()
{
return new DevToolsManagerDelegateQt;
}
content::PlatformNotificationService *ContentBrowserClientQt::GetPlatformNotificationService(content::BrowserContext *browser_context)
{
ProfileQt *profile = static_cast<ProfileQt *>(browser_context);
if (!profile)
return nullptr;
return profile->platformNotificationService();
}
// This is a really complicated way of doing absolutely nothing, but Mojo demands it:
class ServiceDriver
: public blink::mojom::InsecureInputService
, public content::WebContentsUserData<ServiceDriver>
{
public:
static void CreateForRenderFrameHost(content::RenderFrameHost *renderFrameHost)
{
content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(renderFrameHost);
if (!web_contents)
return;
CreateForWebContents(web_contents);
}
static ServiceDriver* FromRenderFrameHost(content::RenderFrameHost *renderFrameHost)
{
content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(renderFrameHost);
if (!web_contents)
return nullptr;
return FromWebContents(web_contents);
}
static void BindInsecureInputService(blink::mojom::InsecureInputServiceRequest request, content::RenderFrameHost *render_frame_host)
{
CreateForRenderFrameHost(render_frame_host);
ServiceDriver *driver = FromRenderFrameHost(render_frame_host);
if (driver)
driver->BindInsecureInputServiceRequest(std::move(request));
}
void BindInsecureInputServiceRequest(blink::mojom::InsecureInputServiceRequest request)
{
m_insecureInputServiceBindings.AddBinding(this, std::move(request));
}
// blink::mojom::InsecureInputService:
void DidEditFieldInInsecureContext() override
{ }
private:
WEB_CONTENTS_USER_DATA_KEY_DECL();
explicit ServiceDriver(content::WebContents* /*web_contents*/) { }
friend class content::WebContentsUserData<ServiceDriver>;
mojo::BindingSet<blink::mojom::InsecureInputService> m_insecureInputServiceBindings;
};
WEB_CONTENTS_USER_DATA_KEY_IMPL(ServiceDriver)
void ContentBrowserClientQt::InitFrameInterfaces()
{
m_frameInterfaces = std::make_unique<service_manager::BinderRegistry>();
m_frameInterfacesParameterized = std::make_unique<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>>();
m_frameInterfacesParameterized->AddInterface(base::BindRepeating(&ServiceDriver::BindInsecureInputService));
}
void ContentBrowserClientQt::BindInterfaceRequestFromFrame(content::RenderFrameHost* render_frame_host,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe)
{
if (!m_frameInterfaces.get() && !m_frameInterfacesParameterized.get())
InitFrameInterfaces();
if (!m_frameInterfacesParameterized->TryBindInterface(interface_name, &interface_pipe, render_frame_host))
m_frameInterfaces->TryBindInterface(interface_name, &interface_pipe);
}
void ContentBrowserClientQt::RunServiceInstance(const service_manager::Identity &identity,
mojo::PendingReceiver<service_manager::mojom::Service> *receiver)
{
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
if (identity.name() == media::mojom::kMediaServiceName) {
service_manager::Service::RunAsyncUntilTermination(media::CreateMediaService(std::move(*receiver)));
return;
}
#endif
content::ContentBrowserClient::RunServiceInstance(identity, receiver);
}
void ContentBrowserClientQt::RunServiceInstanceOnIOThread(const service_manager::Identity &identity,
mojo::PendingReceiver<service_manager::mojom::Service> *receiver)
{
if (identity.name() == "qtwebengine") {
ServiceQt::GetInstance()->CreateServiceQtRequestHandler().Run(std::move(*receiver));
return;
}
content::ContentBrowserClient::RunServiceInstance(identity, receiver);
}
base::Optional<service_manager::Manifest> ContentBrowserClientQt::GetServiceManifestOverlay(base::StringPiece name)
{
if (name == content::mojom::kBrowserServiceName)
return GetQtWebEngineContentBrowserOverlayManifest();
else if (name == content::mojom::kRendererServiceName)
return GetQtWebEngineContentRendererOverlayManifest();
return base::nullopt;
}
std::vector<service_manager::Manifest> ContentBrowserClientQt::GetExtraServiceManifests()
{
auto manifests = GetQtWebEnginePackagedServiceManifests();
manifests.push_back(GetQtWebEngineRendererManifest());
return manifests;
}
bool ContentBrowserClientQt::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)
{
Q_UNUSED(opener_url);
Q_UNUSED(opener_top_level_frame_url);
Q_UNUSED(source_origin);
Q_UNUSED(container_type);
Q_UNUSED(target_url);
Q_UNUSED(referrer);
Q_UNUSED(frame_name);
Q_UNUSED(disposition);
Q_UNUSED(features);
Q_UNUSED(opener_suppressed);
if (no_javascript_access)
*no_javascript_access = false;
content::WebContents* webContents = content::WebContents::FromRenderFrameHost(opener);
WebEngineSettings *settings = nullptr;
if (webContents) {
WebContentsDelegateQt* delegate =
static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
if (delegate)
settings = delegate->webEngineSettings();
}
return (settings && settings->getJavaScriptCanOpenWindowsAutomatically()) || user_gesture;
}
#if QT_CONFIG(webengine_geolocation)
std::unique_ptr<device::LocationProvider> ContentBrowserClientQt::OverrideSystemLocationProvider()
{
return base::WrapUnique(new LocationProviderQt());
}
#endif
void ContentBrowserClientQt::AddNetworkHintsMessageFilter(int render_process_id, net::URLRequestContext *context)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::RenderProcessHost* host = content::RenderProcessHost::FromID(render_process_id);
if (!host)
return;
content::BrowserMessageFilter *network_hints_message_filter =
new network_hints::NetworkHintsMessageFilter(render_process_id);
host->AddFilter(network_hints_message_filter);
}
bool ContentBrowserClientQt::ShouldEnableStrictSiteIsolation()
{
// mirroring AwContentBrowserClient, CastContentBrowserClient and
// HeadlessContentBrowserClient
return false;
}
bool ContentBrowserClientQt::WillCreateRestrictedCookieManager(network::mojom::RestrictedCookieManagerRole role,
content::BrowserContext *browser_context,
const url::Origin &origin,
bool is_service_worker,
int process_id,
int routing_id,
network::mojom::RestrictedCookieManagerRequest *request)
{
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&ProfileIODataQt::CreateRestrictedCookieManager,
ProfileIODataQt::FromBrowserContext(browser_context)->getWeakPtrOnUIThread(),
std::move(*request),
role, origin, is_service_worker, process_id, routing_id));
return true;
}
bool ContentBrowserClientQt::AllowAppCacheOnIO(const GURL &manifest_url,
const GURL &first_party,
content::ResourceContext *context)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(manifest_url));
}
bool ContentBrowserClientQt::AllowAppCache(const GURL &manifest_url,
const GURL &first_party,
content::BrowserContext *context)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return static_cast<ProfileQt *>(context)->profileAdapter()->cookieStore()->d_func()->canAccessCookies(toQt(first_party), toQt(manifest_url));
}
bool ContentBrowserClientQt::AllowServiceWorker(const GURL &scope,
const GURL &first_party,
const GURL & /*script_url*/,
content::ResourceContext *context,
base::RepeatingCallback<content::WebContents*()> wc_getter)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// FIXME: Chrome also checks if javascript is enabled here to check if has been disabled since the service worker
// was started.
return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(scope));
}
// We control worker access to FS and indexed-db using cookie permissions, this is mirroring Chromium's logic.
void ContentBrowserClientQt::AllowWorkerFileSystem(const GURL &url,
content::ResourceContext *context,
const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/,
base::Callback<void(bool)> callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
callback.Run(ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(url), QByteArray(), toQt(url)));
}
bool ContentBrowserClientQt::AllowWorkerIndexedDB(const GURL &url,
content::ResourceContext *context,
const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
return ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(url), QByteArray(), toQt(url));
}
static void LaunchURL(const GURL& url,
const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
content::WebContents* webContents = web_contents_getter.Run();
if (!webContents)
return;
WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
contentsDelegate->launchExternalURL(toQt(url), page_transition, is_main_frame, has_user_gesture);
}
bool ContentBrowserClientQt::HandleExternalProtocol(
const GURL &url,
content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
int child_id,
content::NavigationUIData *navigation_data,
bool is_main_frame,
ui::PageTransition page_transition,
bool has_user_gesture,
network::mojom::URLLoaderFactoryPtr *out_factory)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Q_UNUSED(child_id);
Q_UNUSED(navigation_data);
Q_UNUSED(out_factory);
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&LaunchURL,
url,
web_contents_getter,
page_transition,
is_main_frame,
has_user_gesture));
return true;
}
namespace {
// Copied from chrome/browser/chrome_content_browser_client.cc
template<class HandlerRegistry>
class ProtocolHandlerThrottle : public content::URLLoaderThrottle
{
public:
explicit ProtocolHandlerThrottle(const HandlerRegistry &protocol_handler_registry)
: protocol_handler_registry_(protocol_handler_registry)
{
}
~ProtocolHandlerThrottle() override = default;
void WillStartRequest(network::ResourceRequest *request, bool *defer) override
{
TranslateUrl(&request->url);
}
void WillRedirectRequest(net::RedirectInfo *redirect_info,
const network::ResourceResponseHead &response_head, bool *defer,
std::vector<std::string> *to_be_removed_headers,
net::HttpRequestHeaders *modified_headers) override
{
TranslateUrl(&redirect_info->new_url);
}
private:
void TranslateUrl(GURL *url)
{
if (!protocol_handler_registry_->IsHandledProtocol(url->scheme()))
return;
GURL translated_url = protocol_handler_registry_->Translate(*url);
if (!translated_url.is_empty())
*url = translated_url;
}
HandlerRegistry protocol_handler_registry_;
};
} // namespace
std::vector<std::unique_ptr<content::URLLoaderThrottle>>
ContentBrowserClientQt::CreateURLLoaderThrottlesOnIO(
const network::ResourceRequest & /*request*/, content::ResourceContext *resource_context,
const base::RepeatingCallback<content::WebContents *()> & /*wc_getter*/,
content::NavigationUIData * /*navigation_ui_data*/, int /*frame_tree_node_id*/)
{
std::vector<std::unique_ptr<content::URLLoaderThrottle>> result;
ProfileIODataQt *ioData = ProfileIODataQt::FromResourceContext(resource_context);
result.push_back(std::make_unique<ProtocolHandlerThrottle<
scoped_refptr<ProtocolHandlerRegistry::IOThreadDelegate>>>(
ioData->protocolHandlerRegistryIOThreadDelegate()));
return result;
}
std::vector<std::unique_ptr<content::URLLoaderThrottle>>
ContentBrowserClientQt::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<content::URLLoaderThrottle>> result;
result.push_back(std::make_unique<ProtocolHandlerThrottle<ProtocolHandlerRegistry *>>(
ProtocolHandlerRegistryFactory::GetForBrowserContext(browser_context)));
return result;
}
std::unique_ptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegate(
const net::AuthChallengeInfo &authInfo,
content::WebContents *web_contents,
const content::GlobalRequestID & /*request_id*/,
bool /*is_main_frame*/,
const GURL &url,
scoped_refptr<net::HttpResponseHeaders> /*response_headers*/,
bool first_auth_attempt,
LoginAuthRequiredCallback auth_required_callback)
{
auto loginDelegate = std::make_unique<LoginDelegateQt>(authInfo, web_contents, url, first_auth_attempt, std::move(auth_required_callback));
return loginDelegate;
}
bool ContentBrowserClientQt::ShouldIsolateErrorPage(bool in_main_frame)
{
Q_UNUSED(in_main_frame);
return false;
}
bool ContentBrowserClientQt::ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url)
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
if (effective_url.SchemeIs(extensions::kExtensionScheme))
return true;
#endif
return ContentBrowserClient::ShouldUseProcessPerSite(browser_context, effective_url);
}
std::string ContentBrowserClientQt::getUserAgent()
{
// Mention the Chromium version we're based on to get passed stupid UA-string-based feature detection (several WebRTC demos need this)
return content::BuildUserAgentFromProduct("QtWebEngine/" QTWEBENGINECORE_VERSION_STR " Chrome/" CHROMIUM_VERSION);
}
std::string ContentBrowserClientQt::GetProduct()
{
QString productName(qApp->applicationName() % '/' % qApp->applicationVersion());
return productName.toStdString();
}
} // namespace QtWebEngineCore