mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-01-05 22:48:06 +01:00
8f240861e3
Implementation notes: - Chromium change: CookieMonster::SetCookieableSchemes needs to be called immediately after the CookieMonster is created in NetworkContext:: ApplyContextParamsToBuilder. Add a Profile::GetCookieableSchemes method and NetworkContextParams.cookieable_schemes member (set from ProfileNetworkContextService::CreateNetworkContextParams) to support that. - Chromium change: Add a ContentBrowserClient::HandleExternalProtocol variant that exposes additional NetworkService request information. - GetResourceResponseFilter is not yet implemented. API changes: - Resource-related callbacks have been moved from CefRequestHandler to a new CefResourceRequestHandler interface which is returned via the GetResourceRequestHandler method. If the CefRequestHandler declines to handle a resource it can optionally be handled by the CefRequestContextHandler, if any, associated with the loading context. - The OnProtocolExecution callback has been moved from CefRequestHandler to CefResourceRequestHandler and will be called if a custom scheme request is unhandled. - Cookie send/save permission callbacks have been moved from CefRequestHandler and CefResourceHandler to CefResourceRequestHandler. - New methods added to CefResourceHandler that better match NetworkService execution sequence expectations. The old methods are now deprecated. - New methods added to CefRequest and CefResponse. Known behavior changes with the NetworkService implementation: - Modifying the |new_url| parameter in OnResourceRedirect will no longer result in the method being called an additional time (likely a bug in the old implementation). - Modifying the request URL in OnResourceResponse would previously cause a redirect. This behavior is now deprecated because the NetworkService does not support this functionality when using default network loaders. Temporary support has been added in combination with CefResourceHandler usage only. - Other changes to the request object in OnResourceResponse will now cause the request to be restarted. This means that OnBeforeResourceLoad, etc, will be called an additional time with the new request information. - CefResponse::GetMimeType will now be empty for non-200 responses. - Requests using custom schemes can now be handled via CefResourceRequestHandler with the same callback behavior as builtin schemes. - Redirects of custom scheme requests will now be followed as expected. - Default handling of builtin schemes can now be disabled by setting |disable_default_handling| to true in GetResourceRequestHandler. - Unhandled requests (custom scheme or builtin scheme with default handling disabled) will fail with an CefResponse::GetError value of ERR_UNKNOWN_URL_SCHEME. - The CefSchemeHandlerFactory::Create callback will now include cookie headers. To test: - Run `cefclient --enable-network-service`. All resources should load successfully (this tests the transparent proxy capability). - All tests pass with NetworkService disabled. - The following tests pass with NetworkService enabled: - CookieTest.* - FrameTest.* (excluding .*Nav) - NavigationTest.* (excluding .Redirect*) - RequestHandlerTest.* - RequestContextTest.Basic* - RequestContextTest.Popup* - RequestTest.* - ResourceManagerTest.* - ResourceRequestHandlerTest.* (excluding .Filter*) - SchemeHandlerTest.* - StreamResourceHandlerTest.*
1372 lines
50 KiB
C++
1372 lines
50 KiB
C++
// 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/content_browser_client.h"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
#include "include/cef_version.h"
|
|
#include "libcef/browser/browser_context.h"
|
|
#include "libcef/browser/browser_host_impl.h"
|
|
#include "libcef/browser/browser_info.h"
|
|
#include "libcef/browser/browser_info_manager.h"
|
|
#include "libcef/browser/browser_main.h"
|
|
#include "libcef/browser/browser_message_filter.h"
|
|
#include "libcef/browser/browser_platform_delegate.h"
|
|
#include "libcef/browser/context.h"
|
|
#include "libcef/browser/devtools/devtools_manager_delegate.h"
|
|
#include "libcef/browser/extensions/extension_system.h"
|
|
#include "libcef/browser/media_capture_devices_dispatcher.h"
|
|
#include "libcef/browser/net/chrome_scheme_handler.h"
|
|
#include "libcef/browser/net/net_util.h"
|
|
#include "libcef/browser/net_service/proxy_url_loader_factory.h"
|
|
#include "libcef/browser/net_service/resource_request_handler_wrapper.h"
|
|
#include "libcef/browser/plugins/plugin_service_filter.h"
|
|
#include "libcef/browser/prefs/renderer_prefs.h"
|
|
#include "libcef/browser/printing/printing_message_filter.h"
|
|
#include "libcef/browser/resource_dispatcher_host_delegate.h"
|
|
#include "libcef/browser/speech_recognition_manager_delegate.h"
|
|
#include "libcef/browser/ssl_info_impl.h"
|
|
#include "libcef/browser/thread_util.h"
|
|
#include "libcef/browser/x509_certificate_impl.h"
|
|
#include "libcef/common/cef_messages.h"
|
|
#include "libcef/common/cef_switches.h"
|
|
#include "libcef/common/command_line_impl.h"
|
|
#include "libcef/common/content_client.h"
|
|
#include "libcef/common/extensions/extensions_util.h"
|
|
#include "libcef/common/net/scheme_registration.h"
|
|
#include "libcef/common/net_service/util.h"
|
|
#include "libcef/common/request_impl.h"
|
|
#include "libcef/common/service_manifests/cef_content_browser_overlay_manifest.h"
|
|
#include "libcef/common/service_manifests/cef_content_gpu_overlay_manifest.h"
|
|
#include "libcef/common/service_manifests/cef_content_renderer_overlay_manifest.h"
|
|
#include "libcef/common/service_manifests/cef_content_utility_overlay_manifest.h"
|
|
#include "libcef/common/service_manifests/cef_packaged_service_manifests.h"
|
|
#include "libcef/common/service_manifests/cef_renderer_manifest.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/browser_process.h"
|
|
#include "chrome/browser/chrome_service.h"
|
|
#include "chrome/browser/net/system_network_context_manager.h"
|
|
#include "chrome/browser/plugins/plugin_info_host_impl.h"
|
|
#include "chrome/browser/profiles/profile.h"
|
|
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
|
|
#include "chrome/common/chrome_paths.h"
|
|
#include "chrome/common/chrome_switches.h"
|
|
#include "chrome/common/constants.mojom.h"
|
|
#include "chrome/grit/browser_resources.h"
|
|
#include "chrome/grit/generated_resources.h"
|
|
#include "chrome/services/printing/public/mojom/constants.mojom.h"
|
|
#include "components/navigation_interception/intercept_navigation_throttle.h"
|
|
#include "components/navigation_interception/navigation_params.h"
|
|
#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
|
|
#include "components/version_info/version_info.h"
|
|
#include "content/browser/frame_host/navigation_handle_impl.h"
|
|
#include "content/browser/frame_host/render_frame_host_impl.h"
|
|
#include "content/browser/plugin_service_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/child_process_security_policy.h"
|
|
#include "content/public/browser/client_certificate_delegate.h"
|
|
#include "content/public/browser/navigation_handle.h"
|
|
#include "content/public/browser/page_navigator.h"
|
|
#include "content/public/browser/quota_permission_context.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/resource_dispatcher_host.h"
|
|
#include "content/public/browser/storage_partition.h"
|
|
#include "content/public/common/content_switches.h"
|
|
#include "content/public/common/service_names.mojom.h"
|
|
#include "content/public/common/storage_quota_params.h"
|
|
#include "content/public/common/user_agent.h"
|
|
#include "content/public/common/web_preferences.h"
|
|
#include "extensions/browser/extension_message_filter.h"
|
|
#include "extensions/browser/extension_protocols.h"
|
|
#include "extensions/browser/extension_registry.h"
|
|
#include "extensions/browser/extensions_browser_client.h"
|
|
#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
|
|
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
|
|
#include "extensions/browser/io_thread_extension_message_filter.h"
|
|
#include "extensions/common/constants.h"
|
|
#include "extensions/common/switches.h"
|
|
#include "net/ssl/ssl_cert_request_info.h"
|
|
#include "ppapi/host/ppapi_host.h"
|
|
#include "services/network/public/cpp/network_switches.h"
|
|
#include "services/service_manager/embedder/switches.h"
|
|
#include "services/service_manager/public/mojom/connector.mojom.h"
|
|
#include "services/service_manager/sandbox/switches.h"
|
|
#include "storage/browser/quota/quota_settings.h"
|
|
#include "third_party/blink/public/web/web_window_features.h"
|
|
#include "third_party/widevine/cdm/buildflags.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 defined(OS_LINUX)
|
|
#include "libcef/common/widevine_loader.h"
|
|
#endif
|
|
|
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
|
#include "base/debug/leak_annotations.h"
|
|
#include "chrome/common/chrome_paths.h"
|
|
#include "components/crash/content/app/breakpad_linux.h"
|
|
#include "components/crash/content/browser/crash_handler_host_linux.h"
|
|
#include "content/public/common/content_descriptors.h"
|
|
#endif
|
|
|
|
#if defined(OS_MACOSX)
|
|
#include "services/audio/public/mojom/constants.mojom.h"
|
|
#include "services/video_capture/public/mojom/constants.mojom.h"
|
|
#endif
|
|
|
|
#if defined(OS_WIN)
|
|
#include "sandbox/win/src/sandbox_policy.h"
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
class CefQuotaCallbackImpl : public CefRequestCallback {
|
|
public:
|
|
explicit CefQuotaCallbackImpl(
|
|
const content::QuotaPermissionContext::PermissionCallback& callback)
|
|
: callback_(callback) {}
|
|
|
|
~CefQuotaCallbackImpl() {
|
|
if (!callback_.is_null()) {
|
|
// The callback is still pending. Cancel it now.
|
|
if (CEF_CURRENTLY_ON_IOT()) {
|
|
RunNow(callback_, false);
|
|
} else {
|
|
CEF_POST_TASK(CEF_IOT, base::Bind(&CefQuotaCallbackImpl::RunNow,
|
|
callback_, false));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Continue(bool allow) override {
|
|
if (CEF_CURRENTLY_ON_IOT()) {
|
|
if (!callback_.is_null()) {
|
|
RunNow(callback_, allow);
|
|
callback_.Reset();
|
|
}
|
|
} else {
|
|
CEF_POST_TASK(CEF_IOT,
|
|
base::Bind(&CefQuotaCallbackImpl::Continue, this, allow));
|
|
}
|
|
}
|
|
|
|
void Cancel() override { Continue(false); }
|
|
|
|
void Disconnect() { callback_.Reset(); }
|
|
|
|
private:
|
|
static void RunNow(
|
|
const content::QuotaPermissionContext::PermissionCallback& callback,
|
|
bool allow) {
|
|
CEF_REQUIRE_IOT();
|
|
callback.Run(
|
|
allow ? content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW
|
|
: content::QuotaPermissionContext::
|
|
QUOTA_PERMISSION_RESPONSE_DISALLOW);
|
|
}
|
|
|
|
content::QuotaPermissionContext::PermissionCallback callback_;
|
|
|
|
IMPLEMENT_REFCOUNTING(CefQuotaCallbackImpl);
|
|
DISALLOW_COPY_AND_ASSIGN(CefQuotaCallbackImpl);
|
|
};
|
|
|
|
class CefAllowCertificateErrorCallbackImpl : public CefRequestCallback {
|
|
public:
|
|
typedef base::Callback<void(content::CertificateRequestResultType)>
|
|
CallbackType;
|
|
|
|
explicit CefAllowCertificateErrorCallbackImpl(const CallbackType& callback)
|
|
: callback_(callback) {}
|
|
|
|
~CefAllowCertificateErrorCallbackImpl() {
|
|
if (!callback_.is_null()) {
|
|
// The callback is still pending. Cancel it now.
|
|
if (CEF_CURRENTLY_ON_UIT()) {
|
|
RunNow(callback_, false);
|
|
} else {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::Bind(&CefAllowCertificateErrorCallbackImpl::RunNow,
|
|
callback_, false));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Continue(bool allow) override {
|
|
if (CEF_CURRENTLY_ON_UIT()) {
|
|
if (!callback_.is_null()) {
|
|
RunNow(callback_, allow);
|
|
callback_.Reset();
|
|
}
|
|
} else {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::Bind(&CefAllowCertificateErrorCallbackImpl::Continue,
|
|
this, allow));
|
|
}
|
|
}
|
|
|
|
void Cancel() override { Continue(false); }
|
|
|
|
void Disconnect() { callback_.Reset(); }
|
|
|
|
private:
|
|
static void RunNow(const CallbackType& callback, bool allow) {
|
|
CEF_REQUIRE_UIT();
|
|
callback.Run(allow ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE
|
|
: content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
|
|
}
|
|
|
|
CallbackType callback_;
|
|
|
|
IMPLEMENT_REFCOUNTING(CefAllowCertificateErrorCallbackImpl);
|
|
DISALLOW_COPY_AND_ASSIGN(CefAllowCertificateErrorCallbackImpl);
|
|
};
|
|
|
|
class CefSelectClientCertificateCallbackImpl
|
|
: public CefSelectClientCertificateCallback {
|
|
public:
|
|
explicit CefSelectClientCertificateCallbackImpl(
|
|
std::unique_ptr<content::ClientCertificateDelegate> delegate)
|
|
: delegate_(std::move(delegate)) {}
|
|
|
|
~CefSelectClientCertificateCallbackImpl() {
|
|
// If Select has not been called, call it with NULL to continue without any
|
|
// client certificate.
|
|
if (delegate_)
|
|
DoSelect(NULL);
|
|
}
|
|
|
|
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::Bind(&CefSelectClientCertificateCallbackImpl::RunNow,
|
|
base::Passed(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::Bind(&CefSelectClientCertificateCallbackImpl::RunWithPrivateKey,
|
|
base::Passed(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);
|
|
DISALLOW_COPY_AND_ASSIGN(CefSelectClientCertificateCallbackImpl);
|
|
};
|
|
|
|
class CefQuotaPermissionContext : public content::QuotaPermissionContext {
|
|
public:
|
|
CefQuotaPermissionContext() {}
|
|
|
|
// The callback will be dispatched on the IO thread.
|
|
void RequestQuotaPermission(const content::StorageQuotaParams& params,
|
|
int render_process_id,
|
|
const PermissionCallback& callback) override {
|
|
if (params.storage_type != blink::mojom::StorageType::kPersistent) {
|
|
// To match Chrome behavior we only support requesting quota with this
|
|
// interface for Persistent storage type.
|
|
callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
|
|
return;
|
|
}
|
|
|
|
bool handled = false;
|
|
|
|
CefRefPtr<CefBrowserHostImpl> browser =
|
|
CefBrowserHostImpl::GetBrowserForFrame(render_process_id,
|
|
params.render_frame_id);
|
|
if (browser.get()) {
|
|
CefRefPtr<CefClient> client = browser->GetClient();
|
|
if (client.get()) {
|
|
CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefQuotaCallbackImpl> callbackImpl(
|
|
new CefQuotaCallbackImpl(callback));
|
|
handled = handler->OnQuotaRequest(
|
|
browser.get(), params.origin_url.spec(), params.requested_size,
|
|
callbackImpl.get());
|
|
if (!handled)
|
|
callbackImpl->Disconnect();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!handled) {
|
|
// Disallow the request by default.
|
|
callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
|
|
}
|
|
}
|
|
|
|
private:
|
|
~CefQuotaPermissionContext() override {}
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CefQuotaPermissionContext);
|
|
};
|
|
|
|
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
|
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
|
|
const std::string& process_type) {
|
|
base::FilePath dumps_path;
|
|
base::PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
|
|
{
|
|
ANNOTATE_SCOPED_MEMORY_LEAK;
|
|
// Uploads will only occur if a non-empty crash URL is specified in
|
|
// CefMainDelegate::InitCrashReporter.
|
|
breakpad::CrashHandlerHostLinux* crash_handler =
|
|
new breakpad::CrashHandlerHostLinux(process_type, dumps_path,
|
|
true /* upload */);
|
|
crash_handler->StartUploaderThread();
|
|
return crash_handler;
|
|
}
|
|
}
|
|
|
|
int GetCrashSignalFD(const base::CommandLine& command_line) {
|
|
if (!breakpad::IsCrashReporterEnabled())
|
|
return -1;
|
|
|
|
// Extensions have the same process type as renderers.
|
|
if (command_line.HasSwitch(extensions::switches::kExtensionProcess)) {
|
|
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
|
|
if (!crash_handler)
|
|
crash_handler = CreateCrashHandlerHost("extension");
|
|
return crash_handler->GetDeathSignalSocket();
|
|
}
|
|
|
|
std::string process_type =
|
|
command_line.GetSwitchValueASCII(switches::kProcessType);
|
|
|
|
if (process_type == switches::kRendererProcess) {
|
|
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
|
|
if (!crash_handler)
|
|
crash_handler = CreateCrashHandlerHost(process_type);
|
|
return crash_handler->GetDeathSignalSocket();
|
|
}
|
|
|
|
if (process_type == switches::kPpapiPluginProcess) {
|
|
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
|
|
if (!crash_handler)
|
|
crash_handler = CreateCrashHandlerHost(process_type);
|
|
return crash_handler->GetDeathSignalSocket();
|
|
}
|
|
|
|
if (process_type == switches::kGpuProcess) {
|
|
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
|
|
if (!crash_handler)
|
|
crash_handler = CreateCrashHandlerHost(process_type);
|
|
return crash_handler->GetDeathSignalSocket();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
|
|
|
|
// TODO(cef): We can't currently trust NavigationParams::is_main_frame() because
|
|
// it's always set to true in
|
|
// InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation. Remove the
|
|
// |is_main_frame| argument once this problem is fixed.
|
|
bool NavigationOnUIThread(
|
|
bool is_main_frame,
|
|
int64 frame_id,
|
|
int64 parent_frame_id,
|
|
content::WebContents* source,
|
|
const navigation_interception::NavigationParams& params) {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
bool ignore_navigation = false;
|
|
|
|
CefRefPtr<CefBrowserHostImpl> browser =
|
|
CefBrowserHostImpl::GetBrowserForContents(source);
|
|
if (browser.get()) {
|
|
CefRefPtr<CefClient> client = browser->GetClient();
|
|
if (client.get()) {
|
|
CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefFrame> frame;
|
|
if (is_main_frame) {
|
|
frame = browser->GetMainFrame();
|
|
} else if (frame_id >= 0) {
|
|
frame = browser->GetFrame(frame_id);
|
|
DCHECK(frame);
|
|
} else {
|
|
// Create a temporary frame object for navigation of sub-frames that
|
|
// don't yet exist.
|
|
frame = new CefFrameHostImpl(
|
|
browser.get(), CefFrameHostImpl::kInvalidFrameId, false,
|
|
CefString(), CefString(), parent_frame_id);
|
|
}
|
|
|
|
CefRefPtr<CefRequestImpl> request = new CefRequestImpl();
|
|
request->Set(params, is_main_frame);
|
|
request->SetReadOnly(true);
|
|
|
|
// Initiating a new navigation in OnBeforeBrowse will delete the
|
|
// InterceptNavigationThrottle that currently owns this callback,
|
|
// resulting in a crash. Use the lock to prevent that.
|
|
std::unique_ptr<CefBrowserHostImpl::NavigationLock> navigation_lock =
|
|
browser->CreateNavigationLock();
|
|
ignore_navigation = handler->OnBeforeBrowse(
|
|
browser.get(), frame, request.get(), params.has_user_gesture(),
|
|
params.is_redirect());
|
|
}
|
|
}
|
|
}
|
|
|
|
return ignore_navigation;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
CefContentBrowserClient::CefContentBrowserClient() : browser_main_parts_(NULL) {
|
|
plugin_service_filter_.reset(new CefPluginServiceFilter);
|
|
content::PluginServiceImpl::GetInstance()->SetFilter(
|
|
plugin_service_filter_.get());
|
|
}
|
|
|
|
CefContentBrowserClient::~CefContentBrowserClient() {}
|
|
|
|
// static
|
|
CefContentBrowserClient* CefContentBrowserClient::Get() {
|
|
if (!CefContentClient::Get())
|
|
return nullptr;
|
|
return static_cast<CefContentBrowserClient*>(
|
|
CefContentClient::Get()->browser());
|
|
}
|
|
|
|
content::BrowserMainParts* CefContentBrowserClient::CreateBrowserMainParts(
|
|
const content::MainFunctionParams& parameters) {
|
|
browser_main_parts_ = new CefBrowserMainParts(parameters);
|
|
browser_main_parts_->AddParts(
|
|
ChromeService::GetInstance()->CreateExtraParts());
|
|
return browser_main_parts_;
|
|
}
|
|
|
|
void CefContentBrowserClient::RenderProcessWillLaunch(
|
|
content::RenderProcessHost* host,
|
|
service_manager::mojom::ServiceRequest* service_request) {
|
|
const int id = host->GetID();
|
|
Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
|
|
|
|
host->AddFilter(new CefBrowserMessageFilter(id));
|
|
host->AddFilter(new printing::CefPrintingMessageFilter(id, profile));
|
|
|
|
if (extensions::ExtensionsEnabled()) {
|
|
host->AddFilter(new extensions::ExtensionMessageFilter(id, profile));
|
|
host->AddFilter(
|
|
new extensions::IOThreadExtensionMessageFilter(id, profile));
|
|
host->AddFilter(
|
|
new extensions::ExtensionsGuestViewMessageFilter(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());
|
|
|
|
host->Send(
|
|
new CefProcessMsg_SetIsIncognitoProcess(profile->IsOffTheRecord()));
|
|
|
|
service_manager::mojom::ServicePtr service;
|
|
*service_request = mojo::MakeRequest(&service);
|
|
service_manager::mojom::PIDReceiverPtr pid_receiver;
|
|
service_manager::Identity renderer_identity = host->GetChildIdentity();
|
|
ChromeService::GetInstance()->connector()->RegisterServiceInstance(
|
|
service_manager::Identity(chrome::mojom::kRendererServiceName,
|
|
renderer_identity.instance_group(),
|
|
renderer_identity.instance_id(),
|
|
base::Token::CreateRandom()),
|
|
std::move(service), mojo::MakeRequest(&pid_receiver));
|
|
}
|
|
|
|
bool CefContentBrowserClient::ShouldUseProcessPerSite(
|
|
content::BrowserContext* browser_context,
|
|
const GURL& effective_url) {
|
|
if (!extensions::ExtensionsEnabled())
|
|
return false;
|
|
|
|
if (!effective_url.SchemeIs(extensions::kExtensionScheme))
|
|
return false;
|
|
|
|
extensions::ExtensionRegistry* registry =
|
|
extensions::ExtensionRegistry::Get(browser_context);
|
|
if (!registry)
|
|
return false;
|
|
|
|
const extensions::Extension* extension =
|
|
registry->enabled_extensions().GetByID(effective_url.host());
|
|
if (!extension)
|
|
return false;
|
|
|
|
// TODO(extensions): Extra checks required if type is TYPE_HOSTED_APP.
|
|
|
|
// Hosted apps that have script access to their background page must use
|
|
// process per site, since all instances can make synchronous calls to the
|
|
// background window. Other extensions should use process per site as well.
|
|
return true;
|
|
}
|
|
|
|
// Based on
|
|
// ChromeContentBrowserClientExtensionsPart::DoesSiteRequireDedicatedProcess.
|
|
bool CefContentBrowserClient::DoesSiteRequireDedicatedProcess(
|
|
content::BrowserContext* browser_context,
|
|
const GURL& effective_site_url) {
|
|
if (!extensions::ExtensionsEnabled())
|
|
return false;
|
|
|
|
extensions::ExtensionRegistry* registry =
|
|
extensions::ExtensionRegistry::Get(browser_context);
|
|
const extensions::Extension* extension =
|
|
registry->enabled_extensions().GetExtensionOrAppByURL(effective_site_url);
|
|
if (!extension)
|
|
return false;
|
|
|
|
// Always isolate Chrome Web Store.
|
|
if (extension->id() == extensions::kWebStoreAppId)
|
|
return true;
|
|
|
|
// Extensions should be isolated, except for hosted apps. Isolating hosted
|
|
// apps is a good idea, but ought to be a separate knob.
|
|
if (extension->is_hosted_app())
|
|
return false;
|
|
|
|
// Isolate all extensions.
|
|
return true;
|
|
}
|
|
|
|
bool CefContentBrowserClient::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 CefContentClient::Get()->HasCustomScheme(scheme);
|
|
}
|
|
|
|
void CefContentBrowserClient::SiteInstanceGotProcess(
|
|
content::SiteInstance* site_instance) {
|
|
if (!extensions::ExtensionsEnabled())
|
|
return;
|
|
|
|
// If this isn't an extension renderer there's nothing to do.
|
|
const extensions::Extension* extension = GetExtension(site_instance);
|
|
if (!extension)
|
|
return;
|
|
|
|
CefBrowserContext* browser_context =
|
|
static_cast<CefBrowserContext*>(site_instance->GetBrowserContext());
|
|
|
|
extensions::ProcessMap::Get(browser_context)
|
|
->Insert(extension->id(), site_instance->GetProcess()->GetID(),
|
|
site_instance->GetId());
|
|
|
|
CEF_POST_TASK(
|
|
CEF_IOT, base::Bind(&extensions::InfoMap::RegisterExtensionProcess,
|
|
browser_context->extension_system()->info_map(),
|
|
extension->id(), site_instance->GetProcess()->GetID(),
|
|
site_instance->GetId()));
|
|
}
|
|
|
|
void CefContentBrowserClient::SiteInstanceDeleting(
|
|
content::SiteInstance* site_instance) {
|
|
if (!extensions::ExtensionsEnabled())
|
|
return;
|
|
|
|
// May be NULL during shutdown.
|
|
if (!extensions::ExtensionsBrowserClient::Get())
|
|
return;
|
|
|
|
// May be NULL during shutdown.
|
|
if (!site_instance->HasProcess())
|
|
return;
|
|
|
|
// If this isn't an extension renderer there's nothing to do.
|
|
const extensions::Extension* extension = GetExtension(site_instance);
|
|
if (!extension)
|
|
return;
|
|
|
|
CefBrowserContext* browser_context =
|
|
static_cast<CefBrowserContext*>(site_instance->GetBrowserContext());
|
|
|
|
extensions::ProcessMap::Get(browser_context)
|
|
->Remove(extension->id(), site_instance->GetProcess()->GetID(),
|
|
site_instance->GetId());
|
|
|
|
CEF_POST_TASK(
|
|
CEF_IOT, base::Bind(&extensions::InfoMap::UnregisterExtensionProcess,
|
|
browser_context->extension_system()->info_map(),
|
|
extension->id(), site_instance->GetProcess()->GetID(),
|
|
site_instance->GetId()));
|
|
}
|
|
|
|
void CefContentBrowserClient::RegisterIOThreadServiceHandlers(
|
|
content::ServiceManagerConnection* connection) {
|
|
// For spell checking.
|
|
connection->AddServiceRequestHandler(
|
|
chrome::mojom::kServiceName,
|
|
ChromeService::GetInstance()->CreateChromeServiceRequestHandler());
|
|
}
|
|
|
|
void CefContentBrowserClient::RegisterOutOfProcessServices(
|
|
OutOfProcessServiceMap* services) {
|
|
(*services)[printing::mojom::kServiceName] =
|
|
base::BindRepeating(&base::ASCIIToUTF16, "PDF Compositor Service");
|
|
(*services)[printing::mojom::kChromePrintingServiceName] =
|
|
base::BindRepeating(&base::ASCIIToUTF16, "Printing Service");
|
|
(*services)[proxy_resolver::mojom::kProxyResolverServiceName] =
|
|
base::BindRepeating(&l10n_util::GetStringUTF16,
|
|
IDS_UTILITY_PROCESS_PROXY_RESOLVER_NAME);
|
|
}
|
|
|
|
base::Optional<service_manager::Manifest>
|
|
CefContentBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
|
|
if (name == content::mojom::kBrowserServiceName) {
|
|
return GetCefContentBrowserOverlayManifest();
|
|
} else if (name == content::mojom::kGpuServiceName) {
|
|
return GetCefContentGpuOverlayManifest();
|
|
} else if (name == content::mojom::kPackagedServicesServiceName) {
|
|
service_manager::Manifest overlay;
|
|
overlay.packaged_services = GetCefPackagedServiceManifests();
|
|
return overlay;
|
|
} else if (name == content::mojom::kRendererServiceName) {
|
|
return GetCefContentRendererOverlayManifest();
|
|
} else if (name == content::mojom::kUtilityServiceName) {
|
|
return GetCefContentUtilityOverlayManifest();
|
|
}
|
|
|
|
return base::nullopt;
|
|
}
|
|
|
|
std::vector<service_manager::Manifest>
|
|
CefContentBrowserClient::GetExtraServiceManifests() {
|
|
return std::vector<service_manager::Manifest>{GetCefRendererManifest()};
|
|
}
|
|
|
|
void CefContentBrowserClient::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 defined(OS_MACOSX)
|
|
switches::kFrameworkDirPath,
|
|
#endif
|
|
switches::kLocalesDirPath,
|
|
switches::kLogFile,
|
|
switches::kLogSeverity,
|
|
switches::kProductVersion,
|
|
switches::kResourcesDirPath,
|
|
switches::kUserAgent,
|
|
};
|
|
command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
|
|
base::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::kDisablePlugins,
|
|
switches::kDisableScrollBounce,
|
|
switches::kDisableSpellChecking,
|
|
switches::kEnableSpeechInput,
|
|
switches::kEnableSystemFlash,
|
|
switches::kPpapiFlashArgs,
|
|
switches::kPpapiFlashPath,
|
|
switches::kPpapiFlashVersion,
|
|
switches::kUncaughtExceptionStackSize,
|
|
network::switches::kUnsafelyTreatInsecureOriginAsSecure,
|
|
};
|
|
command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
|
|
base::size(kSwitchNames));
|
|
|
|
if (extensions::ExtensionsEnabled()) {
|
|
// Based on ChromeContentBrowserClientExtensionsPart::
|
|
// AppendExtraRendererCommandLineSwitches
|
|
content::RenderProcessHost* process =
|
|
content::RenderProcessHost::FromID(child_process_id);
|
|
content::BrowserContext* browser_context =
|
|
process ? process->GetBrowserContext() : NULL;
|
|
if (browser_context && 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,
|
|
base::size(kSwitchNames));
|
|
}
|
|
|
|
#if defined(OS_LINUX)
|
|
if (process_type == service_manager::switches::kZygoteProcess) {
|
|
// 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::kPpapiFlashPath,
|
|
switches::kPpapiFlashVersion,
|
|
};
|
|
command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
|
|
base::size(kSwitchNames));
|
|
|
|
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
|
|
if (!browser_cmd->HasSwitch(service_manager::switches::kNoSandbox)) {
|
|
// Pass the Widevine CDM path to the Zygote process. See comments in
|
|
// CefWidevineLoader::AddContentDecryptionModules.
|
|
const base::FilePath& cdm_path = CefWidevineLoader::GetInstance()->path();
|
|
if (!cdm_path.empty())
|
|
command_line->AppendSwitchPath(switches::kWidevineCdmPath, cdm_path);
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
}
|
|
#endif // defined(OS_LINUX)
|
|
|
|
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
|
|
if (app.get()) {
|
|
CefRefPtr<CefBrowserProcessHandler> handler =
|
|
app->GetBrowserProcessHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefCommandLineImpl> commandLinePtr(
|
|
new CefCommandLineImpl(command_line, false, false));
|
|
handler->OnBeforeChildProcessLaunch(commandLinePtr.get());
|
|
commandLinePtr->Detach(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CefContentBrowserClient::AdjustUtilityServiceProcessCommandLine(
|
|
const service_manager::Identity& identity,
|
|
base::CommandLine* command_line) {
|
|
#if defined(OS_MACOSX)
|
|
// On Mac, the video-capture and audio services require a CFRunLoop, provided
|
|
// by a UI message loop, to run AVFoundation and CoreAudio code.
|
|
// See https://crbug.com/834581
|
|
if (identity.name() == video_capture::mojom::kServiceName ||
|
|
identity.name() == audio::mojom::kServiceName)
|
|
command_line->AppendSwitch(switches::kMessageLoopTypeUi);
|
|
#endif
|
|
}
|
|
|
|
bool CefContentBrowserClient::ShouldEnableStrictSiteIsolation() {
|
|
// TODO(cef): Enable this mode once we figure out why it breaks ceftests that
|
|
// rely on command-line arguments passed to the renderer process. It looks
|
|
// like the first renderer process is getting all of the callbacks despite
|
|
// multiple renderer processes being launched.
|
|
// For example, V8RendererTest::OnBrowserCreated appears to get the same
|
|
// kV8TestCmdArg value twice when running with:
|
|
// --gtest_filter=V8Test.ContextEvalCspBypassUnsafeEval:V8Test.ContextEntered
|
|
return false;
|
|
}
|
|
|
|
std::string CefContentBrowserClient::GetApplicationLocale() {
|
|
return g_browser_process->GetApplicationLocale();
|
|
}
|
|
|
|
scoped_refptr<network::SharedURLLoaderFactory>
|
|
CefContentBrowserClient::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*
|
|
CefContentBrowserClient::GetSystemNetworkContext() {
|
|
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
|
DCHECK(SystemNetworkContextManager::GetInstance());
|
|
return SystemNetworkContextManager::GetInstance()->GetContext();
|
|
}
|
|
|
|
content::QuotaPermissionContext*
|
|
CefContentBrowserClient::CreateQuotaPermissionContext() {
|
|
return new CefQuotaPermissionContext();
|
|
}
|
|
|
|
void CefContentBrowserClient::GetQuotaSettings(
|
|
content::BrowserContext* context,
|
|
content::StoragePartition* partition,
|
|
storage::OptionalQuotaSettingsCallback callback) {
|
|
const base::FilePath& cache_path = partition->GetPath();
|
|
storage::GetNominalDynamicSettings(
|
|
cache_path, cache_path.empty() /* is_incognito */,
|
|
storage::GetDefaultDiskInfoHelper(), std::move(callback));
|
|
}
|
|
|
|
content::MediaObserver* CefContentBrowserClient::GetMediaObserver() {
|
|
return CefMediaCaptureDevicesDispatcher::GetInstance();
|
|
}
|
|
|
|
content::SpeechRecognitionManagerDelegate*
|
|
CefContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
|
|
const base::CommandLine* command_line =
|
|
base::CommandLine::ForCurrentProcess();
|
|
if (command_line->HasSwitch(switches::kEnableSpeechInput))
|
|
return new CefSpeechRecognitionManagerDelegate();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
content::GeneratedCodeCacheSettings
|
|
CefContentBrowserClient::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 CefContentBrowserClient::AllowCertificateError(
|
|
content::WebContents* web_contents,
|
|
int cert_error,
|
|
const net::SSLInfo& ssl_info,
|
|
const GURL& request_url,
|
|
content::ResourceType resource_type,
|
|
bool strict_enforcement,
|
|
bool expired_previous_decision,
|
|
const base::Callback<void(content::CertificateRequestResultType)>&
|
|
callback) {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
if (resource_type != content::ResourceType::RESOURCE_TYPE_MAIN_FRAME) {
|
|
// A sub-resource has a certificate error. The user doesn't really
|
|
// have a context for making the right decision, so block the request
|
|
// hard.
|
|
callback.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
|
|
return;
|
|
}
|
|
|
|
CefRefPtr<CefBrowserHostImpl> browser =
|
|
CefBrowserHostImpl::GetBrowserForContents(web_contents);
|
|
if (!browser.get())
|
|
return;
|
|
CefRefPtr<CefClient> client = browser->GetClient();
|
|
if (!client.get())
|
|
return;
|
|
CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
|
|
if (!handler.get())
|
|
return;
|
|
|
|
CefRefPtr<CefSSLInfo> cef_ssl_info = new CefSSLInfoImpl(ssl_info);
|
|
|
|
CefRefPtr<CefAllowCertificateErrorCallbackImpl> callbackImpl(
|
|
new CefAllowCertificateErrorCallbackImpl(callback));
|
|
|
|
bool proceed = handler->OnCertificateError(
|
|
browser.get(), static_cast<cef_errorcode_t>(cert_error),
|
|
request_url.spec(), cef_ssl_info, callbackImpl.get());
|
|
if (!proceed) {
|
|
callbackImpl->Disconnect();
|
|
callback.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
|
|
}
|
|
}
|
|
|
|
void CefContentBrowserClient::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<CefBrowserHostImpl> browser =
|
|
CefBrowserHostImpl::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;
|
|
}
|
|
|
|
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]);
|
|
}
|
|
}
|
|
|
|
bool CefContentBrowserClient::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 CefContentBrowserClient::ResourceDispatcherHostCreated() {
|
|
resource_dispatcher_host_delegate_.reset(
|
|
new CefResourceDispatcherHostDelegate());
|
|
content::ResourceDispatcherHost::Get()->SetDelegate(
|
|
resource_dispatcher_host_delegate_.get());
|
|
}
|
|
|
|
void CefContentBrowserClient::OverrideWebkitPrefs(
|
|
content::RenderViewHost* rvh,
|
|
content::WebPreferences* prefs) {
|
|
// Using RVH instead of RFH here because rvh->GetMainFrame() may be nullptr
|
|
// when this method is called.
|
|
renderer_prefs::PopulateWebPreferences(rvh, *prefs);
|
|
|
|
if (rvh->GetWidget()->GetView()) {
|
|
rvh->GetWidget()->GetView()->SetBackgroundColor(
|
|
prefs->base_background_color);
|
|
}
|
|
}
|
|
|
|
void CefContentBrowserClient::BrowserURLHandlerCreated(
|
|
content::BrowserURLHandler* handler) {
|
|
scheme::BrowserURLHandlerCreated(handler);
|
|
}
|
|
|
|
std::string CefContentBrowserClient::GetDefaultDownloadName() {
|
|
return "download";
|
|
}
|
|
|
|
void CefContentBrowserClient::DidCreatePpapiPlugin(
|
|
content::BrowserPpapiHost* browser_host) {
|
|
browser_host->GetPpapiHost()->AddHostFactoryFilter(
|
|
std::unique_ptr<ppapi::host::HostFactory>(
|
|
new ChromeBrowserPepperHostFactory(browser_host)));
|
|
}
|
|
|
|
content::DevToolsManagerDelegate*
|
|
CefContentBrowserClient::GetDevToolsManagerDelegate() {
|
|
return new CefDevToolsManagerDelegate();
|
|
}
|
|
|
|
std::vector<std::unique_ptr<content::NavigationThrottle>>
|
|
CefContentBrowserClient::CreateThrottlesForNavigation(
|
|
content::NavigationHandle* navigation_handle) {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
|
|
|
|
const bool is_main_frame = navigation_handle->IsInMainFrame();
|
|
|
|
int64 parent_frame_id = CefFrameHostImpl::kUnspecifiedFrameId;
|
|
if (!is_main_frame) {
|
|
// Identify the RenderFrameHost that originated the navigation.
|
|
content::RenderFrameHost* parent_frame_host =
|
|
navigation_handle->GetParentFrame();
|
|
DCHECK(parent_frame_host);
|
|
if (parent_frame_host)
|
|
parent_frame_id = parent_frame_host->GetRoutingID();
|
|
if (parent_frame_id < 0)
|
|
parent_frame_id = CefFrameHostImpl::kUnspecifiedFrameId;
|
|
}
|
|
|
|
int64 frame_id = CefFrameHostImpl::kInvalidFrameId;
|
|
if (!is_main_frame && navigation_handle->HasCommitted()) {
|
|
frame_id = navigation_handle->GetRenderFrameHost()->GetRoutingID();
|
|
if (frame_id < 0)
|
|
frame_id = CefFrameHostImpl::kInvalidFrameId;
|
|
}
|
|
|
|
// Must use SynchronyMode::kSync to ensure that OnBeforeBrowse is always
|
|
// called before OnBeforeResourceLoad.
|
|
std::unique_ptr<content::NavigationThrottle> throttle =
|
|
std::make_unique<navigation_interception::InterceptNavigationThrottle>(
|
|
navigation_handle,
|
|
base::Bind(&NavigationOnUIThread, is_main_frame, frame_id,
|
|
parent_frame_id),
|
|
navigation_interception::SynchronyMode::kSync);
|
|
throttles.push_back(std::move(throttle));
|
|
|
|
return throttles;
|
|
}
|
|
|
|
#if defined(OS_LINUX)
|
|
void CefContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
|
|
const base::CommandLine& command_line,
|
|
int child_process_id,
|
|
content::PosixFileDescriptorInfo* mappings) {
|
|
int crash_signal_fd = GetCrashSignalFD(command_line);
|
|
if (crash_signal_fd >= 0) {
|
|
mappings->Share(service_manager::kCrashDumpSignal, crash_signal_fd);
|
|
}
|
|
}
|
|
#endif // defined(OS_LINUX)
|
|
|
|
#if defined(OS_WIN)
|
|
const wchar_t* CefContentBrowserClient::GetResourceDllName() {
|
|
static wchar_t file_path[MAX_PATH + 1] = {0};
|
|
|
|
if (file_path[0] == 0) {
|
|
// Retrieve the module path (usually libcef.dll).
|
|
base::FilePath module;
|
|
base::PathService::Get(base::FILE_MODULE, &module);
|
|
const std::wstring wstr = module.value();
|
|
size_t count = std::min(static_cast<size_t>(MAX_PATH), wstr.size());
|
|
wcsncpy(file_path, wstr.c_str(), count);
|
|
file_path[count] = 0;
|
|
}
|
|
|
|
return file_path;
|
|
}
|
|
|
|
bool CefContentBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy* policy) {
|
|
return true;
|
|
}
|
|
#endif // defined(OS_WIN)
|
|
|
|
void CefContentBrowserClient::ExposeInterfacesToRenderer(
|
|
service_manager::BinderRegistry* registry,
|
|
blink::AssociatedInterfaceRegistry* associated_registry,
|
|
content::RenderProcessHost* host) {
|
|
Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
|
|
host->GetChannel()->AddAssociatedInterfaceForIOThread(base::Bind(
|
|
&PluginInfoHostImpl::OnPluginInfoHostRequest,
|
|
base::MakeRefCounted<PluginInfoHostImpl>(host->GetID(), profile)));
|
|
}
|
|
|
|
std::unique_ptr<net::ClientCertStore>
|
|
CefContentBrowserClient::CreateClientCertStore(
|
|
content::ResourceContext* resource_context) {
|
|
if (!resource_context)
|
|
return nullptr;
|
|
return static_cast<CefResourceContext*>(resource_context)
|
|
->CreateClientCertStore();
|
|
}
|
|
|
|
void CefContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
|
|
int frame_tree_node_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(),
|
|
!!extensions::WebViewGuest::FromWebContents(web_contents)));
|
|
}
|
|
|
|
void CefContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
|
int render_process_id,
|
|
int render_frame_id,
|
|
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));
|
|
}
|
|
|
|
bool CefContentBrowserClient::WillCreateURLLoaderFactory(
|
|
content::BrowserContext* browser_context,
|
|
content::RenderFrameHost* frame,
|
|
int render_process_id,
|
|
bool is_navigation,
|
|
bool is_download,
|
|
const url::Origin& request_initiator,
|
|
network::mojom::URLLoaderFactoryRequest* factory_request,
|
|
network::mojom::TrustedURLLoaderHeaderClientPtrInfo* header_client,
|
|
bool* bypass_redirect_checks) {
|
|
if (!net_service::IsEnabled())
|
|
return false;
|
|
|
|
auto request_handler = net_service::CreateInterceptedRequestHandler(
|
|
browser_context, frame, render_process_id, is_navigation, is_download,
|
|
request_initiator);
|
|
|
|
net_service::ProxyURLLoaderFactory::CreateProxy(
|
|
browser_context, factory_request, header_client,
|
|
std::move(request_handler));
|
|
return true;
|
|
}
|
|
|
|
void CefContentBrowserClient::OnNetworkServiceCreated(
|
|
network::mojom::NetworkService* network_service) {
|
|
if (!net_service::IsEnabled())
|
|
return;
|
|
|
|
DCHECK(g_browser_process);
|
|
PrefService* local_state = g_browser_process->local_state();
|
|
DCHECK(local_state);
|
|
|
|
if (!SystemNetworkContextManager::GetInstance()) {
|
|
// TODO(network): This triggers creation of ChromeBrowserPolicyConnector via
|
|
// ChromeBrowserProcessStub::policy_service() which loads some system DLLs
|
|
// on Windows. Determine the correct initialization timing to avoid the need
|
|
// for ScopedAllowIO here.
|
|
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
|
SystemNetworkContextManager::CreateInstance(local_state);
|
|
}
|
|
// Need to set up global NetworkService state before anything else uses it.
|
|
SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated(
|
|
network_service);
|
|
}
|
|
|
|
network::mojom::NetworkContextPtr CefContentBrowserClient::CreateNetworkContext(
|
|
content::BrowserContext* context,
|
|
bool in_memory,
|
|
const base::FilePath& relative_partition_path) {
|
|
Profile* profile = Profile::FromBrowserContext(context);
|
|
return profile->CreateNetworkContext(in_memory, relative_partition_path);
|
|
}
|
|
|
|
// The sandbox may block read/write access from the NetworkService to
|
|
// directories that are not returned by this method.
|
|
std::vector<base::FilePath>
|
|
CefContentBrowserClient::GetNetworkContextsParentDirectory() {
|
|
base::FilePath user_data_path;
|
|
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path);
|
|
DCHECK(!user_data_path.empty());
|
|
|
|
// The CefContext::ValidateCachePath method enforces the requirement that all
|
|
// cache_path values be either equal to or a child of root_cache_path.
|
|
const base::FilePath& root_cache_path =
|
|
base::FilePath(CefString(&CefContext::Get()->settings().root_cache_path));
|
|
|
|
// 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 CefContentBrowserClient::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,
|
|
const std::string& method,
|
|
const net::HttpRequestHeaders& headers,
|
|
network::mojom::URLLoaderFactoryRequest* factory_request,
|
|
network::mojom::URLLoaderFactory*& out_factory) {
|
|
if (net_service::IsEnabled()) {
|
|
// Call the other HandleExternalProtocol variant.
|
|
return false;
|
|
}
|
|
|
|
CefRefPtr<CefRequestImpl> requestPtr = new CefRequestImpl();
|
|
requestPtr->SetURL(url.spec());
|
|
requestPtr->SetMethod(method);
|
|
requestPtr->Set(headers);
|
|
requestPtr->SetReadOnly(true);
|
|
|
|
net_util::HandleExternalProtocol(requestPtr, web_contents_getter);
|
|
return false;
|
|
}
|
|
|
|
bool CefContentBrowserClient::HandleExternalProtocol(
|
|
content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
|
|
int frame_tree_node_id,
|
|
content::NavigationUIData* navigation_data,
|
|
const network::ResourceRequest& request,
|
|
network::mojom::URLLoaderFactoryRequest* factory_request,
|
|
network::mojom::URLLoaderFactory*& out_factory) {
|
|
DCHECK(net_service::IsEnabled());
|
|
// CefBrowserPlatformDelegate::HandleExternalProtocol may be called if
|
|
// nothing handles the request.
|
|
auto request_handler = net_service::CreateInterceptedRequestHandler(
|
|
web_contents_getter, frame_tree_node_id, request);
|
|
out_factory = net_service::ProxyURLLoaderFactory::CreateProxy(
|
|
web_contents_getter, factory_request, std::move(request_handler));
|
|
return true;
|
|
}
|
|
|
|
std::string CefContentBrowserClient::GetProduct() const {
|
|
const base::CommandLine* command_line =
|
|
base::CommandLine::ForCurrentProcess();
|
|
if (command_line->HasSwitch(switches::kProductVersion))
|
|
return command_line->GetSwitchValueASCII(switches::kProductVersion);
|
|
|
|
return GetChromeProduct();
|
|
}
|
|
|
|
std::string CefContentBrowserClient::GetChromeProduct() const {
|
|
return base::StringPrintf("Chrome/%d.%d.%d.%d", CHROME_VERSION_MAJOR,
|
|
CHROME_VERSION_MINOR, CHROME_VERSION_BUILD,
|
|
CHROME_VERSION_PATCH);
|
|
}
|
|
|
|
std::string CefContentBrowserClient::GetUserAgent() const {
|
|
const base::CommandLine* command_line =
|
|
base::CommandLine::ForCurrentProcess();
|
|
if (command_line->HasSwitch(switches::kUserAgent))
|
|
return command_line->GetSwitchValueASCII(switches::kUserAgent);
|
|
|
|
return content::BuildUserAgentFromProduct(GetProduct());
|
|
}
|
|
|
|
blink::UserAgentMetadata CefContentBrowserClient::GetUserAgentMetadata() const {
|
|
blink::UserAgentMetadata metadata;
|
|
|
|
metadata.brand = version_info::GetProductName();
|
|
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;
|
|
}
|
|
|
|
void CefContentBrowserClient::RegisterCustomScheme(const std::string& scheme) {
|
|
// Register as a Web-safe scheme so that requests for the scheme from a
|
|
// render process will be allowed in resource_dispatcher_host_impl.cc
|
|
// ShouldServiceRequest.
|
|
content::ChildProcessSecurityPolicy* policy =
|
|
content::ChildProcessSecurityPolicy::GetInstance();
|
|
if (!policy->IsWebSafeScheme(scheme))
|
|
policy->RegisterWebSafeScheme(scheme);
|
|
}
|
|
|
|
CefRefPtr<CefRequestContextImpl> CefContentBrowserClient::request_context()
|
|
const {
|
|
return browser_main_parts_->request_context();
|
|
}
|
|
|
|
CefDevToolsDelegate* CefContentBrowserClient::devtools_delegate() const {
|
|
return browser_main_parts_->devtools_delegate();
|
|
}
|
|
|
|
scoped_refptr<base::SingleThreadTaskRunner>
|
|
CefContentBrowserClient::background_task_runner() const {
|
|
return browser_main_parts_->background_task_runner();
|
|
}
|
|
|
|
scoped_refptr<base::SingleThreadTaskRunner>
|
|
CefContentBrowserClient::user_visible_task_runner() const {
|
|
return browser_main_parts_->user_visible_task_runner();
|
|
}
|
|
|
|
scoped_refptr<base::SingleThreadTaskRunner>
|
|
CefContentBrowserClient::user_blocking_task_runner() const {
|
|
return browser_main_parts_->user_blocking_task_runner();
|
|
}
|
|
|
|
const extensions::Extension* CefContentBrowserClient::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());
|
|
}
|