Move the frame/handler association to CefResourceContext (see issue #2622).

A CefBrowserHostImpl is created using a CefRequestContextImpl that may have a
CefRequestContextHandler. Multiple CefRequestContextImpl may share the same
underlying CefBrowserContext which owns a CefResourceContext. IO-thread
callbacks from Chromium are often associated with a CefResourceContext and the
target frame is identified using render_process_id/render_frame_id routing IDs.

This change forwards frame create/delete notifications from CefBrowserHostImpl
(or CefMimeHandlerViewGuestDelegate) to CefResourceContext so that it can
properly resolve the association from routing ID to Handler when queried from
CefPluginServiceFilter::IsPluginAvailable.

To test: Verify that all ceftests pass with NetworkService disabled.
This commit is contained in:
Marshall Greenblatt 2019-03-23 19:40:32 -04:00
parent a23e845244
commit ea27dff338
10 changed files with 179 additions and 70 deletions

View File

@ -287,8 +287,7 @@ void CefBrowserContext::Initialize() {
content::BrowserContext::Initialize(this, GetPath()); content::BrowserContext::Initialize(this, GetPath());
resource_context_.reset( resource_context_.reset(new CefResourceContext(IsOffTheRecord()));
new CefResourceContext(IsOffTheRecord(), GetHandler()));
// This must be called before creating any services to avoid hitting // This must be called before creating any services to avoid hitting
// DependencyManager::AssertContextWasntDestroyed when creating/destroying // DependencyManager::AssertContextWasntDestroyed when creating/destroying
@ -369,19 +368,6 @@ void CefBrowserContext::RemoveCefRequestContext(
delete this; delete this;
} }
CefRequestContextImpl* CefBrowserContext::GetCefRequestContext(
bool impl_only) const {
CEF_REQUIRE_UIT();
// First try to find a non-proxy RequestContext.
for (CefRequestContextImpl* impl : request_context_set_) {
if (!impl->GetHandler())
return impl;
}
if (impl_only)
return nullptr;
return *request_context_set_.begin();
}
// static // static
CefBrowserContext* CefBrowserContext::GetForCachePath( CefBrowserContext* CefBrowserContext::GetForCachePath(
const base::FilePath& cache_path) { const base::FilePath& cache_path) {
@ -572,10 +558,6 @@ SimpleFactoryKey* CefBrowserContext::GetSimpleFactoryKey() const {
return nullptr; return nullptr;
} }
CefRequestContextImpl* CefBrowserContext::GetCefRequestContext() const {
return GetCefRequestContext(false);
}
const CefRequestContextSettings& CefBrowserContext::GetSettings() const { const CefRequestContextSettings& CefBrowserContext::GetSettings() const {
return settings_; return settings_;
} }
@ -625,11 +607,44 @@ void CefBrowserContext::RebuildTable(
enumerator->OnComplete(true); enumerator->OnComplete(true);
} }
void CefBrowserContext::OnRenderFrameDeleted(int render_process_id, void CefBrowserContext::OnRenderFrameCreated(
int render_frame_id, CefRequestContextImpl* request_context,
bool is_main_frame, int render_process_id,
bool is_guest_view) { int render_frame_id,
bool is_main_frame,
bool is_guest_view) {
CEF_REQUIRE_UIT(); CEF_REQUIRE_UIT();
CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
if (handler && resource_context_) {
DCHECK_GE(render_process_id, 0);
// 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::AddHandler,
base::Unretained(resource_context_.get()),
render_process_id, render_frame_id, handler));
}
}
void CefBrowserContext::OnRenderFrameDeleted(
CefRequestContextImpl* request_context,
int render_process_id,
int render_frame_id,
bool is_main_frame,
bool is_guest_view) {
CEF_REQUIRE_UIT();
CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
if (handler && resource_context_) {
DCHECK_GE(render_process_id, 0);
// 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::RemoveHandler,
base::Unretained(resource_context_.get()),
render_process_id, render_frame_id));
}
if (resource_context_ && is_main_frame) { if (resource_context_ && is_main_frame) {
DCHECK_GE(render_process_id, 0); DCHECK_GE(render_process_id, 0);
// Using base::Unretained() is safe because both this callback and possible // Using base::Unretained() is safe because both this callback and possible

View File

@ -134,7 +134,6 @@ class CefBrowserContext : public ChromeProfileStub,
// itself when the count reaches zero. // itself when the count reaches zero.
void AddCefRequestContext(CefRequestContextImpl* context); void AddCefRequestContext(CefRequestContextImpl* context);
void RemoveCefRequestContext(CefRequestContextImpl* context); void RemoveCefRequestContext(CefRequestContextImpl* context);
CefRequestContextImpl* GetCefRequestContext(bool impl_only) const;
// BrowserContext methods. // BrowserContext methods.
content::ResourceContext* GetResourceContext() override; content::ResourceContext* GetResourceContext() override;
@ -185,10 +184,6 @@ class CefBrowserContext : public ChromeProfileStub,
// visitedlink::VisitedLinkDelegate methods. // visitedlink::VisitedLinkDelegate methods.
void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override; void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
// Returns the first RequestContext without a handler, if one exists,
// otherwise the first RequestContext.
CefRequestContextImpl* GetCefRequestContext() const;
// Returns the settings associated with this object. Safe to call from any // Returns the settings associated with this object. Safe to call from any
// thread. // thread.
const CefRequestContextSettings& GetSettings() const; const CefRequestContextSettings& GetSettings() const;
@ -204,10 +199,16 @@ class CefBrowserContext : public ChromeProfileStub,
// visited links. // visited links.
void AddVisitedURLs(const std::vector<GURL>& urls); void AddVisitedURLs(const std::vector<GURL>& urls);
// Called from CefBrowserHostImpl::RenderFrameDeleted or // Called from CefRequestContextImpl::OnRenderFrameCreated.
// CefMimeHandlerViewGuestDelegate::OnGuestDetached when a render frame is void OnRenderFrameCreated(CefRequestContextImpl* request_context,
// deleted. int render_process_id,
void OnRenderFrameDeleted(int render_process_id, int render_frame_id,
bool is_main_frame,
bool is_guest_view);
// Called from CefRequestContextImpl::OnRenderFrameDeleted.
void OnRenderFrameDeleted(CefRequestContextImpl* request_context,
int render_process_id,
int render_frame_id, int render_frame_id,
bool is_main_frame, bool is_main_frame,
bool is_guest_view); bool is_guest_view);

View File

@ -374,8 +374,8 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
CefRefPtr<CefBrowserHostImpl> browser = CreateInternal( CefRefPtr<CefBrowserHostImpl> browser = CreateInternal(
create_params.settings, create_params.client, web_contents.release(), create_params.settings, create_params.client, web_contents.release(),
true, info, create_params.devtools_opener, is_devtools_popup, true, info, create_params.devtools_opener, is_devtools_popup,
create_params.request_context, std::move(platform_delegate), static_cast<CefRequestContextImpl*>(create_params.request_context.get()),
cef_extension); std::move(platform_delegate), cef_extension);
if (!browser) if (!browser)
return nullptr; return nullptr;
@ -401,7 +401,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
scoped_refptr<CefBrowserInfo> browser_info, scoped_refptr<CefBrowserInfo> browser_info,
CefRefPtr<CefBrowserHostImpl> opener, CefRefPtr<CefBrowserHostImpl> opener,
bool is_devtools_popup, bool is_devtools_popup,
CefRefPtr<CefRequestContext> request_context, CefRefPtr<CefRequestContextImpl> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate, std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension) { CefRefPtr<CefExtension> extension) {
CEF_REQUIRE_UIT(); CEF_REQUIRE_UIT();
@ -2565,17 +2565,15 @@ void CefBrowserHostImpl::WebContentsCreated(
if (!opener.get()) if (!opener.get())
return; return;
// Popups must share the same BrowserContext as the parent. // Popups must share the same RequestContext as the parent.
CefBrowserContext* browser_context = CefRefPtr<CefRequestContextImpl> request_context = opener->request_context();
static_cast<CefBrowserContext*>(new_contents->GetBrowserContext()); DCHECK(request_context);
DCHECK(browser_context);
// We don't officially own |new_contents| until AddNewContents() is called. // We don't officially own |new_contents| until AddNewContents() is called.
// However, we need to install observers/delegates here. // However, we need to install observers/delegates here.
CefRefPtr<CefBrowserHostImpl> browser = CefRefPtr<CefBrowserHostImpl> browser =
CreateInternal(settings, client, new_contents, false, info, opener, false, CreateInternal(settings, client, new_contents, false, info, opener, false,
browser_context->GetCefRequestContext(), request_context, std::move(platform_delegate), nullptr);
std::move(platform_delegate), nullptr);
} }
void CefBrowserHostImpl::DidNavigateMainFramePostCommit( void CefBrowserHostImpl::DidNavigateMainFramePostCommit(
@ -2727,6 +2725,10 @@ void CefBrowserHostImpl::RenderFrameCreated(
browser_info_->frame_tree_node_id_manager()->add_frame_tree_node_id( browser_info_->frame_tree_node_id_manager()->add_frame_tree_node_id(
frame_tree_node_id); frame_tree_node_id);
} }
const bool is_main_frame = (render_frame_host->GetParent() == nullptr);
request_context_->OnRenderFrameCreated(render_process_id, render_routing_id,
is_main_frame, false);
} }
void CefBrowserHostImpl::RenderFrameHostChanged( void CefBrowserHostImpl::RenderFrameHostChanged(
@ -2748,15 +2750,9 @@ void CefBrowserHostImpl::FrameDeleted(
browser_info_->frame_tree_node_id_manager()->remove_frame_tree_node_id( browser_info_->frame_tree_node_id_manager()->remove_frame_tree_node_id(
frame_tree_node_id); frame_tree_node_id);
if (web_contents()) { const bool is_main_frame = (render_frame_host->GetParent() == nullptr);
const bool is_main_frame = (render_frame_host->GetParent() == nullptr); request_context_->OnRenderFrameDeleted(render_process_id, render_routing_id,
CefBrowserContext* context = is_main_frame, false);
static_cast<CefBrowserContext*>(web_contents()->GetBrowserContext());
if (context) {
context->OnRenderFrameDeleted(render_process_id, render_routing_id,
is_main_frame, false);
}
}
base::AutoLock lock_scope(state_lock_); base::AutoLock lock_scope(state_lock_);
@ -3250,7 +3246,7 @@ CefBrowserHostImpl::CefBrowserHostImpl(
content::WebContents* web_contents, content::WebContents* web_contents,
scoped_refptr<CefBrowserInfo> browser_info, scoped_refptr<CefBrowserInfo> browser_info,
CefRefPtr<CefBrowserHostImpl> opener, CefRefPtr<CefBrowserHostImpl> opener,
CefRefPtr<CefRequestContext> request_context, CefRefPtr<CefRequestContextImpl> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate, std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension) CefRefPtr<CefExtension> extension)
: content::WebContentsObserver(web_contents), : content::WebContentsObserver(web_contents),

View File

@ -22,6 +22,7 @@
#include "libcef/browser/frame_host_impl.h" #include "libcef/browser/frame_host_impl.h"
#include "libcef/browser/javascript_dialog_manager.h" #include "libcef/browser/javascript_dialog_manager.h"
#include "libcef/browser/menu_manager.h" #include "libcef/browser/menu_manager.h"
#include "libcef/browser/request_context_impl.h"
#include "libcef/common/response_manager.h" #include "libcef/common/response_manager.h"
#include "base/observer_list.h" #include "base/observer_list.h"
@ -369,6 +370,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
CefRefPtr<CefClient> client() const { return client_; } CefRefPtr<CefClient> client() const { return client_; }
scoped_refptr<CefBrowserInfo> browser_info() const { return browser_info_; } scoped_refptr<CefBrowserInfo> browser_info() const { return browser_info_; }
int browser_id() const; int browser_id() const;
CefRefPtr<CefRequestContextImpl> request_context() const {
return request_context_;
}
// Accessors that must be called on the UI thread. // Accessors that must be called on the UI thread.
content::BrowserContext* GetBrowserContext(); content::BrowserContext* GetBrowserContext();
@ -558,7 +562,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
scoped_refptr<CefBrowserInfo> browser_info, scoped_refptr<CefBrowserInfo> browser_info,
CefRefPtr<CefBrowserHostImpl> opener, CefRefPtr<CefBrowserHostImpl> opener,
bool is_devtools_popup, bool is_devtools_popup,
CefRefPtr<CefRequestContext> request_context, CefRefPtr<CefRequestContextImpl> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate, std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension); CefRefPtr<CefExtension> extension);
@ -588,7 +592,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
content::WebContents* web_contents, content::WebContents* web_contents,
scoped_refptr<CefBrowserInfo> browser_info, scoped_refptr<CefBrowserInfo> browser_info,
CefRefPtr<CefBrowserHostImpl> opener, CefRefPtr<CefBrowserHostImpl> opener,
CefRefPtr<CefRequestContext> request_context, CefRefPtr<CefRequestContextImpl> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate, std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension); CefRefPtr<CefExtension> extension);
@ -672,7 +676,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
CefRefPtr<CefClient> client_; CefRefPtr<CefClient> client_;
scoped_refptr<CefBrowserInfo> browser_info_; scoped_refptr<CefBrowserInfo> browser_info_;
CefWindowHandle opener_; CefWindowHandle opener_;
CefRefPtr<CefRequestContext> request_context_; CefRefPtr<CefRequestContextImpl> request_context_;
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate_; std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate_;
const bool is_windowless_; const bool is_windowless_;
const bool is_views_hosted_; const bool is_views_hosted_;

View File

@ -68,6 +68,10 @@ void CefMimeHandlerViewGuestDelegate::OnGuestAttached(
const int frame_tree_node_id = main_frame_host->GetFrameTreeNodeId(); const int frame_tree_node_id = main_frame_host->GetFrameTreeNodeId();
info->frame_tree_node_id_manager()->add_frame_tree_node_id( info->frame_tree_node_id_manager()->add_frame_tree_node_id(
frame_tree_node_id); frame_tree_node_id);
const bool is_main_frame = (main_frame_host->GetParent() == nullptr);
owner_browser->request_context()->OnRenderFrameCreated(
render_process_id, render_frame_id, is_main_frame, true);
} }
void CefMimeHandlerViewGuestDelegate::OnGuestDetached( void CefMimeHandlerViewGuestDelegate::OnGuestDetached(
@ -90,13 +94,9 @@ void CefMimeHandlerViewGuestDelegate::OnGuestDetached(
info->frame_tree_node_id_manager()->remove_frame_tree_node_id( info->frame_tree_node_id_manager()->remove_frame_tree_node_id(
frame_tree_node_id); frame_tree_node_id);
CefBrowserContext* context = const bool is_main_frame = (main_frame_host->GetParent() == nullptr);
static_cast<CefBrowserContext*>(web_contents->GetBrowserContext()); owner_browser->request_context()->OnRenderFrameDeleted(
if (context) { render_process_id, render_frame_id, is_main_frame, true);
const bool is_main_frame = (main_frame_host->GetParent() == nullptr);
context->OnRenderFrameDeleted(render_process_id, render_frame_id,
is_main_frame, true);
}
} }
bool CefMimeHandlerViewGuestDelegate::HandleContextMenu( bool CefMimeHandlerViewGuestDelegate::HandleContextMenu(

View File

@ -94,7 +94,10 @@ bool CefPluginServiceFilter::IsPluginAvailable(
return true; return true;
} }
CefRefPtr<CefRequestContextHandler> handler = resource_context->GetHandler(); // The |render_frame_id| value may not be valid, so allow matches with any
// handler that shares the same |render_process_id| value.
CefRefPtr<CefRequestContextHandler> handler =
resource_context->GetHandler(render_process_id, render_frame_id, false);
if (!handler) { if (!handler) {
// No handler so go with the default plugin load decision. // No handler so go with the default plugin load decision.
return *status != chrome::mojom::PluginStatus::kDisabled; return *status != chrome::mojom::PluginStatus::kDisabled;

View File

@ -543,6 +543,22 @@ CefRefPtr<CefExtension> CefRequestContextImpl::GetExtension(
return GetBrowserContext()->extension_system()->GetExtension(extension_id); return GetBrowserContext()->extension_system()->GetExtension(extension_id);
} }
void CefRequestContextImpl::OnRenderFrameCreated(int render_process_id,
int render_frame_id,
bool is_main_frame,
bool is_guest_view) {
browser_context_->OnRenderFrameCreated(
this, render_process_id, render_frame_id, is_main_frame, is_guest_view);
}
void CefRequestContextImpl::OnRenderFrameDeleted(int render_process_id,
int render_frame_id,
bool is_main_frame,
bool is_guest_view) {
browser_context_->OnRenderFrameDeleted(
this, render_process_id, render_frame_id, is_main_frame, is_guest_view);
}
// static // static
CefRefPtr<CefRequestContextImpl> CefRefPtr<CefRequestContextImpl>
CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) { CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) {

View File

@ -86,6 +86,22 @@ class CefRequestContextImpl : public CefRequestContext {
const CefRequestContextSettings& settings() const { return config_.settings; } const CefRequestContextSettings& settings() const { return config_.settings; }
// Called from CefBrowserHostImpl::RenderFrameCreated or
// CefMimeHandlerViewGuestDelegate::OnGuestAttached when a render frame is
// created.
void OnRenderFrameCreated(int render_process_id,
int render_frame_id,
bool is_main_frame,
bool is_guest_view);
// Called from CefBrowserHostImpl::FrameDeleted or
// CefMimeHandlerViewGuestDelegate::OnGuestDetached when a render frame is
// deleted.
void OnRenderFrameDeleted(int render_process_id,
int render_frame_id,
bool is_main_frame,
bool is_guest_view);
private: private:
friend class CefRequestContext; friend class CefRequestContext;

View File

@ -23,10 +23,8 @@
#include "net/ssl/client_cert_store_mac.h" #include "net/ssl/client_cert_store_mac.h"
#endif #endif
CefResourceContext::CefResourceContext( CefResourceContext::CefResourceContext(bool is_off_the_record)
bool is_off_the_record, : is_off_the_record_(is_off_the_record) {}
CefRefPtr<CefRequestContextHandler> handler)
: is_off_the_record_(is_off_the_record), handler_(handler) {}
CefResourceContext::~CefResourceContext() {} CefResourceContext::~CefResourceContext() {}
@ -55,6 +53,52 @@ void CefResourceContext::set_extensions_info_map(
extension_info_map_ = extensions_info_map; extension_info_map_ = extensions_info_map;
} }
void CefResourceContext::AddHandler(
int render_process_id,
int render_frame_id,
CefRefPtr<CefRequestContextHandler> handler) {
CEF_REQUIRE_IOT();
DCHECK_GE(render_process_id, 0);
DCHECK(handler);
handler_map_.insert(std::make_pair(
std::make_pair(render_process_id, render_frame_id), handler));
}
void CefResourceContext::RemoveHandler(int render_process_id,
int render_frame_id) {
CEF_REQUIRE_IOT();
DCHECK_GE(render_process_id, 0);
HandlerMap::iterator it =
handler_map_.find(std::make_pair(render_process_id, render_frame_id));
if (it != handler_map_.end())
handler_map_.erase(it);
}
CefRefPtr<CefRequestContextHandler> CefResourceContext::GetHandler(
int render_process_id,
int render_frame_id,
bool require_frame_match) {
CEF_REQUIRE_IOT();
DCHECK_GE(render_process_id, 0);
HandlerMap::const_iterator it =
handler_map_.find(std::make_pair(render_process_id, render_frame_id));
if (it != handler_map_.end())
return it->second;
if (!require_frame_match) {
// Choose an arbitrary handler for the same process.
for (auto& kv : handler_map_) {
if (kv.first.first == render_process_id)
return kv.second;
}
}
return nullptr;
}
void CefResourceContext::AddPluginLoadDecision( void CefResourceContext::AddPluginLoadDecision(
int render_process_id, int render_process_id,
const base::FilePath& plugin_path, const base::FilePath& plugin_path,

View File

@ -28,14 +28,25 @@ class CefURLRequestContextGetter;
// See browser_context.h for an object relationship diagram. // See browser_context.h for an object relationship diagram.
class CefResourceContext : public content::ResourceContext { class CefResourceContext : public content::ResourceContext {
public: public:
CefResourceContext(bool is_off_the_record, explicit CefResourceContext(bool is_off_the_record);
CefRefPtr<CefRequestContextHandler> handler);
~CefResourceContext() override; ~CefResourceContext() override;
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(); std::unique_ptr<net::ClientCertStore> CreateClientCertStore();
void set_extensions_info_map(extensions::InfoMap* extensions_info_map); void set_extensions_info_map(extensions::InfoMap* extensions_info_map);
// Keep track of handlers associated with specific frames. This information
// originates from frame create/delete notifications in CefBrowserHostImpl or
// CefMimeHandlerViewGuestDelegate which are forwarded via
// CefRequestContextImpl and CefBrowserContext.
void AddHandler(int render_process_id,
int render_frame_id,
CefRefPtr<CefRequestContextHandler> handler);
void RemoveHandler(int render_process_id, int render_frame_id);
CefRefPtr<CefRequestContextHandler> GetHandler(int render_process_id,
int render_frame_id,
bool require_frame_match);
// Remember the plugin load decision for plugin status requests that arrive // Remember the plugin load decision for plugin status requests that arrive
// via CefPluginServiceFilter::IsPluginAvailable. // via CefPluginServiceFilter::IsPluginAvailable.
void AddPluginLoadDecision(int render_process_id, void AddPluginLoadDecision(int render_process_id,
@ -58,13 +69,16 @@ class CefResourceContext : public content::ResourceContext {
const extensions::InfoMap* GetExtensionInfoMap() const { const extensions::InfoMap* GetExtensionInfoMap() const {
return extension_info_map_.get(); return extension_info_map_.get();
} }
CefRefPtr<CefRequestContextHandler> GetHandler() const { return handler_; }
private: private:
// Only accessed on the IO thread. // Only accessed on the IO thread.
bool is_off_the_record_; bool is_off_the_record_;
scoped_refptr<extensions::InfoMap> extension_info_map_; scoped_refptr<extensions::InfoMap> extension_info_map_;
CefRefPtr<CefRequestContextHandler> handler_;
// Map of (render_process_id, render_frame_id) to handler.
typedef std::map<std::pair<int, int>, CefRefPtr<CefRequestContextHandler>>
HandlerMap;
HandlerMap handler_map_;
// Map (render_process_id, plugin_path, is_main_frame, main_frame_origin) to // Map (render_process_id, plugin_path, is_main_frame, main_frame_origin) to
// plugin load decision. // plugin load decision.