chrome: Support client-created request contexts (see issue #2969)

RequestContextTest and URLRequestTest suites now pass with the Chrome runtime
enabled.
This commit is contained in:
Marshall Greenblatt
2021-04-06 18:09:45 -04:00
parent 1cddbeb12f
commit 09fa22898d
23 changed files with 279 additions and 74 deletions

View File

@@ -12,11 +12,13 @@
#include "libcef/browser/request_context_impl.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_switches.h"
#include "libcef/features/runtime.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -229,6 +231,25 @@ CefBrowserContext* CefBrowserContext::FromBrowserContext(
return g_manager.Get().GetImplFromBrowserContext(context);
}
// static
CefBrowserContext* CefBrowserContext::FromProfile(const Profile* profile) {
auto* cef_context = FromBrowserContext(profile);
if (cef_context)
return cef_context;
if (cef::IsChromeRuntimeEnabled()) {
auto* original_profile = profile->GetOriginalProfile();
if (original_profile != profile) {
// With the Chrome runtime if the user launches an incognito window via
// the UI we might be associated with the original Profile instead of the
// (current) incognito profile.
return FromBrowserContext(original_profile);
}
}
return nullptr;
}
// static
std::vector<CefBrowserContext*> CefBrowserContext::GetAll() {
return g_manager.Get().GetAllImpl();

View File

@@ -103,6 +103,7 @@ class CefBrowserContext {
// Returns the underlying CefBrowserContext if any.
static CefBrowserContext* FromBrowserContext(
const content::BrowserContext* context);
static CefBrowserContext* FromProfile(const Profile* profile);
// Returns all existing CefBrowserContext.
static std::vector<CefBrowserContext*> GetAll();

View File

@@ -6,11 +6,11 @@
#include "libcef/browser/prefs/browser_prefs.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/browser_process.h"
ChromeBrowserContext::ChromeBrowserContext(
const CefRequestContextSettings& settings)
: CefBrowserContext(settings) {}
: CefBrowserContext(settings), weak_ptr_factory_(this) {}
ChromeBrowserContext::~ChromeBrowserContext() = default;
@@ -22,19 +22,73 @@ Profile* ChromeBrowserContext::AsProfile() {
return profile_;
}
void ChromeBrowserContext::Initialize() {
void ChromeBrowserContext::InitializeAsync(base::OnceClosure initialized_cb) {
initialized_cb_ = std::move(initialized_cb);
CefBrowserContext::Initialize();
// TODO(chrome-runtime): ProfileManager can create new profiles relative to
// the user-data-dir, but it should be done asynchronously.
// The global ProfileManager instance can be retrieved via
// |g_browser_process->profile_manager()|.
profile_ = ProfileManager::GetLastUsedProfileAllowedByPolicy();
if (!cache_path_.empty()) {
auto* profile_manager = g_browser_process->profile_manager();
const auto& user_data_dir = profile_manager->user_data_dir();
browser_prefs::SetLanguagePrefs(profile_);
if (cache_path_ == user_data_dir) {
// Use the default disk-based profile.
ProfileCreated(profile_manager->GetActiveUserProfile(),
Profile::CreateStatus::CREATE_STATUS_INITIALIZED);
return;
} else if (cache_path_.DirName() == user_data_dir) {
// Create or load a specific disk-based profile. May continue
// synchronously or asynchronously.
profile_manager->CreateProfileAsync(
cache_path_,
base::Bind(&ChromeBrowserContext::ProfileCreated,
weak_ptr_factory_.GetWeakPtr()),
/*name=*/base::string16(), /*icon_url=*/std::string());
return;
} else {
// All profile directories must be relative to |user_data_dir|.
LOG(ERROR) << "Cannot create profile at path "
<< cache_path_.AsUTF8Unsafe();
}
}
// Default to creating a new/unique OffTheRecord profile.
ProfileCreated(nullptr, Profile::CreateStatus::CREATE_STATUS_CANCELED);
}
void ChromeBrowserContext::Shutdown() {
CefBrowserContext::Shutdown();
// |g_browser_process| may be nullptr during shutdown.
if (should_destroy_ && g_browser_process) {
g_browser_process->profile_manager()
->GetActiveUserProfile()
->DestroyOffTheRecordProfile(profile_);
}
profile_ = nullptr;
}
void ChromeBrowserContext::ProfileCreated(Profile* profile,
Profile::CreateStatus status) {
if (status != Profile::CreateStatus::CREATE_STATUS_CREATED &&
status != Profile::CreateStatus::CREATE_STATUS_INITIALIZED) {
DCHECK(!profile);
// Creation of a disk-based profile failed for some reason. Create a
// new/unique OffTheRecord profile instead.
const auto& profile_id = Profile::OTRProfileID::CreateUniqueForCEF();
profile = g_browser_process->profile_manager()
->GetActiveUserProfile()
->GetOffTheRecordProfile(profile_id);
status = Profile::CreateStatus::CREATE_STATUS_INITIALIZED;
should_destroy_ = true;
}
if (status == Profile::CreateStatus::CREATE_STATUS_INITIALIZED) {
DCHECK(profile);
DCHECK(!profile_);
profile_ = profile;
browser_prefs::SetLanguagePrefs(profile_);
std::move(initialized_cb_).Run();
}
}

View File

@@ -8,22 +8,32 @@
#include "libcef/browser/browser_context.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/profiles/profile_manager.h"
// See CefBrowserContext documentation for usage. Only accessed on the UI thread
// unless otherwise indicated.
class ChromeBrowserContext : public CefBrowserContext {
public:
explicit ChromeBrowserContext(const CefRequestContextSettings& settings);
void InitializeAsync(base::OnceClosure initialized_cb);
// CefBrowserContext overrides.
content::BrowserContext* AsBrowserContext() override;
Profile* AsProfile() override;
void Initialize() override;
void Shutdown() override;
private:
~ChromeBrowserContext() override;
void ProfileCreated(Profile* profile, Profile::CreateStatus status);
base::OnceClosure initialized_cb_;
Profile* profile_ = nullptr;
bool should_destroy_ = false;
base::WeakPtrFactory<ChromeBrowserContext> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ChromeBrowserContext);
};

View File

@@ -175,7 +175,7 @@ bool ChromeContentBrowserClientCef::WillCreateURLLoaderFactory(
// For example, the User Manager profile created via
// profiles::CreateSystemProfileForUserManager.
auto profile = Profile::FromBrowserContext(browser_context);
if (!CefBrowserContext::FromBrowserContext(profile->GetOriginalProfile()))
if (!CefBrowserContext::FromProfile(profile))
return false;
auto request_handler = net_service::CreateInterceptedRequestHandler(

View File

@@ -262,8 +262,7 @@ class InterceptedRequestHandlerWrapper : public InterceptedRequestHandler {
browser_context_ = browser_context;
auto profile = Profile::FromBrowserContext(browser_context);
auto cef_browser_context =
CefBrowserContext::FromBrowserContext(profile->GetOriginalProfile());
auto cef_browser_context = CefBrowserContext::FromProfile(profile);
iothread_state_ = cef_browser_context->iothread_state();
DCHECK(iothread_state_);
cookieable_schemes_ = cef_browser_context->GetCookieableSchemes();

View File

@@ -612,7 +612,19 @@ CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) {
}
// The new context will be initialized later by EnsureBrowserContext().
return new CefRequestContextImpl(config);
CefRefPtr<CefRequestContextImpl> context = new CefRequestContextImpl(config);
if (config.handler) {
// Keep the context alive until OnRequestContextInitialized is called.
if (CEF_CURRENTLY_ON_UIT()) {
context->Initialize();
} else {
CEF_POST_TASK(
CEF_UIT, base::BindOnce(&CefRequestContextImpl::Initialize, context));
}
}
return context;
}
CefRequestContextImpl::CefRequestContextImpl(
@@ -645,16 +657,20 @@ void CefRequestContextImpl::Initialize() {
}
}
auto initialized_cb =
base::BindOnce(&CefRequestContextImpl::BrowserContextInitialized, this);
if (!browser_context_) {
// Create a new CefBrowserContext instance. If the cache path is non-
// empty then this new instance will become the globally registered
// CefBrowserContext for that path. Otherwise, this new instance will
// be a completely isolated "incognito mode" context.
browser_context_ =
CefAppManager::Get()->CreateNewBrowserContext(config_.settings);
browser_context_ = CefAppManager::Get()->CreateNewBrowserContext(
config_.settings, std::move(initialized_cb));
} else {
// Share the same settings as the existing context.
config_.settings = browser_context_->settings();
std::move(initialized_cb).Run();
}
// We'll disassociate from |browser_context_| on destruction.
@@ -666,9 +682,16 @@ void CefRequestContextImpl::Initialize() {
// IsSharedWith().
config_.other = nullptr;
}
}
if (config_.handler)
config_.handler->OnRequestContextInitialized(this);
void CefRequestContextImpl::BrowserContextInitialized() {
if (config_.handler) {
// Always execute asynchronously so the current call stack can unwind.
CEF_POST_TASK(
CEF_UIT,
base::BindOnce(&CefRequestContextHandler::OnRequestContextInitialized,
config_.handler, CefRefPtr<CefRequestContext>(this)));
}
}
void CefRequestContextImpl::EnsureBrowserContext() {

View File

@@ -128,6 +128,7 @@ class CefRequestContextImpl : public CefRequestContext {
explicit CefRequestContextImpl(const Config& config);
void Initialize();
void BrowserContextInitialized();
// Make sure the browser context exists. Only called on the UI thread.
void EnsureBrowserContext();