From 897c0f01edce155b72d7a45b5beda9bdf27518d5 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 14 Feb 2017 17:27:19 -0500 Subject: [PATCH] Simplify ownership of CefBrowserContext objects (issue #2083) --- libcef/browser/browser_context.cc | 48 ++- libcef/browser/browser_context.h | 43 +-- libcef/browser/browser_context_impl.cc | 60 ++-- libcef/browser/browser_context_impl.h | 29 +- libcef/browser/browser_context_proxy.cc | 6 +- libcef/browser/browser_context_proxy.h | 12 +- libcef/browser/browser_host_impl.cc | 25 +- libcef/browser/browser_main.cc | 4 +- libcef/browser/browser_main.h | 8 +- libcef/browser/browser_urlrequest_impl.cc | 6 +- libcef/browser/chrome_browser_process_stub.cc | 2 +- libcef/browser/chrome_profile_manager_stub.cc | 8 +- libcef/browser/content_browser_client.cc | 5 +- libcef/browser/content_browser_client.h | 8 +- .../browser/extensions/api/tabs/tabs_api.cc | 4 +- .../extensions/extensions_api_client.cc | 2 +- .../extensions/extensions_browser_client.cc | 4 +- .../mime_handler_view_guest_delegate.cc | 3 +- libcef/browser/request_context_impl.cc | 305 ++++++++++-------- libcef/browser/request_context_impl.h | 74 +++-- tests/ceftests/request_context_unittest.cc | 2 - 21 files changed, 351 insertions(+), 307 deletions(-) diff --git a/libcef/browser/browser_context.cc b/libcef/browser/browser_context.cc index a50e96f93..ba84693f2 100644 --- a/libcef/browser/browser_context.cc +++ b/libcef/browser/browser_context.cc @@ -15,25 +15,14 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" -#if DCHECK_IS_ON() -base::AtomicRefCount CefBrowserContext::DebugObjCt = 0; -#endif - CefBrowserContext::CefBrowserContext(bool is_proxy) : is_proxy_(is_proxy), extension_system_(NULL) { -#if DCHECK_IS_ON() - base::AtomicRefCountInc(&DebugObjCt); -#endif } CefBrowserContext::~CefBrowserContext() { // Should be cleared in Shutdown(). DCHECK(!resource_context_.get()); - -#if DCHECK_IS_ON() - base::AtomicRefCountDec(&DebugObjCt); -#endif } void CefBrowserContext::Initialize() { @@ -129,28 +118,27 @@ void CefBrowserContext::OnRenderFrameDeleted(int render_process_id, int render_frame_id, bool is_main_frame, bool is_guest_view) { - CEF_POST_TASK(CEF_IOT, - base::Bind(&CefBrowserContext::RenderFrameDeletedOnIOThread, this, - render_process_id, render_frame_id, is_main_frame, - is_guest_view)); -} - -void CefBrowserContext::OnPurgePluginListCache() { - CEF_POST_TASK(CEF_IOT, - base::Bind(&CefBrowserContext::PurgePluginListCacheOnIOThread, this)); -} - -void CefBrowserContext::RenderFrameDeletedOnIOThread(int render_process_id, - int render_frame_id, - bool is_main_frame, - bool is_guest_view) { + CEF_REQUIRE_UIT(); if (resource_context_ && is_main_frame) { DCHECK_GE(render_process_id, 0); - resource_context_->ClearPluginLoadDecision(render_process_id); + // Using base::Unretained() is safe because both this callback and possible + // deletion of |resource_context_| will execute on the IO thread, and this + // callback will be executed first. + CEF_POST_TASK(CEF_IOT, + base::Bind(&CefResourceContext::ClearPluginLoadDecision, + base::Unretained(resource_context_.get()), + render_process_id)); } } -void CefBrowserContext::PurgePluginListCacheOnIOThread() { - if (resource_context_) - resource_context_->ClearPluginLoadDecision(-1); +void CefBrowserContext::OnPurgePluginListCache() { + CEF_REQUIRE_UIT(); + if (resource_context_) { + // Using base::Unretained() is safe because both this callback and possible + // deletion of |resource_context_| will execute on the IO thread, and this + // callback will be executed first. + CEF_POST_TASK(CEF_IOT, + base::Bind(&CefResourceContext::ClearPluginLoadDecision, + base::Unretained(resource_context_.get()), -1)); + } } diff --git a/libcef/browser/browser_context.h b/libcef/browser/browser_context.h index 57266f271..9b2308321 100644 --- a/libcef/browser/browser_context.h +++ b/libcef/browser/browser_context.h @@ -33,12 +33,12 @@ // // BCI = CefBrowserContextImpl // Entry point from WC when using an isolated RCI. Owns the RC and creates the -// SPI indirectly. Life span controlled by RCI and (for the global context) -// CefBrowserMainParts. +// SPI indirectly. Owned by CefBrowserMainParts for the global context or RCI +// for non-global contexts. // // BCP = CefBrowserContextProxy // Entry point from WC when using a custom RCI. Owns the RC and creates the -// URCGP and SPP. Life span controlled by RCI. +// URCGP and SPP. Owned by RCI. // // SPI = content::StoragePartitionImpl // Owns storage-related objects like Quota, IndexedDB, Cache, etc. Created by @@ -83,29 +83,29 @@ // // Relationship diagram: // ref = reference (CefRefPtr/scoped_refptr) -// own = ownership (scoped_ptr) +// own = ownership (std::unique_ptr) // ptr = raw pointer // // CefBrowserMainParts----\ isolated cookie manager, etc. // | \ ^ -// ref ref ref/own +// own ref ref/own // v v | // /---> BCI -own-> SPI -ref-> URCGI --own-> URCI <-ptr-- CSP // / ^ ^ ^ ^ -// ptr ref ptr ref / +// ptr ptr ptr ref / // / | | | / // BHI -own-> WC -ptr-> BCP -own-> SPP -ref-> URCGP -own-> URCP --ref-/ // -// BHI -ref-> RCI -ref-> BCI/BCP -own-> RC -ref-> URCGI/URCGP +// BHI -ref-> RCI -own-> BCI/BCP -own-> RC -ref-> URCGI/URCGP // // // How shutdown works: // 1. CefBrowserHostImpl is destroyed on any thread due to browser close, // ref release, etc. -// 2. CefRequestContextImpl is destroyed on any thread due to -// CefBrowserHostImpl destruction, ref release, etc. +// 2. CefRequestContextImpl is destroyed (possibly asynchronously) on the UI +// thread due to CefBrowserHostImpl destruction, ref release, etc. // 3. CefBrowserContext* is destroyed on the UI thread due to -// CefRequestContextImpl destruction (*Impl, *Proxy) or ref release in +// CefRequestContextImpl destruction (*Impl, *Proxy) or deletion in // CefBrowserMainParts::PostMainMessageLoopRun() (*Impl). // 4. CefResourceContext is destroyed asynchronously on the IO thread due to // CefBrowserContext* destruction. This cancels/destroys any pending @@ -128,10 +128,7 @@ class CefExtensionSystem; // Main entry point for configuring behavior on a per-browser basis. An instance // of this class is passed to WebContents::Create in CefBrowserHostImpl:: // CreateInternal. Only accessed on the UI thread unless otherwise indicated. -class CefBrowserContext - : public ChromeProfileStub, - public base::RefCountedThreadSafe< - CefBrowserContext, content::BrowserThread::DeleteOnUIThread> { +class CefBrowserContext : public ChromeProfileStub { public: explicit CefBrowserContext(bool is_proxy); @@ -183,10 +180,9 @@ class CefBrowserContext return extension_system_; } -#if DCHECK_IS_ON() - // Simple tracking of allocated objects. - static base::AtomicRefCount DebugObjCt; // NOLINT(runtime/int) -#endif + bool is_proxy() const { + return is_proxy_; + } protected: ~CefBrowserContext() override; @@ -195,17 +191,6 @@ class CefBrowserContext void Shutdown(); private: - // Only allow deletion via scoped_refptr(). - friend struct content::BrowserThread::DeleteOnThread< - content::BrowserThread::UI>; - friend class base::DeleteHelper; - - void RenderFrameDeletedOnIOThread(int render_process_id, - int render_frame_id, - bool is_main_frame, - bool is_guest_view); - void PurgePluginListCacheOnIOThread(); - // True if this CefBrowserContext is a CefBrowserContextProxy. const bool is_proxy_; diff --git a/libcef/browser/browser_context_impl.cc b/libcef/browser/browser_context_impl.cc index 4262ecb6c..1d9b05bc8 100644 --- a/libcef/browser/browser_context_impl.cc +++ b/libcef/browser/browser_context_impl.cc @@ -8,6 +8,7 @@ #include #include "libcef/browser/browser_context_proxy.h" +#include "libcef/browser/content_browser_client.h" #include "libcef/browser/context.h" #include "libcef/browser/download_manager_delegate.h" #include "libcef/browser/extensions/extension_system.h" @@ -85,9 +86,19 @@ class ImplManager { const content::BrowserContext* context) { CEF_REQUIRE_UIT(); + const CefBrowserContext* cef_context = + static_cast(context); + const CefBrowserContextImpl* cef_context_impl = nullptr; + if (cef_context->is_proxy()) { + cef_context_impl = + static_cast(cef_context)->parent(); + } else { + cef_context_impl = static_cast(cef_context); + } + Vector::iterator it = all_.begin(); for (; it != all_.end(); ++it) { - if (*it == context || (*it)->HasProxy(context)) + if (*it == cef_context_impl) return *it; } return NULL; @@ -139,6 +150,7 @@ base::LazyInstance g_manager = LAZY_INSTANCE_INITIALIZER; class CefVisitedLinkListener : public visitedlink::VisitedLinkMaster::Listener { public: CefVisitedLinkListener() { + DCHECK(listener_map_.empty()); } void CreateListenerForContext(const CefBrowserContext* context) { @@ -196,11 +208,18 @@ CefBrowserContextImpl::CefBrowserContextImpl( } CefBrowserContextImpl::~CefBrowserContextImpl() { + CEF_REQUIRE_UIT(); + + // No CefRequestContextImpl should be referencing this object any longer. + DCHECK_EQ(request_context_count_, 0); + // Unregister the context first to avoid re-entrancy during shutdown. g_manager.Get().RemoveImpl(this, cache_path_); Shutdown(); + visitedlink_listener_->RemoveListenerForContext(this); + // The FontFamilyCache references the ProxyService so delete it before the // ProxyService is deleted. SetUserData(&kFontFamilyCacheKey, NULL); @@ -281,48 +300,39 @@ void CefBrowserContextImpl::Initialize() { void CefBrowserContextImpl::AddProxy(const CefBrowserContextProxy* proxy) { CEF_REQUIRE_UIT(); - DCHECK(!HasProxy(proxy)); - proxy_list_.push_back(proxy); - visitedlink_listener_->CreateListenerForContext(proxy); } void CefBrowserContextImpl::RemoveProxy(const CefBrowserContextProxy* proxy) { CEF_REQUIRE_UIT(); - visitedlink_listener_->RemoveListenerForContext(proxy); - - bool found = false; - ProxyList::iterator it = proxy_list_.begin(); - for (; it != proxy_list_.end(); ++it) { - if (*it == proxy) { - proxy_list_.erase(it); - found = true; - break; - } - } - DCHECK(found); } -bool CefBrowserContextImpl::HasProxy( - const content::BrowserContext* context) const { +void CefBrowserContextImpl::AddRequestContext() { CEF_REQUIRE_UIT(); - ProxyList::const_iterator it = proxy_list_.begin(); - for (; it != proxy_list_.end(); ++it) { - if (*it == context) - return true; + request_context_count_++; +} + +void CefBrowserContextImpl::RemoveRequestContext() { + CEF_REQUIRE_UIT(); + request_context_count_--; + DCHECK_GE(request_context_count_, 0); + + // Delete non-global contexts when the reference count reaches zero. + if (request_context_count_ == 0 && + this != CefContentBrowserClient::Get()->browser_context()) { + delete this; } - return false; } // static -scoped_refptr CefBrowserContextImpl::GetForCachePath( +CefBrowserContextImpl* CefBrowserContextImpl::GetForCachePath( const base::FilePath& cache_path) { return g_manager.Get().GetImplForPath(cache_path); } // static -CefRefPtr CefBrowserContextImpl::GetForContext( +CefBrowserContextImpl* CefBrowserContextImpl::GetForContext( content::BrowserContext* context) { return g_manager.Get().GetImplForContext(context); } diff --git a/libcef/browser/browser_context_impl.h b/libcef/browser/browser_context_impl.h index 1029ce372..5539364ca 100644 --- a/libcef/browser/browser_context_impl.h +++ b/libcef/browser/browser_context_impl.h @@ -25,9 +25,9 @@ class VisitedLinkMaster; } // Isolated BrowserContext implementation. Life span is controlled by -// CefRequestContextImpl and (for the main context) CefBrowserMainParts. Only -// accessed on the UI thread unless otherwise indicated. See browser_context.h -// for an object relationship diagram. +// CefBrowserMainParts for the global context and CefRequestContextImpl +// for non-global contexts. Only accessed on the UI thread unless otherwise +// indicated. See browser_context.h for an object relationship diagram. class CefBrowserContextImpl : public CefBrowserContext, public visitedlink::VisitedLinkDelegate { public: @@ -35,11 +35,11 @@ class CefBrowserContextImpl : public CefBrowserContext, // Returns the existing instance, if any, associated with the specified // |cache_path|. - static scoped_refptr GetForCachePath( + static CefBrowserContextImpl* GetForCachePath( const base::FilePath& cache_path); // Returns the underlying CefBrowserContextImpl if any. - static CefRefPtr GetForContext( + static CefBrowserContextImpl* GetForContext( content::BrowserContext* context); // Returns all existing CefBrowserContextImpl. @@ -48,10 +48,14 @@ class CefBrowserContextImpl : public CefBrowserContext, // Must be called immediately after this object is created. void Initialize() override; - // Track associated proxy objects. + // Track associated CefBrowserContextProxy objects. void AddProxy(const CefBrowserContextProxy* proxy); void RemoveProxy(const CefBrowserContextProxy* proxy); - bool HasProxy(const content::BrowserContext* context) const; + + // Track associated CefRequestContextImpl objects. If this object is a non- + // global context then it will delete itself when the count reaches zero. + void AddRequestContext(); + void RemoveRequestContext(); // BrowserContext methods. base::FilePath GetPath() const override; @@ -98,10 +102,8 @@ class CefBrowserContextImpl : public CefBrowserContext, } private: - // Only allow deletion via scoped_refptr(). - friend struct content::BrowserThread::DeleteOnThread< - content::BrowserThread::UI>; - friend class base::DeleteHelper; + // Allow deletion via std::unique_ptr(). + friend std::default_delete; ~CefBrowserContextImpl() override; @@ -109,9 +111,8 @@ class CefBrowserContextImpl : public CefBrowserContext, CefRequestContextSettings settings_; base::FilePath cache_path_; - // Not owned by this class. - typedef std::vector ProxyList; - ProxyList proxy_list_; + // Number of CefRequestContextImpl objects referencing this object. + int request_context_count_ = 0; std::unique_ptr pref_service_; std::unique_ptr pref_proxy_config_tracker_; diff --git a/libcef/browser/browser_context_proxy.cc b/libcef/browser/browser_context_proxy.cc index 8d9186ef7..9117fd657 100644 --- a/libcef/browser/browser_context_proxy.cc +++ b/libcef/browser/browser_context_proxy.cc @@ -59,16 +59,18 @@ bool ShouldProxyUserData(const void* key) { CefBrowserContextProxy::CefBrowserContextProxy( CefRefPtr handler, - scoped_refptr parent) + CefBrowserContextImpl* parent) : CefBrowserContext(true), handler_(handler), parent_(parent) { DCHECK(handler_.get()); - DCHECK(parent_.get()); + DCHECK(parent_); parent_->AddProxy(this); } CefBrowserContextProxy::~CefBrowserContextProxy() { + CEF_REQUIRE_UIT(); + Shutdown(); parent_->RemoveProxy(this); diff --git a/libcef/browser/browser_context_proxy.h b/libcef/browser/browser_context_proxy.h index 969b820ef..2e350188a 100644 --- a/libcef/browser/browser_context_proxy.h +++ b/libcef/browser/browser_context_proxy.h @@ -21,7 +21,7 @@ class CefStoragePartitionProxy; class CefBrowserContextProxy : public CefBrowserContext { public: CefBrowserContextProxy(CefRefPtr handler, - scoped_refptr parent); + CefBrowserContextImpl* parent); // Must be called immediately after this object is created. void Initialize() override; @@ -67,21 +67,19 @@ class CefBrowserContextProxy : public CefBrowserContext { content::StoragePartition* GetOrCreateStoragePartitionProxy( content::StoragePartition* partition_impl); - scoped_refptr parent() const { + CefBrowserContextImpl* parent() const { return parent_; } private: - // Only allow deletion via scoped_refptr(). - friend struct content::BrowserThread::DeleteOnThread< - content::BrowserThread::UI>; - friend class base::DeleteHelper; + // Allow deletion via std::unique_ptr() only. + friend std::default_delete; ~CefBrowserContextProxy() override; // Members initialized during construction are safe to access from any thread. CefRefPtr handler_; - scoped_refptr parent_; + CefBrowserContextImpl* parent_; // Guaranteed to outlive this object. std::unique_ptr download_manager_delegate_; std::unique_ptr storage_partition_proxy_; diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 7e81df8fa..661a6560d 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -281,10 +281,10 @@ CefRefPtr CefBrowserHostImpl::Create( // Get or create the request context and browser context. CefRefPtr request_context_impl = - CefRequestContextImpl::GetForRequestContext( + CefRequestContextImpl::GetOrCreateForRequestContext( create_params.request_context); DCHECK(request_context_impl); - scoped_refptr browser_context = + CefBrowserContext* browser_context = request_context_impl->GetBrowserContext(); DCHECK(browser_context); @@ -298,8 +298,7 @@ CefRefPtr CefBrowserHostImpl::Create( create_params.request_context = request_context_impl.get(); } - content::WebContents::CreateParams wc_create_params( - browser_context.get()); + content::WebContents::CreateParams wc_create_params(browser_context); if (platform_delegate->IsWindowless()) { // Create the OSR view for the WebContents. @@ -692,13 +691,13 @@ void CefBrowserHostImpl::StartDownload(const CefString& url) { if (!web_contents()) return; - scoped_refptr context = + CefBrowserContext* context = static_cast(web_contents()->GetBrowserContext()); - if (!context.get()) + if (!context) return; content::DownloadManager* manager = - content::BrowserContext::GetDownloadManager(context.get()); + content::BrowserContext::GetDownloadManager(context); if (!manager) return; @@ -2272,11 +2271,11 @@ void CefBrowserHostImpl::WebContentsCreated( CefRefPtr opener = GetBrowserForContents(source_contents); DCHECK(opener.get()); - scoped_refptr browser_context = + CefBrowserContext* browser_context = static_cast(new_contents->GetBrowserContext()); - DCHECK(browser_context.get()); + DCHECK(browser_context); CefRefPtr request_context = - CefRequestContextImpl::GetForBrowserContext(browser_context).get(); + CefRequestContextImpl::CreateForBrowserContext(browser_context).get(); DCHECK(request_context.get()); CefRefPtr browser = CefBrowserHostImpl::CreateInternal( @@ -2406,7 +2405,7 @@ void CefBrowserHostImpl::RenderFrameDeleted( if (web_contents()) { const bool is_main_frame = (render_frame_host->GetParent() == nullptr); - scoped_refptr context = + CefBrowserContext* context = static_cast(web_contents()->GetBrowserContext()); if (context) { context->OnRenderFrameDeleted(render_process_id, render_routing_id, @@ -2578,9 +2577,9 @@ void CefBrowserHostImpl::DidNavigateAnyFrame( if (!web_contents()) return; - scoped_refptr context = + CefBrowserContext* context = static_cast(web_contents()->GetBrowserContext()); - if (!context.get()) + if (!context) return; context->AddVisitedURLs(params.redirects); diff --git a/libcef/browser/browser_main.cc b/libcef/browser/browser_main.cc index c1d792ea0..cdf893c3d 100644 --- a/libcef/browser/browser_main.cc +++ b/libcef/browser/browser_main.cc @@ -193,7 +193,7 @@ void CefBrowserMainParts::PreMainMessageLoopRun() { CefContext::Get()->PopulateRequestContextSettings(&settings); // Create the global BrowserContext. - global_browser_context_ = new CefBrowserContextImpl(settings); + global_browser_context_.reset(new CefBrowserContextImpl(settings)); global_browser_context_->Initialize(); CefDevToolsManagerDelegate::StartHttpHandler(global_browser_context_.get()); @@ -212,7 +212,7 @@ void CefBrowserMainParts::PostMainMessageLoopRun() { // NOTE: Destroy objects in reverse order of creation. CefDevToolsManagerDelegate::StopHttpHandler(); - global_browser_context_ = NULL; + global_browser_context_.reset(nullptr); if (extensions::ExtensionsEnabled()) { extensions::ExtensionsBrowserClient::Set(NULL); diff --git a/libcef/browser/browser_main.h b/libcef/browser/browser_main.h index 16a2034d0..05ff1b9a0 100644 --- a/libcef/browser/browser_main.h +++ b/libcef/browser/browser_main.h @@ -6,7 +6,6 @@ #define CEF_LIBCEF_BROWSER_BROWSER_MAIN_H_ #pragma once -#include "libcef/browser/browser_context_impl.h" #include "libcef/browser/net/url_request_context_getter_impl.h" #include "base/macros.h" @@ -31,6 +30,7 @@ class ExtensionsBrowserClient; class ExtensionsClient; } +class CefBrowserContextImpl; class CefDevToolsDelegate; class CefBrowserMainParts : public content::BrowserMainParts { @@ -47,8 +47,8 @@ class CefBrowserMainParts : public content::BrowserMainParts { void PostMainMessageLoopRun() override; void PostDestroyThreads() override; - scoped_refptr browser_context() const { - return global_browser_context_; + CefBrowserContextImpl* browser_context() const { + return global_browser_context_.get(); } CefDevToolsDelegate* devtools_delegate() const { return devtools_delegate_; @@ -59,7 +59,7 @@ class CefBrowserMainParts : public content::BrowserMainParts { void PlatformInitialize(); #endif // defined(OS_WIN) - scoped_refptr global_browser_context_; + std::unique_ptr global_browser_context_; CefDevToolsDelegate* devtools_delegate_; // Deletes itself. std::unique_ptr message_loop_; diff --git a/libcef/browser/browser_urlrequest_impl.cc b/libcef/browser/browser_urlrequest_impl.cc index b394262ff..6fd73dd25 100644 --- a/libcef/browser/browser_urlrequest_impl.cc +++ b/libcef/browser/browser_urlrequest_impl.cc @@ -190,11 +190,11 @@ class CefBrowserURLRequest::Context // Get or create the request context and browser context. CefRefPtr request_context_impl = - CefRequestContextImpl::GetForRequestContext(request_context_); + CefRequestContextImpl::GetOrCreateForRequestContext(request_context_); DCHECK(request_context_impl.get()); - scoped_refptr browser_context = + CefBrowserContext* browser_context = request_context_impl->GetBrowserContext(); - DCHECK(browser_context.get()); + DCHECK(browser_context); if (!request_context_.get()) request_context_ = request_context_impl.get(); diff --git a/libcef/browser/chrome_browser_process_stub.cc b/libcef/browser/chrome_browser_process_stub.cc index 4ef7d7e28..dfa91eaa0 100644 --- a/libcef/browser/chrome_browser_process_stub.cc +++ b/libcef/browser/chrome_browser_process_stub.cc @@ -360,7 +360,7 @@ ChromeBrowserProcessStub::GetPhysicalWebDataSource() { content::BrowserContext* ChromeBrowserProcessStub::GetBrowserContextRedirectedInIncognito( content::BrowserContext* context) { - return CefBrowserContextImpl::GetForContext(context).get(); + return CefBrowserContextImpl::GetForContext(context); } content::BrowserContext* diff --git a/libcef/browser/chrome_profile_manager_stub.cc b/libcef/browser/chrome_profile_manager_stub.cc index 4ccdcb315..9c7edd066 100644 --- a/libcef/browser/chrome_profile_manager_stub.cc +++ b/libcef/browser/chrome_profile_manager_stub.cc @@ -21,7 +21,7 @@ namespace { // Return the main context for now since we don't currently have a good way to // determine that. CefBrowserContextImpl* GetActiveBrowserContext() { - return CefContentBrowserClient::Get()->browser_context().get(); + return CefContentBrowserClient::Get()->browser_context(); } } // namespace @@ -35,7 +35,7 @@ ChromeProfileManagerStub::~ChromeProfileManagerStub() { Profile* ChromeProfileManagerStub::GetProfile( const base::FilePath& profile_dir) { - scoped_refptr browser_context = + CefBrowserContextImpl* browser_context = CefBrowserContextImpl::GetForCachePath(profile_dir); if (!browser_context) { // ProfileManager makes assumptions about profile directory paths that do @@ -46,7 +46,7 @@ Profile* ChromeProfileManagerStub::GetProfile( // asking for. browser_context = GetActiveBrowserContext(); } - return browser_context.get(); + return browser_context; } bool ChromeProfileManagerStub::IsValidProfile(const void* profile) { @@ -54,7 +54,7 @@ bool ChromeProfileManagerStub::IsValidProfile(const void* profile) { return false; return !!CefBrowserContextImpl::GetForContext( reinterpret_cast( - const_cast(profile))).get(); + const_cast(profile))); } Profile* ChromeProfileManagerStub::GetLastUsedProfile( diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index 06afec7c7..a45aae486 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -7,6 +7,7 @@ #include #include +#include "libcef/browser/browser_context.h" #include "libcef/browser/browser_info.h" #include "libcef/browser/browser_info_manager.h" #include "libcef/browser/browser_host_impl.h" @@ -42,6 +43,7 @@ #include "base/json/json_reader.h" #include "base/path_service.h" #include "cef/grit/cef_resources.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/spellchecker/spellcheck_message_filter.h" #include "chrome/common/chrome_switches.h" #include "components/navigation_interception/intercept_navigation_throttle.h" @@ -979,8 +981,7 @@ void CefContentBrowserClient::RegisterCustomScheme(const std::string& scheme) { policy->RegisterWebSafeScheme(scheme); } -scoped_refptr -CefContentBrowserClient::browser_context() const { +CefBrowserContextImpl* CefContentBrowserClient::browser_context() const { return browser_main_parts_->browser_context(); } diff --git a/libcef/browser/content_browser_client.h b/libcef/browser/content_browser_client.h index 74418f769..2b2de1cdf 100644 --- a/libcef/browser/content_browser_client.h +++ b/libcef/browser/content_browser_client.h @@ -10,7 +10,6 @@ #include #include "include/cef_request_context_handler.h" -#include "libcef/browser/browser_context_impl.h" #include "libcef/browser/net/url_request_context_getter_impl.h" #include "base/macros.h" @@ -20,6 +19,7 @@ #include "third_party/skia/include/core/SkColor.h" class CefBrowserMainParts; +class CefBrowserContextImpl; class CefDevToolsDelegate; class CefResourceDispatcherHostDelegate; @@ -28,6 +28,10 @@ class PluginServiceFilter; class SiteInstance; } +namespace extensions { +class Extension; +} + class CefContentBrowserClient : public content::ContentBrowserClient { public: CefContentBrowserClient(); @@ -113,7 +117,7 @@ class CefContentBrowserClient : public content::ContentBrowserClient { // Perform browser process registration for the custom scheme. void RegisterCustomScheme(const std::string& scheme); - scoped_refptr browser_context() const; + CefBrowserContextImpl* browser_context() const; CefDevToolsDelegate* devtools_delegate() const; private: diff --git a/libcef/browser/extensions/api/tabs/tabs_api.cc b/libcef/browser/extensions/api/tabs/tabs_api.cc index fbc1a382b..a91653a79 100644 --- a/libcef/browser/extensions/api/tabs/tabs_api.cc +++ b/libcef/browser/extensions/api/tabs/tabs_api.cc @@ -57,10 +57,10 @@ bool GetTabById(int tab_id, if (!request_context) continue; CefRefPtr request_context_impl = - CefRequestContextImpl::GetForRequestContext(request_context); + CefRequestContextImpl::GetOrCreateForRequestContext(request_context); if (!request_context_impl) continue; - scoped_refptr browser_context = + CefBrowserContext* browser_context = request_context_impl->GetBrowserContext(); if (!browser_context) continue; diff --git a/libcef/browser/extensions/extensions_api_client.cc b/libcef/browser/extensions/extensions_api_client.cc index 1080f7d36..daaa19eee 100644 --- a/libcef/browser/extensions/extensions_api_client.cc +++ b/libcef/browser/extensions/extensions_api_client.cc @@ -44,7 +44,7 @@ CefExtensionsAPIClient::CreateGuestViewManagerDelegate( // *Proxy object that has already been deleted. return base::WrapUnique( new extensions::ExtensionsGuestViewManagerDelegate( - CefBrowserContextImpl::GetForContext(context).get())); + CefBrowserContextImpl::GetForContext(context))); } std::unique_ptr diff --git a/libcef/browser/extensions/extensions_browser_client.cc b/libcef/browser/extensions/extensions_browser_client.cc index 48c185812..467425ed3 100644 --- a/libcef/browser/extensions/extensions_browser_client.cc +++ b/libcef/browser/extensions/extensions_browser_client.cc @@ -64,8 +64,8 @@ bool CefExtensionsBrowserClient::IsSameContext(BrowserContext* first, BrowserContext* second) { // Returns true if |first| and |second| share the same underlying // CefBrowserContextImpl. - return CefBrowserContextImpl::GetForContext(first).get() == - CefBrowserContextImpl::GetForContext(second).get(); + return CefBrowserContextImpl::GetForContext(first) == + CefBrowserContextImpl::GetForContext(second); } bool CefExtensionsBrowserClient::HasOffTheRecordContext( diff --git a/libcef/browser/extensions/mime_handler_view_guest_delegate.cc b/libcef/browser/extensions/mime_handler_view_guest_delegate.cc index 8d0f610da..0a5cde31e 100644 --- a/libcef/browser/extensions/mime_handler_view_guest_delegate.cc +++ b/libcef/browser/extensions/mime_handler_view_guest_delegate.cc @@ -5,6 +5,7 @@ #include "libcef/browser/extensions/mime_handler_view_guest_delegate.h" +#include "libcef/browser/browser_context.h" #include "libcef/browser/browser_host_impl.h" #include "libcef/browser/browser_info.h" #include "libcef/browser/content_browser_client.h" @@ -91,7 +92,7 @@ void CefMimeHandlerViewGuestDelegate::OnGuestDetached( info->guest_render_id_manager()->remove_render_frame_id( render_process_id, render_frame_id); - scoped_refptr context = + CefBrowserContext* context = static_cast(web_contents->GetBrowserContext()); if (context) { context->OnRenderFrameDeleted(render_process_id, render_frame_id, diff --git a/libcef/browser/request_context_impl.cc b/libcef/browser/request_context_impl.cc index 999c6bfc8..4de0e410a 100644 --- a/libcef/browser/request_context_impl.cc +++ b/libcef/browser/request_context_impl.cc @@ -64,7 +64,7 @@ struct ResolveHostHelper { resolved_ips.push_back(iter->ToStringWithoutPort()); CEF_POST_TASK(CEF_UIT, - base::Bind(&CefResolveCallback::OnResolveCompleted, callback_.get(), + base::Bind(&CefResolveCallback::OnResolveCompleted, callback_, static_cast(result), resolved_ips)); delete this; @@ -88,8 +88,9 @@ CefRefPtr CefRequestContext::GetGlobalContext() { return NULL; } - return CefRequestContextImpl::GetForBrowserContext( - CefContentBrowserClient::Get()->browser_context()); + CefRequestContextImpl::Config config; + config.is_global = true; + return new CefRequestContextImpl(config); } // static @@ -102,7 +103,11 @@ CefRefPtr CefRequestContext::CreateContext( return NULL; } - return new CefRequestContextImpl(settings, handler); + CefRequestContextImpl::Config config; + config.settings = settings; + config.handler = handler; + config.unique_id = g_next_id.GetNext(); + return new CefRequestContextImpl(config); } // static @@ -118,18 +123,31 @@ CefRefPtr CefRequestContext::CreateContext( if (!other.get()) return NULL; - return new CefRequestContextImpl( - static_cast(other.get()), handler); + CefRequestContextImpl::Config config; + config.other = static_cast(other.get()); + config.handler = handler; + config.unique_id = g_next_id.GetNext(); + return new CefRequestContextImpl(config); } -// CefBrowserContextImpl +// CefRequestContextImpl CefRequestContextImpl::~CefRequestContextImpl() { + // Delete the proxy first because it also references |browser_context_impl_|. + if (browser_context_proxy_) + browser_context_proxy_.reset(nullptr); + + if (browser_context_impl_) { + // May result in |browser_context_impl_| being deleted if it's not the + // global context and no other CefRequestContextImpl are referencing it. + browser_context_impl_->RemoveRequestContext(); + } } // static -CefRefPtr CefRequestContextImpl::GetForRequestContext( +CefRefPtr +CefRequestContextImpl::GetOrCreateForRequestContext( CefRefPtr request_context) { if (request_context.get()) { // Use the context from the provided CefRequestContext. @@ -137,87 +155,27 @@ CefRefPtr CefRequestContextImpl::GetForRequestContext( } // Use the global context. - scoped_refptr browser_context = - CefContentBrowserClient::Get()->browser_context(); - return GetForBrowserContext(browser_context); + CefRequestContextImpl::Config config; + config.is_global = true; + return new CefRequestContextImpl(config); } // static -CefRefPtr CefRequestContextImpl::GetForBrowserContext( - scoped_refptr browser_context) { - DCHECK(browser_context.get()); - return new CefRequestContextImpl(browser_context); +CefRefPtr CefRequestContextImpl::CreateForBrowserContext( + CefBrowserContext* browser_context) { + DCHECK(browser_context); + CefRequestContextImpl::Config config; + config.handler = browser_context->GetHandler(); + CefRefPtr impl = new CefRequestContextImpl(config); + // Force immediate initialization because it's not safe to keep a raw pointer + // to |browser_context|. + impl->Initialize(browser_context); + return impl; } -scoped_refptr CefRequestContextImpl::GetBrowserContext() { - CEF_REQUIRE_UIT(); - - if (!browser_context_) { - scoped_refptr parent; - - if (other_.get()) { - // Share storage with |other_|. - parent = CefBrowserContextImpl::GetForContext( - other_->GetBrowserContext().get()); - } - - if (!parent.get()) { - const base::FilePath& cache_path = - base::FilePath(CefString(&settings_.cache_path)); - if (!cache_path.empty()) { - // Check if a CefBrowserContextImpl is already globally registered for - // the specified cache path. If so then use it. - parent = CefBrowserContextImpl::GetForCachePath(cache_path); - } - } - - if (!parent.get()) { - // Create a new CefBrowserContextImpl instance. If the cache path is non- - // empty then this new instance will become the globally registered - // CefBrowserContextImpl for that path. Otherwise, this new instance will - // be a completely isolated "incongento mode" context. - parent = new CefBrowserContextImpl(settings_); - parent->Initialize(); - } - - // The parent's settings may be different. Force our settings to match the - // parent. - settings_ = parent->GetSettings(); - - if (handler_.get()) { - // Use a proxy that will execute handler callbacks where appropriate and - // otherwise forward all requests to the parent implementation. - browser_context_ = new CefBrowserContextProxy(handler_, parent); - browser_context_->Initialize(); - } else { - // Use the parent implementation directly. - browser_context_ = parent; - } - - request_context_impl_ = parent->request_context().get(); - DCHECK(request_context_impl_); - - if (handler_.get()) { - // Keep the handler alive until the associated request context is - // destroyed. - request_context_impl_->AddHandler(handler_); - } - } - - if (!request_context_impl_) { - request_context_impl_ = - CefBrowserContextImpl::GetForContext(browser_context_.get())-> - request_context().get(); - DCHECK(request_context_impl_); - } - - if (other_.get()) { - // Clear the reference to |other_| after setting |request_context_impl_|. - // This is the reverse order of checks in IsSharedWith(). - other_ = NULL; - } - - return browser_context_; +CefBrowserContext* CefRequestContextImpl::GetBrowserContext() { + EnsureBrowserContext(); + return browser_context(); } void CefRequestContextImpl::GetBrowserContext( @@ -235,8 +193,8 @@ void CefRequestContextImpl::GetRequestContextImpl( task_runner = base::MessageLoop::current()->task_runner(); if (request_context_impl_) { // The browser context already exists. - DCHECK(browser_context_.get()); - GetRequestContextImplOnIOThread(task_runner, callback, browser_context_); + DCHECK(browser_context()); + GetRequestContextImplOnIOThread(task_runner, callback, browser_context()); } else { // Need to initialize the browser context first. GetBrowserContextOnUIThread( @@ -252,14 +210,28 @@ bool CefRequestContextImpl::IsSame(CefRefPtr other) { if (!other_impl) return false; + // Compare whether both are the global context. + if (config_.is_global && other_impl->config_.is_global) + return true; + // Compare CefBrowserContext pointers if one has been associated. - if (browser_context_ && other_impl->browser_context_) - return (browser_context_ == other_impl->browser_context_); - else if (browser_context_ || other_impl->browser_context_) + if (browser_context() && other_impl->browser_context()) { + if (browser_context()->is_proxy() && + other_impl->browser_context()->is_proxy()) { + CefBrowserContextProxy* proxy = + static_cast(browser_context()); + CefBrowserContextProxy* other_proxy = + static_cast(other_impl->browser_context()); + return (proxy->parent() == other_proxy->parent() && + proxy->GetHandler() == other_proxy->GetHandler()); + } + return (browser_context() == other_impl->browser_context()); + } else if (browser_context() || other_impl->browser_context()) { return false; + } // Otherwise compare unique IDs. - return (unique_id_ == other_impl->unique_id_); + return (config_.unique_id == other_impl->config_.unique_id); } bool CefRequestContextImpl::IsSharingWith(CefRefPtr other) { @@ -271,14 +243,14 @@ bool CefRequestContextImpl::IsSharingWith(CefRefPtr other) { if (IsSame(other)) return true; - CefRefPtr pending_other = other_; + CefRefPtr pending_other = config_.other; if (pending_other.get()) { // This object is not initialized but we know what context this object will // share with. Compare to that other context instead. return pending_other->IsSharingWith(other); } - pending_other = other_impl->other_; + pending_other = other_impl->config_.other; if (pending_other.get()) { // The other object is not initialized but we know what context that object // will share with. Compare to that other context instead. @@ -292,26 +264,26 @@ bool CefRequestContextImpl::IsSharingWith(CefRefPtr other) { // This or the other object is not initialized. Compare the cache path values. // If both are non-empty and the same then they'll share the same storage. - if (settings_.cache_path.length > 0 && - other_impl->settings_.cache_path.length > 0) { - return (base::FilePath(CefString(&settings_.cache_path)) == - base::FilePath(CefString(&other_impl->settings_.cache_path))); + if (config_.settings.cache_path.length > 0 && + other_impl->config_.settings.cache_path.length > 0) { + return (base::FilePath(CefString(&config_.settings.cache_path)) == + base::FilePath( + CefString(&other_impl->config_.settings.cache_path))); } return false; } bool CefRequestContextImpl::IsGlobal() { - return (browser_context_ == - CefContentBrowserClient::Get()->browser_context()); + return config_.is_global; } CefRefPtr CefRequestContextImpl::GetHandler() { - return handler_; + return config_.handler; } CefString CefRequestContextImpl::GetCachePath() { - return CefString(&settings_.cache_path); + return CefString(&config_.settings.cache_path); } CefRefPtr CefRequestContextImpl::GetDefaultCookieManager( @@ -357,7 +329,7 @@ bool CefRequestContextImpl::HasPreference(const CefString& name) { // Make sure the browser context exists. EnsureBrowserContext(); - PrefService* pref_service = browser_context_->GetPrefs(); + PrefService* pref_service = browser_context()->GetPrefs(); return (pref_service->FindPreference(name) != NULL); } @@ -372,7 +344,7 @@ CefRefPtr CefRequestContextImpl::GetPreference( // Make sure the browser context exists. EnsureBrowserContext(); - PrefService* pref_service = browser_context_->GetPrefs(); + PrefService* pref_service = browser_context()->GetPrefs(); const PrefService::Preference* pref = pref_service->FindPreference(name); if (!pref) return NULL; @@ -390,7 +362,7 @@ CefRefPtr CefRequestContextImpl::GetAllPreferences( // Make sure the browser context exists. EnsureBrowserContext(); - PrefService* pref_service = browser_context_->GetPrefs(); + PrefService* pref_service = browser_context()->GetPrefs(); std::unique_ptr values; if (include_defaults) @@ -412,7 +384,7 @@ bool CefRequestContextImpl::CanSetPreference(const CefString& name) { // Make sure the browser context exists. EnsureBrowserContext(); - PrefService* pref_service = browser_context_->GetPrefs(); + PrefService* pref_service = browser_context()->GetPrefs(); const PrefService::Preference* pref = pref_service->FindPreference(name); return (pref && pref->IsUserModifiable()); } @@ -429,7 +401,7 @@ bool CefRequestContextImpl::SetPreference(const CefString& name, // Make sure the browser context exists. EnsureBrowserContext(); - PrefService* pref_service = browser_context_->GetPrefs(); + PrefService* pref_service = browser_context()->GetPrefs(); // The below validation logic should match PrefService::SetUserPrefValue. @@ -530,35 +502,91 @@ cef_errorcode_t CefRequestContextImpl::ResolveHostCached( } CefRequestContextImpl::CefRequestContextImpl( - scoped_refptr browser_context) - : browser_context_(browser_context), - settings_(browser_context->GetSettings()), - handler_(browser_context->GetHandler()), - unique_id_(0), - request_context_impl_(NULL) { + const CefRequestContextImpl::Config& config) + : config_(config) { } -CefRequestContextImpl::CefRequestContextImpl( - const CefRequestContextSettings& settings, - CefRefPtr handler) - : settings_(settings), - handler_(handler), - unique_id_(g_next_id.GetNext()), - request_context_impl_(NULL) { +void CefRequestContextImpl::Initialize() { + CefBrowserContext* other_browser_context = nullptr; + if (config_.is_global) + other_browser_context = CefContentBrowserClient::Get()->browser_context(); + else if (config_.other.get()) + other_browser_context = config_.other->GetBrowserContext(); + + Initialize(other_browser_context); + + if (config_.other.get()) { + // Clear the reference to |other_| after setting |request_context_impl_|. + // This is the reverse order of checks in IsSharedWith(). + config_.other = NULL; + } } -CefRequestContextImpl::CefRequestContextImpl( - CefRefPtr other, - CefRefPtr handler) - : other_(other), - handler_(handler), - unique_id_(g_next_id.GetNext()), - request_context_impl_(NULL) { +void CefRequestContextImpl::Initialize( + CefBrowserContext* other_browser_context) { + CEF_REQUIRE_UIT(); + + DCHECK(!browser_context_impl_); + DCHECK(!request_context_impl_); + + if (other_browser_context) { + // Share storage with |other_browser_context|. + browser_context_impl_ = CefBrowserContextImpl::GetForContext( + other_browser_context); + } + + if (!browser_context_impl_) { + const base::FilePath& cache_path = + base::FilePath(CefString(&config_.settings.cache_path)); + if (!cache_path.empty()) { + // Check if a CefBrowserContextImpl is already globally registered for + // the specified cache path. If so then use it. + browser_context_impl_ = + CefBrowserContextImpl::GetForCachePath(cache_path); + } + } + + if (!browser_context_impl_) { + // Create a new CefBrowserContextImpl instance. If the cache path is non- + // empty then this new instance will become the globally registered + // CefBrowserContextImpl for that path. Otherwise, this new instance will + // be a completely isolated "incongento mode" context. + browser_context_impl_ = new CefBrowserContextImpl(config_.settings); + browser_context_impl_->Initialize(); + } + + // We'll disassociate from |browser_context_impl_| on destruction. + browser_context_impl_->AddRequestContext(); + + // Force our settings to match |browser_context_impl_|. + config_.settings = browser_context_impl_->GetSettings(); + + if (config_.handler.get()) { + // Use a proxy that will execute handler callbacks where appropriate and + // otherwise forward all requests to |browser_context_impl_|. + browser_context_proxy_.reset( + new CefBrowserContextProxy(config_.handler, browser_context_impl_)); + browser_context_proxy_->Initialize(); + DCHECK(!config_.is_global); + } else { + config_.is_global = (browser_context_impl_ == + CefContentBrowserClient::Get()->browser_context()); + } + + request_context_impl_ = browser_context_impl_->request_context().get(); + DCHECK(request_context_impl_); + + if (config_.handler.get()) { + // Keep the handler alive until the associated request context is + // destroyed. + request_context_impl_->AddHandler(config_.handler); + } } void CefRequestContextImpl::EnsureBrowserContext() { - GetBrowserContext(); - DCHECK(browser_context_.get()); + if (!browser_context()) + Initialize(); + DCHECK(browser_context()); DCHECK(request_context_impl_); } @@ -577,17 +605,17 @@ void CefRequestContextImpl::GetBrowserContextOnUIThread( if (task_runner->BelongsToCurrentThread()) { // Execute the callback immediately. - callback.Run(browser_context_); + callback.Run(browser_context()); } else { // Execute the callback on the target thread. - task_runner->PostTask(FROM_HERE, base::Bind(callback, browser_context_)); + task_runner->PostTask(FROM_HERE, base::Bind(callback, browser_context())); } } void CefRequestContextImpl::GetRequestContextImplOnIOThread( scoped_refptr task_runner, const RequestContextCallback& callback, - scoped_refptr browser_context) { + CefBrowserContext* browser_context) { if (!CEF_CURRENTLY_ON_IOT()) { CEF_POST_TASK(CEF_IOT, base::Bind(&CefRequestContextImpl::GetRequestContextImplOnIOThread, @@ -628,16 +656,16 @@ void CefRequestContextImpl::ClearSchemeHandlerFactoriesInternal( void CefRequestContextImpl::PurgePluginListCacheInternal( bool reload_pages, - scoped_refptr browser_context) { + CefBrowserContext* browser_context) { CEF_REQUIRE_UIT(); browser_context->OnPurgePluginListCache(); content::PluginService::GetInstance()->PurgePluginListCache( - browser_context.get(), false); + browser_context, false); } void CefRequestContextImpl::ClearCertificateExceptionsInternal( CefRefPtr callback, - scoped_refptr browser_context) { + CefBrowserContext* browser_context) { CEF_REQUIRE_UIT(); content::SSLHostStateDelegate* ssl_delegate = @@ -647,7 +675,7 @@ void CefRequestContextImpl::ClearCertificateExceptionsInternal( if (callback) { CEF_POST_TASK(CEF_UIT, - base::Bind(&CefCompletionCallback::OnComplete, callback.get())); + base::Bind(&CefCompletionCallback::OnComplete, callback)); } } @@ -669,7 +697,7 @@ void CefRequestContextImpl::CloseAllConnectionsInternal( if (callback) { CEF_POST_TASK(CEF_UIT, - base::Bind(&CefCompletionCallback::OnComplete, callback.get())); + base::Bind(&CefCompletionCallback::OnComplete, callback)); } } @@ -702,3 +730,10 @@ void CefRequestContextImpl::ResolveHostInternal( helper->OnResolveCompleted(retval); } + +CefBrowserContext* CefRequestContextImpl::browser_context() const { + if (browser_context_proxy_) + return browser_context_proxy_.get(); + return browser_context_impl_; +} + diff --git a/libcef/browser/request_context_impl.h b/libcef/browser/request_context_impl.h index e8cb02038..7f2c4a510 100644 --- a/libcef/browser/request_context_impl.h +++ b/libcef/browser/request_context_impl.h @@ -8,32 +8,35 @@ #include "include/cef_request_context.h" #include "libcef/browser/browser_context.h" +#include "libcef/browser/thread_util.h" + +class CefBrowserContextImpl; +class CefBrowserContextProxy; // Implementation of the CefRequestContext interface. All methods are thread- -// safe unless otherwise indicated. +// safe unless otherwise indicated. Will be deleted on the UI thread. class CefRequestContextImpl : public CefRequestContext { public: ~CefRequestContextImpl() override; // Returns a CefRequestContextImpl for the specified |request_context|. // Will return the global context if |request_context| is NULL. - static CefRefPtr GetForRequestContext( + static CefRefPtr GetOrCreateForRequestContext( CefRefPtr request_context); // Returns a CefRequestContextImpl for the specified |browser_context|. // |browser_context| must be non-NULL. - static CefRefPtr GetForBrowserContext( - scoped_refptr browser_context); + static CefRefPtr CreateForBrowserContext( + CefBrowserContext* browser_context); // Returns the browser context object. Can only be called on the UI thread. - scoped_refptr GetBrowserContext(); + CefBrowserContext* GetBrowserContext(); // Executes |callback| either synchronously or asynchronously with the browser // context object when it's available. If |task_runner| is NULL the callback // will be executed on the originating thread. The resulting context object // can only be accessed on the UI thread. - typedef base::Callback)> - BrowserContextCallback; + typedef base::Callback BrowserContextCallback; void GetBrowserContext( scoped_refptr task_runner, const BrowserContextCallback& callback); @@ -79,17 +82,36 @@ class CefRequestContextImpl : public CefRequestContext { const CefString& origin, std::vector& resolved_ips) override; - const CefRequestContextSettings& settings() const { return settings_; } + const CefRequestContextSettings& settings() const { return config_.settings; } private: friend class CefRequestContext; - explicit CefRequestContextImpl( - scoped_refptr browser_context); - CefRequestContextImpl(const CefRequestContextSettings& settings, - CefRefPtr handler); - CefRequestContextImpl(CefRefPtr other, - CefRefPtr handler); + struct Config { + // True if wrapping the global context. + bool is_global = false; + + // |settings| or |other| will be set when creating a new CefRequestContext + // via the API. When wrapping an existing CefBrowserContext* both will be + // empty and Initialize(CefBrowserContext*) will be called immediately after + // CefRequestContextImpl construction. + CefRequestContextSettings settings; + CefRefPtr other; + + // Optionally use this handler, in which case a CefBrowserContextProxy will + // be created. + CefRefPtr handler; + + // Used to uniquely identify CefRequestContext objects before an associated + // CefBrowserContext has been created. Should be set when a new + // CefRequestContext via the API. + int unique_id = -1; + }; + + explicit CefRequestContextImpl(const Config& config); + + void Initialize(); + void Initialize(CefBrowserContext* other_browser_context); // Make sure the browser context exists. Only called on the UI thread. void EnsureBrowserContext(); @@ -100,7 +122,7 @@ class CefRequestContextImpl : public CefRequestContext { void GetRequestContextImplOnIOThread( scoped_refptr task_runner, const RequestContextCallback& callback, - scoped_refptr browser_context); + CefBrowserContext* browser_context); void RegisterSchemeHandlerFactoryInternal( const CefString& scheme_name, @@ -111,10 +133,10 @@ class CefRequestContextImpl : public CefRequestContext { scoped_refptr request_context); void PurgePluginListCacheInternal( bool reload_pages, - scoped_refptr browser_context); + CefBrowserContext* browser_context); void ClearCertificateExceptionsInternal( CefRefPtr callback, - scoped_refptr browser_context); + CefBrowserContext* browser_context); void CloseAllConnectionsInternal( CefRefPtr callback, scoped_refptr request_context); @@ -123,19 +145,19 @@ class CefRequestContextImpl : public CefRequestContext { CefRefPtr callback, scoped_refptr request_context); - scoped_refptr browser_context_; - CefRequestContextSettings settings_; - CefRefPtr other_; - CefRefPtr handler_; + CefBrowserContext* browser_context() const; - // Used to uniquely identify CefRequestContext objects before an associated - // CefBrowserContext has been created. - int unique_id_; + // If *Impl then we must disassociate from it on destruction. + CefBrowserContextImpl* browser_context_impl_ = nullptr; + // If *Proxy then we own it. + std::unique_ptr browser_context_proxy_; + + Config config_; // Owned by the CefBrowserContext. - CefURLRequestContextGetterImpl* request_context_impl_; + CefURLRequestContextGetterImpl* request_context_impl_ = nullptr; - IMPLEMENT_REFCOUNTING(CefRequestContextImpl); + IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefRequestContextImpl); DISALLOW_COPY_AND_ASSIGN(CefRequestContextImpl); }; diff --git a/tests/ceftests/request_context_unittest.cc b/tests/ceftests/request_context_unittest.cc index 9c16d5ea2..ea5574282 100644 --- a/tests/ceftests/request_context_unittest.cc +++ b/tests/ceftests/request_context_unittest.cc @@ -671,8 +671,6 @@ class MethodTestHandler : public TestHandler { } ~CompletionCallback() override { - EXPECT_UI_THREAD(); - // OnComplete should be executed. EXPECT_FALSE(test_handler_); }