416 lines
11 KiB
C++
416 lines
11 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 "cef/libcef/browser/browser_context.h"
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/files/file_util.h"
|
|
#include "base/lazy_instance.h"
|
|
#include "base/logging.h"
|
|
#include "base/no_destructor.h"
|
|
#include "base/strings/string_split.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "cef/libcef/browser/context.h"
|
|
#include "cef/libcef/browser/media_router/media_router_manager.h"
|
|
#include "cef/libcef/browser/request_context_impl.h"
|
|
#include "cef/libcef/browser/thread_util.h"
|
|
#include "cef/libcef/common/cef_switches.h"
|
|
#include "cef/libcef/common/frame_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"
|
|
#include "content/public/browser/storage_partition.h"
|
|
|
|
using content::BrowserThread;
|
|
|
|
namespace {
|
|
|
|
// Manages the global list of Impl instances.
|
|
class ImplManager {
|
|
public:
|
|
using Vector = std::vector<CefBrowserContext*>;
|
|
|
|
ImplManager() = default;
|
|
|
|
ImplManager(const ImplManager&) = delete;
|
|
ImplManager& operator=(const ImplManager&) = delete;
|
|
|
|
~ImplManager() {
|
|
DCHECK(all_.empty());
|
|
DCHECK(map_.empty());
|
|
}
|
|
|
|
void AddImpl(CefBrowserContext* impl) {
|
|
CEF_REQUIRE_UIT();
|
|
DCHECK(!IsValidImpl(impl));
|
|
all_.push_back(impl);
|
|
}
|
|
|
|
void RemoveImpl(CefBrowserContext* impl, const base::FilePath& path) {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
{
|
|
Vector::iterator it = GetImplPos(impl);
|
|
DCHECK(it != all_.end());
|
|
all_.erase(it);
|
|
}
|
|
|
|
if (!path.empty()) {
|
|
PathMap::iterator it = map_.find(path);
|
|
DCHECK(it != map_.end());
|
|
if (it != map_.end()) {
|
|
map_.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool IsValidImpl(const CefBrowserContext* impl) {
|
|
CEF_REQUIRE_UIT();
|
|
return GetImplPos(impl) != all_.end();
|
|
}
|
|
|
|
CefBrowserContext* GetImplFromGlobalId(
|
|
const content::GlobalRenderFrameHostId& global_id,
|
|
bool require_frame_match) {
|
|
CEF_REQUIRE_UIT();
|
|
for (const auto& context : all_) {
|
|
if (context->IsAssociatedContext(global_id, require_frame_match)) {
|
|
return context;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CefBrowserContext* GetImplFromBrowserContext(
|
|
const content::BrowserContext* context) {
|
|
CEF_REQUIRE_UIT();
|
|
if (!context) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (const auto& bc : all_) {
|
|
if (bc->AsBrowserContext() == context) {
|
|
return bc;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void SetImplPath(CefBrowserContext* impl, const base::FilePath& path) {
|
|
CEF_REQUIRE_UIT();
|
|
DCHECK(!path.empty());
|
|
DCHECK(IsValidImpl(impl));
|
|
DCHECK(GetImplFromPath(path) == nullptr);
|
|
map_.insert(std::make_pair(path, impl));
|
|
}
|
|
|
|
CefBrowserContext* GetImplFromPath(const base::FilePath& path) {
|
|
CEF_REQUIRE_UIT();
|
|
DCHECK(!path.empty());
|
|
PathMap::const_iterator it = map_.find(path);
|
|
if (it != map_.end()) {
|
|
return it->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const Vector GetAllImpl() const { return all_; }
|
|
|
|
private:
|
|
Vector::iterator GetImplPos(const CefBrowserContext* impl) {
|
|
Vector::iterator it = all_.begin();
|
|
for (; it != all_.end(); ++it) {
|
|
if (*it == impl) {
|
|
return it;
|
|
}
|
|
}
|
|
return all_.end();
|
|
}
|
|
|
|
using PathMap = std::map<base::FilePath, raw_ptr<CefBrowserContext>>;
|
|
PathMap map_;
|
|
|
|
Vector all_;
|
|
};
|
|
|
|
#if DCHECK_IS_ON()
|
|
// Because of DCHECK()s in the object destructor.
|
|
base::LazyInstance<ImplManager>::DestructorAtExit g_manager =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
#else
|
|
base::LazyInstance<ImplManager>::Leaky g_manager = LAZY_INSTANCE_INITIALIZER;
|
|
#endif
|
|
|
|
CefBrowserContext* GetSelf(base::WeakPtr<CefBrowserContext> self) {
|
|
CEF_REQUIRE_UIT();
|
|
return self.get();
|
|
}
|
|
|
|
CefBrowserContext::CookieableSchemes MakeSupportedSchemes(
|
|
const CefString& schemes_list,
|
|
bool include_defaults) {
|
|
if (schemes_list.empty() && include_defaults) {
|
|
// No explicit registration of schemes.
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::vector<std::string> all_schemes;
|
|
if (!schemes_list.empty()) {
|
|
all_schemes =
|
|
base::SplitString(schemes_list.ToString(), std::string(","),
|
|
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
|
}
|
|
|
|
if (include_defaults) {
|
|
// Add default schemes that should always support cookies.
|
|
// This list should match CookieMonster::kDefaultCookieableSchemes.
|
|
all_schemes.push_back("http");
|
|
all_schemes.push_back("https");
|
|
all_schemes.push_back("ws");
|
|
all_schemes.push_back("wss");
|
|
}
|
|
|
|
return std::make_optional(all_schemes);
|
|
}
|
|
|
|
template <typename T>
|
|
CefBrowserContext::CookieableSchemes MakeSupportedSchemes(const T& settings) {
|
|
return MakeSupportedSchemes(CefString(&settings.cookieable_schemes_list),
|
|
!settings.cookieable_schemes_exclude_defaults);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
CefBrowserContext::CefBrowserContext(const CefRequestContextSettings& settings)
|
|
: settings_(settings), weak_ptr_factory_(this) {
|
|
g_manager.Get().AddImpl(this);
|
|
getter_ = base::BindRepeating(GetSelf, weak_ptr_factory_.GetWeakPtr());
|
|
}
|
|
|
|
CefBrowserContext::~CefBrowserContext() {
|
|
CEF_REQUIRE_UIT();
|
|
#if DCHECK_IS_ON()
|
|
DCHECK(is_shutdown_);
|
|
#endif
|
|
}
|
|
|
|
void CefBrowserContext::Initialize() {
|
|
cache_path_ = base::FilePath(CefString(&settings_.cache_path));
|
|
|
|
if (!cache_path_.empty()) {
|
|
g_manager.Get().SetImplPath(this, cache_path_);
|
|
}
|
|
|
|
iothread_state_ = base::MakeRefCounted<CefIOThreadState>();
|
|
cookieable_schemes_ = MakeSupportedSchemes(settings_);
|
|
}
|
|
|
|
void CefBrowserContext::Shutdown() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
#if DCHECK_IS_ON()
|
|
is_shutdown_ = true;
|
|
#endif
|
|
|
|
// No CefRequestContext should be referencing this object any longer.
|
|
DCHECK(request_context_set_.empty());
|
|
|
|
// Unregister the context first to avoid re-entrancy during shutdown.
|
|
g_manager.Get().RemoveImpl(this, cache_path_);
|
|
|
|
// Destroy objects that may hold references to the MediaRouter.
|
|
media_router_manager_.reset();
|
|
|
|
// Invalidate any Getter references to this object.
|
|
weak_ptr_factory_.InvalidateWeakPtrs();
|
|
}
|
|
|
|
void CefBrowserContext::AddCefRequestContext(CefRequestContextImpl* context) {
|
|
CEF_REQUIRE_UIT();
|
|
request_context_set_.insert(context);
|
|
}
|
|
|
|
void CefBrowserContext::RemoveCefRequestContext(
|
|
CefRequestContextImpl* context) {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
request_context_set_.erase(context);
|
|
|
|
// Delete ourselves when the reference count reaches zero.
|
|
if (request_context_set_.empty()) {
|
|
Shutdown();
|
|
|
|
// Allow the current call stack to unwind before deleting |this|.
|
|
content::BrowserThread::DeleteSoon(CEF_UIT, FROM_HERE, this);
|
|
}
|
|
}
|
|
|
|
// static
|
|
CefBrowserContext* CefBrowserContext::FromCachePath(
|
|
const base::FilePath& cache_path) {
|
|
return g_manager.Get().GetImplFromPath(cache_path);
|
|
}
|
|
|
|
// static
|
|
CefBrowserContext* CefBrowserContext::FromGlobalId(
|
|
const content::GlobalRenderFrameHostId& global_id,
|
|
bool require_frame_match) {
|
|
return g_manager.Get().GetImplFromGlobalId(global_id, require_frame_match);
|
|
}
|
|
|
|
// static
|
|
CefBrowserContext* CefBrowserContext::FromBrowserContext(
|
|
const content::BrowserContext* context) {
|
|
return g_manager.Get().GetImplFromBrowserContext(context);
|
|
}
|
|
|
|
// static
|
|
CefBrowserContext* CefBrowserContext::FromProfile(const Profile* profile) {
|
|
return FromBrowserContext(profile);
|
|
}
|
|
|
|
// static
|
|
std::vector<CefBrowserContext*> CefBrowserContext::GetAll() {
|
|
return g_manager.Get().GetAllImpl();
|
|
}
|
|
|
|
void CefBrowserContext::OnRenderFrameCreated(
|
|
CefRequestContextImpl* request_context,
|
|
const content::GlobalRenderFrameHostId& global_id,
|
|
bool is_main_frame) {
|
|
CEF_REQUIRE_UIT();
|
|
DCHECK(frame_util::IsValidGlobalId(global_id));
|
|
|
|
render_id_set_.insert(global_id);
|
|
|
|
CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
|
|
if (handler) {
|
|
handler_map_.AddHandler(global_id, handler);
|
|
|
|
CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::AddHandler,
|
|
iothread_state_, global_id, handler));
|
|
}
|
|
}
|
|
|
|
void CefBrowserContext::OnRenderFrameDeleted(
|
|
CefRequestContextImpl* request_context,
|
|
const content::GlobalRenderFrameHostId& global_id,
|
|
bool is_main_frame) {
|
|
CEF_REQUIRE_UIT();
|
|
DCHECK(frame_util::IsValidGlobalId(global_id));
|
|
|
|
auto it1 = render_id_set_.find(global_id);
|
|
if (it1 != render_id_set_.end()) {
|
|
render_id_set_.erase(it1);
|
|
}
|
|
|
|
CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
|
|
if (handler) {
|
|
handler_map_.RemoveHandler(global_id);
|
|
|
|
CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::RemoveHandler,
|
|
iothread_state_, global_id));
|
|
}
|
|
}
|
|
|
|
CefRefPtr<CefRequestContextHandler> CefBrowserContext::GetHandler(
|
|
const content::GlobalRenderFrameHostId& global_id,
|
|
bool require_frame_match) const {
|
|
CEF_REQUIRE_UIT();
|
|
return handler_map_.GetHandler(global_id, require_frame_match);
|
|
}
|
|
|
|
bool CefBrowserContext::IsAssociatedContext(
|
|
const content::GlobalRenderFrameHostId& global_id,
|
|
bool require_frame_match) const {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
if (frame_util::IsValidGlobalId(global_id)) {
|
|
const auto it1 = render_id_set_.find(global_id);
|
|
if (it1 != render_id_set_.end()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (frame_util::IsValidChildId(global_id.child_id) && !require_frame_match) {
|
|
// Choose an arbitrary handler for the same process.
|
|
for (const auto& render_ids : render_id_set_) {
|
|
if (render_ids.child_id == global_id.child_id) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CefBrowserContext::RegisterSchemeHandlerFactory(
|
|
const CefString& scheme_name,
|
|
const CefString& domain_name,
|
|
CefRefPtr<CefSchemeHandlerFactory> factory) {
|
|
CEF_POST_TASK(
|
|
CEF_IOT,
|
|
base::BindOnce(&CefIOThreadState::RegisterSchemeHandlerFactory,
|
|
iothread_state_, scheme_name, domain_name, factory));
|
|
}
|
|
|
|
void CefBrowserContext::ClearSchemeHandlerFactories() {
|
|
CEF_POST_TASK(CEF_IOT,
|
|
base::BindOnce(&CefIOThreadState::ClearSchemeHandlerFactories,
|
|
iothread_state_));
|
|
}
|
|
|
|
network::mojom::NetworkContext* CefBrowserContext::GetNetworkContext() {
|
|
CEF_REQUIRE_UIT();
|
|
auto browser_context = AsBrowserContext();
|
|
return browser_context->GetDefaultStoragePartition()->GetNetworkContext();
|
|
}
|
|
|
|
CefMediaRouterManager* CefBrowserContext::GetMediaRouterManager() {
|
|
CEF_REQUIRE_UIT();
|
|
if (!media_router_manager_) {
|
|
media_router_manager_ =
|
|
std::make_unique<CefMediaRouterManager>(AsBrowserContext());
|
|
}
|
|
return media_router_manager_.get();
|
|
}
|
|
|
|
CefRefPtr<CefRequestContextImpl> CefBrowserContext::GetAnyRequestContext(
|
|
bool prefer_no_handler) const {
|
|
CEF_REQUIRE_UIT();
|
|
if (request_context_set_.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (prefer_no_handler) {
|
|
for (const auto& request_context : request_context_set_) {
|
|
if (!request_context->GetHandler()) {
|
|
return request_context.get();
|
|
}
|
|
}
|
|
}
|
|
|
|
return request_context_set_.begin()->get();
|
|
}
|
|
|
|
CefBrowserContext::CookieableSchemes CefBrowserContext::GetCookieableSchemes()
|
|
const {
|
|
CEF_REQUIRE_UIT();
|
|
return cookieable_schemes_;
|
|
}
|
|
|
|
// static
|
|
CefBrowserContext::CookieableSchemes
|
|
CefBrowserContext::GetGlobalCookieableSchemes() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
static base::NoDestructor<CookieableSchemes> schemes(
|
|
[]() { return MakeSupportedSchemes(CefContext::Get()->settings()); }());
|
|
return *schemes;
|
|
}
|