chrome: cefclient: Add support for --request-context-per-browser

Wait for the OnRequestContextInitialized callback before using a
non-global CefRequestContext.

Use default handling of --load-extension for Chrome runtime (fixes #3529).
This commit is contained in:
Marshall Greenblatt 2024-02-08 16:29:17 -05:00
parent 36e4ef1673
commit b7e35d2878
7 changed files with 98 additions and 48 deletions

View File

@ -96,10 +96,21 @@ class RootWindow
// of this class will be called on the main thread.
class Delegate {
public:
// Called to retrieve the CefRequestContext for browser. Only called for
// non-popup browsers. May return nullptr.
virtual CefRefPtr<CefRequestContext> GetRequestContext(
RootWindow* root_window) = 0;
// Called to synchronously retrieve the CefRequestContext for browser. Only
// called for non-popup browsers. Must be called on the main thread. With
// the Chrome runtime this method is only safe when using the global request
// context.
// TODO: Delete this method and use the async version instead.
virtual CefRefPtr<CefRequestContext> GetRequestContext() = 0;
using RequestContextCallback =
base::OnceCallback<void(CefRefPtr<CefRequestContext>)>;
// Called to asynchronously retrieve the CefRequestContext for browser. Only
// called for non-popup browsers. Save to call on any thread. |callback|
// will be executed on the UI thread after the request context is
// initialized.
virtual void GetRequestContext(RequestContextCallback callback) = 0;
// Returns the ImageCache.
virtual scoped_refptr<ImageCache> GetImageCache() = 0;

View File

@ -443,7 +443,7 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
if (!is_popup_) {
// Create the browser window.
browser_window_->CreateBrowser(parent, browser_bounds_, settings, nullptr,
delegate_->GetRequestContext(this));
delegate_->GetRequestContext());
} else {
// With popups we already have a browser window. Parent the browser window
// to the root window and show it in the correct location.

View File

@ -620,8 +620,7 @@ void RootWindowMacImpl::CreateRootWindow(const CefBrowserSettings& settings,
browser_window_->CreateBrowser(
CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(contentView),
CefRect(0, 0, contentBounds.size.width, contentBounds.size.height),
settings, nullptr,
root_window_.delegate_->GetRequestContext(&root_window_));
settings, nullptr, root_window_.delegate_->GetRequestContext());
} else {
// With popups we already have a browser window. Parent the browser window
// to the root window and show it in the correct location.

View File

@ -8,6 +8,7 @@
#include "include/base/cef_callback.h"
#include "include/base/cef_logging.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "tests/cefclient/browser/client_handler_std.h"
#include "tests/cefclient/browser/main_context.h"
@ -24,36 +25,41 @@ namespace {
class ClientRequestContextHandler : public CefRequestContextHandler,
public CefExtensionHandler {
public:
ClientRequestContextHandler() = default;
using CreateCallback = RootWindow::Delegate::RequestContextCallback;
explicit ClientRequestContextHandler(CreateCallback callback)
: create_callback_(std::move(callback)) {}
// CefRequestContextHandler methods:
void OnRequestContextInitialized(
CefRefPtr<CefRequestContext> request_context) override {
CEF_REQUIRE_UI_THREAD();
const auto main_context = MainContext::Get();
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(switches::kLoadExtension)) {
if (MainContext::Get()
->GetRootWindowManager()
->request_context_per_browser()) {
if (!main_context->UseChromeRuntime() &&
command_line->HasSwitch(switches::kLoadExtension)) {
// Alloy implementation for loading extensions. Chrome runtime handles
// this internally.
if (main_context->GetRootWindowManager()->request_context_per_browser()) {
// The example extension loading implementation requires all browsers to
// share the same request context.
LOG(ERROR)
<< "Cannot mix --load-extension and --request-context-per-browser";
return;
}
// Load one or more extension paths specified on the command-line and
// delimited with semicolon.
const std::string& extension_path =
command_line->GetSwitchValue(switches::kLoadExtension);
if (!extension_path.empty()) {
std::string part;
std::istringstream f(extension_path);
while (getline(f, part, ';')) {
if (!part.empty()) {
extension_util::LoadExtension(request_context, part, this);
} else {
// Load one or more extension paths specified on the command-line and
// delimited with semicolon.
const std::string& extension_path =
command_line->GetSwitchValue(switches::kLoadExtension);
if (!extension_path.empty()) {
std::string part;
std::istringstream f(extension_path);
while (getline(f, part, ';')) {
if (!part.empty()) {
extension_util::LoadExtension(request_context, part, this);
}
}
}
}
@ -67,6 +73,12 @@ class ClientRequestContextHandler : public CefRequestContextHandler,
request_context->SetContentSetting(startup_url, startup_url,
CEF_CONTENT_SETTING_TYPE_POPUPS,
CEF_CONTENT_SETTING_VALUE_ALLOW);
if (!create_callback_.is_null()) {
// Execute the callback asynchronously.
CefPostTask(TID_UI,
base::BindOnce(std::move(create_callback_), request_context));
}
}
// CefExtensionHandler methods:
@ -95,6 +107,8 @@ class ClientRequestContextHandler : public CefRequestContextHandler,
}
private:
CreateCallback create_callback_;
IMPLEMENT_REFCOUNTING(ClientRequestContextHandler);
DISALLOW_COPY_AND_ASSIGN(ClientRequestContextHandler);
};
@ -324,11 +338,33 @@ void RootWindowManager::NotifyExtensionsChanged() {
}
}
CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext(
RootWindow* root_window) {
CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext() {
REQUIRE_MAIN_THREAD();
return CreateRequestContext(RequestContextCallback());
}
void RootWindowManager::GetRequestContext(RequestContextCallback callback) {
DCHECK(!callback.is_null());
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute on the main thread.
MAIN_POST_CLOSURE(base::BindOnce(
base::IgnoreResult(&RootWindowManager::CreateRequestContext),
base::Unretained(this), std::move(callback)));
} else {
CreateRequestContext(std::move(callback));
}
}
CefRefPtr<CefRequestContext> RootWindowManager::CreateRequestContext(
RequestContextCallback callback) {
REQUIRE_MAIN_THREAD();
if (request_context_per_browser_) {
// Synchronous use of non-global request contexts is not safe with the
// Chrome runtime.
CHECK(!callback.is_null() || !MainContext::Get()->UseChromeRuntime());
// Create a new request context for each browser.
CefRequestContextSettings settings;
@ -350,15 +386,21 @@ CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext(
}
}
return CefRequestContext::CreateContext(settings,
new ClientRequestContextHandler);
return CefRequestContext::CreateContext(
settings, new ClientRequestContextHandler(std::move(callback)));
}
// All browsers will share the global request context.
if (!shared_request_context_.get()) {
if (!shared_request_context_) {
shared_request_context_ = CefRequestContext::CreateContext(
CefRequestContext::GetGlobalContext(), new ClientRequestContextHandler);
CefRequestContext::GetGlobalContext(),
new ClientRequestContextHandler(std::move(callback)));
} else if (!callback.is_null()) {
// Execute the callback on the UI thread.
CefPostTask(TID_UI,
base::BindOnce(std::move(callback), shared_request_context_));
}
return shared_request_context_;
}

View File

@ -94,8 +94,8 @@ class RootWindowManager : public RootWindow::Delegate {
void NotifyExtensionsChanged();
// RootWindow::Delegate methods.
CefRefPtr<CefRequestContext> GetRequestContext(
RootWindow* root_window) override;
CefRefPtr<CefRequestContext> GetRequestContext() override;
void GetRequestContext(RequestContextCallback callback) override;
scoped_refptr<ImageCache> GetImageCache() override;
void OnTest(RootWindow* root_window, int test_id) override;
void OnExit(RootWindow* root_window) override;
@ -109,6 +109,10 @@ class RootWindowManager : public RootWindow::Delegate {
base::OnceClosure close_callback,
bool with_osr) override;
// |callback| may be nullptr. Must be called on the main thread.
CefRefPtr<CefRequestContext> CreateRequestContext(
RequestContextCallback callback);
void CleanupOnUIThread();
const bool terminate_when_all_windows_closed_;

View File

@ -58,20 +58,14 @@ void RootWindowViews::Init(RootWindow::Delegate* delegate,
CreateClientHandler(config_->url);
initialized_ = true;
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute GetRequestContext() on the main thread.
MAIN_POST_CLOSURE(base::BindOnce(
[](scoped_refptr<RootWindowViews> self,
const CefBrowserSettings& settings) {
// Continue initialization on the UI thread.
self->InitOnUIThread(settings,
self->delegate_->GetRequestContext(self.get()));
},
scoped_refptr<RootWindowViews>(this), settings));
} else {
// Continue initialization on the UI thread.
InitOnUIThread(settings, delegate_->GetRequestContext(this));
}
delegate_->GetRequestContext(base::BindOnce(
[](scoped_refptr<RootWindowViews> self,
const CefBrowserSettings& settings,
CefRefPtr<CefRequestContext> request_context) {
// Continue initialization on the UI thread.
self->InitOnUIThread(settings, request_context);
},
scoped_refptr<RootWindowViews>(this), settings));
}
void RootWindowViews::InitAsPopup(RootWindow::Delegate* delegate,

View File

@ -1015,7 +1015,7 @@ void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
CefRect cef_rect(rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top);
browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_, nullptr,
delegate_->GetRequestContext(this));
delegate_->GetRequestContext());
} else {
// With popups we already have a browser window. Parent the browser window
// to the root window and show it in the correct location.