From a79981bf7f0d4cbf05a890307f7a7d0c60c81719 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Thu, 8 Feb 2024 16:29:17 -0500 Subject: [PATCH] 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). --- tests/cefclient/browser/root_window.h | 19 +++- tests/cefclient/browser/root_window_gtk.cc | 2 +- tests/cefclient/browser/root_window_mac.mm | 3 +- .../cefclient/browser/root_window_manager.cc | 90 ++++++++++++++----- tests/cefclient/browser/root_window_manager.h | 8 +- tests/cefclient/browser/root_window_views.cc | 22 ++--- tests/cefclient/browser/root_window_win.cc | 2 +- 7 files changed, 98 insertions(+), 48 deletions(-) diff --git a/tests/cefclient/browser/root_window.h b/tests/cefclient/browser/root_window.h index 0a72ad48b..3764b8c3c 100644 --- a/tests/cefclient/browser/root_window.h +++ b/tests/cefclient/browser/root_window.h @@ -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 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 GetRequestContext() = 0; + + using RequestContextCallback = + base::OnceCallback)>; + + // 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 GetImageCache() = 0; diff --git a/tests/cefclient/browser/root_window_gtk.cc b/tests/cefclient/browser/root_window_gtk.cc index 420bc8787..6cf9a6645 100644 --- a/tests/cefclient/browser/root_window_gtk.cc +++ b/tests/cefclient/browser/root_window_gtk.cc @@ -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. diff --git a/tests/cefclient/browser/root_window_mac.mm b/tests/cefclient/browser/root_window_mac.mm index 072566fbf..ad70fe772 100644 --- a/tests/cefclient/browser/root_window_mac.mm +++ b/tests/cefclient/browser/root_window_mac.mm @@ -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. diff --git a/tests/cefclient/browser/root_window_manager.cc b/tests/cefclient/browser/root_window_manager.cc index 520166a23..2c09253ba 100644 --- a/tests/cefclient/browser/root_window_manager.cc +++ b/tests/cefclient/browser/root_window_manager.cc @@ -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 request_context) override { CEF_REQUIRE_UI_THREAD(); + const auto main_context = MainContext::Get(); CefRefPtr 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 RootWindowManager::GetRequestContext( - RootWindow* root_window) { +CefRefPtr 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 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 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_; } diff --git a/tests/cefclient/browser/root_window_manager.h b/tests/cefclient/browser/root_window_manager.h index 42559cd5e..5142b24d2 100644 --- a/tests/cefclient/browser/root_window_manager.h +++ b/tests/cefclient/browser/root_window_manager.h @@ -94,8 +94,8 @@ class RootWindowManager : public RootWindow::Delegate { void NotifyExtensionsChanged(); // RootWindow::Delegate methods. - CefRefPtr GetRequestContext( - RootWindow* root_window) override; + CefRefPtr GetRequestContext() override; + void GetRequestContext(RequestContextCallback callback) override; scoped_refptr 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 CreateRequestContext( + RequestContextCallback callback); + void CleanupOnUIThread(); const bool terminate_when_all_windows_closed_; diff --git a/tests/cefclient/browser/root_window_views.cc b/tests/cefclient/browser/root_window_views.cc index b302abc7c..b61909b5b 100644 --- a/tests/cefclient/browser/root_window_views.cc +++ b/tests/cefclient/browser/root_window_views.cc @@ -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 self, - const CefBrowserSettings& settings) { - // Continue initialization on the UI thread. - self->InitOnUIThread(settings, - self->delegate_->GetRequestContext(self.get())); - }, - scoped_refptr(this), settings)); - } else { - // Continue initialization on the UI thread. - InitOnUIThread(settings, delegate_->GetRequestContext(this)); - } + delegate_->GetRequestContext(base::BindOnce( + [](scoped_refptr self, + const CefBrowserSettings& settings, + CefRefPtr request_context) { + // Continue initialization on the UI thread. + self->InitOnUIThread(settings, request_context); + }, + scoped_refptr(this), settings)); } void RootWindowViews::InitAsPopup(RootWindow::Delegate* delegate, diff --git a/tests/cefclient/browser/root_window_win.cc b/tests/cefclient/browser/root_window_win.cc index 33e46f99b..71d0815e2 100644 --- a/tests/cefclient/browser/root_window_win.cc +++ b/tests/cefclient/browser/root_window_win.cc @@ -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.