diff --git a/cef.gyp b/cef.gyp index e92c78bd3..0a0af99cb 100644 --- a/cef.gyp +++ b/cef.gyp @@ -900,6 +900,9 @@ '<(DEPTH)/components/components.gyp:update_client', '<(DEPTH)/components/components.gyp:user_prefs', '<(DEPTH)/components/components.gyp:version_info', + '<(DEPTH)/components/components.gyp:visitedlink_browser', + '<(DEPTH)/components/components.gyp:visitedlink_common', + '<(DEPTH)/components/components.gyp:visitedlink_renderer', '<(DEPTH)/components/components.gyp:web_cache_renderer', '<(DEPTH)/components/url_formatter/url_formatter.gyp:url_formatter', '<(DEPTH)/content/content.gyp:content_app_both', diff --git a/libcef/browser/browser_context.h b/libcef/browser/browser_context.h index 96e7ceeff..6f8be6b4b 100644 --- a/libcef/browser/browser_context.h +++ b/libcef/browser/browser_context.h @@ -152,6 +152,10 @@ class CefBrowserContext // Settings for plugins and extensions. virtual HostContentSettingsMap* GetHostContentSettingsMap() = 0; + // Called from CefBrowserHostImpl::DidNavigateAnyFrame to update the table of + // visited links. + virtual void AddVisitedURLs(const std::vector& urls) = 0; + CefResourceContext* resource_context() const { return resource_context_.get(); } diff --git a/libcef/browser/browser_context_impl.cc b/libcef/browser/browser_context_impl.cc index 80124e34a..8528edb02 100644 --- a/libcef/browser/browser_context_impl.cc +++ b/libcef/browser/browser_context_impl.cc @@ -30,6 +30,8 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/guest_view/browser/guest_view_manager.h" #include "components/ui/zoom/zoom_event_manager.h" +#include "components/visitedlink/browser/visitedlink_event_listener.h" +#include "components/visitedlink/browser/visitedlink_master.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" @@ -129,6 +131,69 @@ base::LazyInstance g_manager = LAZY_INSTANCE_INITIALIZER; } // namespace +// Creates and manages VisitedLinkEventListener objects for each +// CefBrowserContext sharing the same VisitedLinkMaster. +class CefVisitedLinkListener : public visitedlink::VisitedLinkMaster::Listener { + public: + CefVisitedLinkListener() + : master_(nullptr) { + } + + void set_master(visitedlink::VisitedLinkMaster* master) { + DCHECK(!master_); + master_ = master; + } + + void CreateListenerForContext(const CefBrowserContext* context) { + CEF_REQUIRE_UIT(); + scoped_ptr listener( + new visitedlink::VisitedLinkEventListener( + master_, const_cast(context))); + listener_map_.insert(std::make_pair(context, std::move(listener))); + } + + void RemoveListenerForContext(const CefBrowserContext* context) { + CEF_REQUIRE_UIT(); + ListenerMap::iterator it = listener_map_.find(context); + DCHECK(it != listener_map_.end()); + listener_map_.erase(it); + } + + // visitedlink::VisitedLinkMaster::Listener methods. + + void NewTable(base::SharedMemory* shared_memory) override { + CEF_REQUIRE_UIT(); + ListenerMap::iterator it = listener_map_.begin(); + for (; it != listener_map_.end(); ++it) + it->second->NewTable(shared_memory); + } + + void Add(visitedlink::VisitedLinkCommon::Fingerprint fingerprint) override { + CEF_REQUIRE_UIT(); + ListenerMap::iterator it = listener_map_.begin(); + for (; it != listener_map_.end(); ++it) + it->second->Add(fingerprint); + } + + void Reset(bool invalidate_hashes) override { + CEF_REQUIRE_UIT(); + ListenerMap::iterator it = listener_map_.begin(); + for (; it != listener_map_.end(); ++it) + it->second->Reset(invalidate_hashes); + } + + private: + visitedlink::VisitedLinkMaster* master_; + + // Map of CefBrowserContext to the associated VisitedLinkEventListener. + typedef std::map > + ListenerMap; + ListenerMap listener_map_; + + DISALLOW_COPY_AND_ASSIGN(CefVisitedLinkListener); +}; + CefBrowserContextImpl::CefBrowserContextImpl( const CefRequestContextSettings& settings) : settings_(settings) { @@ -183,6 +248,19 @@ void CefBrowserContextImpl::Initialize() { pref_path = cache_path_.AppendASCII(browser_prefs::kUserPrefsFileName); pref_service_ = browser_prefs::CreatePrefService(pref_path); + // Initialize visited links management. + base::FilePath visited_link_path; + if (!cache_path_.empty()) + visited_link_path = cache_path_.Append(FILE_PATH_LITERAL("Visited Links")); + visitedlink_listener_ = new CefVisitedLinkListener; + visitedlink_master_.reset( + new visitedlink::VisitedLinkMaster(visitedlink_listener_, this, + !visited_link_path.empty(), false, + visited_link_path, 0)); + visitedlink_listener_->set_master(visitedlink_master_.get()); + visitedlink_listener_->CreateListenerForContext(this); + visitedlink_master_->Init(); + CefBrowserContext::Initialize(); // Initialize proxy configuration tracker. @@ -202,10 +280,15 @@ 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) { @@ -412,3 +495,13 @@ HostContentSettingsMap* CefBrowserContextImpl::GetHostContentSettingsMap() { } return host_content_settings_map_.get(); } + +void CefBrowserContextImpl::AddVisitedURLs(const std::vector& urls) { + visitedlink_master_->AddURLs(urls); +} + +void CefBrowserContextImpl::RebuildTable( + const scoped_refptr& enumerator) { + // Called when visited links will not or cannot be loaded from disk. + enumerator->OnComplete(true); +} diff --git a/libcef/browser/browser_context_impl.h b/libcef/browser/browser_context_impl.h index 928a55984..e28cfb069 100644 --- a/libcef/browser/browser_context_impl.h +++ b/libcef/browser/browser_context_impl.h @@ -14,16 +14,23 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "components/proxy_config/pref_proxy_config_tracker.h" +#include "components/visitedlink/browser/visitedlink_delegate.h" class CefBrowserContextProxy; class CefDownloadManagerDelegate; class CefSSLHostStateDelegate; +class CefVisitedLinkListener; + +namespace visitedlink { +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. -class CefBrowserContextImpl : public CefBrowserContext { +class CefBrowserContextImpl : public CefBrowserContext, + public visitedlink::VisitedLinkDelegate { public: explicit CefBrowserContextImpl(const CefRequestContextSettings& settings); @@ -88,6 +95,10 @@ class CefBrowserContextImpl : public CefBrowserContext { content::URLRequestInterceptorScopedVector request_interceptors) override; HostContentSettingsMap* GetHostContentSettingsMap() override; + void AddVisitedURLs(const std::vector& urls) override; + + // visitedlink::VisitedLinkDelegate methods. + void RebuildTable(const scoped_refptr& enumerator) override; // Guaranteed to exist once this object has been initialized. scoped_refptr request_context() const { @@ -118,6 +129,9 @@ class CefBrowserContextImpl : public CefBrowserContext { scoped_ptr permission_manager_; scoped_ptr ssl_host_state_delegate_; scoped_refptr host_content_settings_map_; + scoped_ptr visitedlink_master_; + // |visitedlink_listener_| is owned by visitedlink_master_. + CefVisitedLinkListener* visitedlink_listener_; DISALLOW_COPY_AND_ASSIGN(CefBrowserContextImpl); }; diff --git a/libcef/browser/browser_context_proxy.cc b/libcef/browser/browser_context_proxy.cc index 6e2c18e65..5867d30e3 100644 --- a/libcef/browser/browser_context_proxy.cc +++ b/libcef/browser/browser_context_proxy.cc @@ -12,6 +12,7 @@ #include "base/logging.h" #include "chrome/browser/font_family_cache.h" #include "components/guest_view/common/guest_view_constants.h" +#include "components/visitedlink/browser/visitedlink_master.h" #include "content/browser/streams/stream_context.h" #include "content/public/browser/storage_partition.h" @@ -196,3 +197,7 @@ net::URLRequestContextGetter* HostContentSettingsMap* CefBrowserContextProxy::GetHostContentSettingsMap() { return parent_->GetHostContentSettingsMap(); } + +void CefBrowserContextProxy::AddVisitedURLs(const std::vector& urls) { + parent_->AddVisitedURLs(urls); +} diff --git a/libcef/browser/browser_context_proxy.h b/libcef/browser/browser_context_proxy.h index 9e77b0248..4bb252a60 100644 --- a/libcef/browser/browser_context_proxy.h +++ b/libcef/browser/browser_context_proxy.h @@ -70,6 +70,7 @@ class CefBrowserContextProxy : public CefBrowserContext { content::URLRequestInterceptorScopedVector request_interceptors) override; HostContentSettingsMap* GetHostContentSettingsMap() override; + void AddVisitedURLs(const std::vector& urls) override; scoped_refptr parent() const { return parent_; diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 7e4274219..170764611 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -2403,6 +2403,21 @@ void CefBrowserHostImpl::FrameDeleted( focused_frame_id_ = CefFrameHostImpl::kInvalidFrameId; } +void CefBrowserHostImpl::DidNavigateAnyFrame( + content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + if (!web_contents()) + return; + + scoped_refptr context = + static_cast(web_contents()->GetBrowserContext()); + if (!context.get()) + return; + + context->AddVisitedURLs(params.redirects); +} + void CefBrowserHostImpl::TitleWasSet(content::NavigationEntry* entry, bool explicit_set) { // |entry| may be NULL if a popup is created via window.open and never diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index ebf038a10..a0e09290b 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -406,6 +406,10 @@ class CefBrowserHostImpl : public CefBrowserHost, bool was_ignored_by_handler) override; void FrameDeleted( content::RenderFrameHost* render_frame_host) override; + void DidNavigateAnyFrame( + content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override; void PluginCrashed(const base::FilePath& plugin_path, base::ProcessId plugin_pid) override; diff --git a/libcef/renderer/content_renderer_client.cc b/libcef/renderer/content_renderer_client.cc index 3b3f494a8..80908417f 100644 --- a/libcef/renderer/content_renderer_client.cc +++ b/libcef/renderer/content_renderer_client.cc @@ -50,6 +50,7 @@ #include "components/content_settings/core/common/content_settings_types.h" #include "components/nacl/common/nacl_constants.h" #include "components/printing/renderer/print_web_view_helper.h" +#include "components/visitedlink/renderer/visitedlink_slave.h" #include "components/web_cache/renderer/web_cache_render_process_observer.h" #include "content/common/frame_messages.h" #include "content/public/browser/browser_thread.h" @@ -391,6 +392,9 @@ void CefContentRendererClient::RenderThreadStarted() { thread->AddObserver(spellcheck_.get()); } + visited_link_slave_.reset(new visitedlink::VisitedLinkSlave()); + thread->AddObserver(visited_link_slave_.get()); + if (content::RenderProcessHost::run_renderer_in_process()) { // When running in single-process mode register as a destruction observer // on the render thread's MessageLoop. @@ -596,6 +600,15 @@ bool CefContentRendererClient::WillSendRequest( return false; } +unsigned long long CefContentRendererClient::VisitedLinkHash( + const char* canonical_url, size_t length) { + return visited_link_slave_->ComputeURLFingerprint(canonical_url, length); +} + +bool CefContentRendererClient::IsLinkVisited(unsigned long long link_hash) { + return visited_link_slave_->IsVisited(link_hash); +} + content::BrowserPluginDelegate* CefContentRendererClient::CreateBrowserPluginDelegate( content::RenderFrame* render_frame, diff --git a/libcef/renderer/content_renderer_client.h b/libcef/renderer/content_renderer_client.h index f3bb275ef..16c8e0fc2 100644 --- a/libcef/renderer/content_renderer_client.h +++ b/libcef/renderer/content_renderer_client.h @@ -30,6 +30,10 @@ class ExtensionsRendererClient; class ResourceRequestPolicy; } +namespace visitedlink { +class VisitedLinkSlave; +} + namespace web_cache { class WebCacheRenderProcessObserver; } @@ -116,6 +120,9 @@ class CefContentRendererClient : public content::ContentRendererClient, const GURL& url, const GURL& first_party_for_cookies, GURL* new_url) override; + unsigned long long VisitedLinkHash(const char* canonical_url, + size_t length) override; + bool IsLinkVisited(unsigned long long link_hash) override; content::BrowserPluginDelegate* CreateBrowserPluginDelegate( content::RenderFrame* render_frame, const std::string& mime_type, @@ -145,6 +152,7 @@ class CefContentRendererClient : public content::ContentRendererClient, scoped_ptr observer_; scoped_ptr web_cache_observer_; scoped_ptr spellcheck_; + scoped_ptr visited_link_slave_; // Map of RenderView pointers to CefBrowserImpl references. typedef std::map > BrowserMap; diff --git a/tests/cefclient/browser/root_window_manager.cc b/tests/cefclient/browser/root_window_manager.cc index f6cbfd65e..4d8186ba6 100644 --- a/tests/cefclient/browser/root_window_manager.cc +++ b/tests/cefclient/browser/root_window_manager.cc @@ -49,6 +49,8 @@ RootWindowManager::RootWindowManager(bool terminate_when_all_windows_closed) DCHECK(command_line.get()); request_context_per_browser_ = command_line->HasSwitch(switches::kRequestContextPerBrowser); + request_context_shared_cache_ = + command_line->HasSwitch(switches::kRequestContextSharedCache); } RootWindowManager::~RootWindowManager() { @@ -147,12 +149,19 @@ CefRefPtr RootWindowManager::GetRequestContext( CefRefPtr command_line = CefCommandLine::GetGlobalCommandLine(); if (command_line->HasSwitch(switches::kCachePath)) { - // If a global cache path value is specified then give each browser a - // unique cache path. - std::stringstream ss; - ss << command_line->GetSwitchValue(switches::kCachePath).ToString() << - time(NULL); - CefString(&settings.cache_path) = ss.str(); + if (request_context_shared_cache_) { + // Give each browser the same cache path. The resulting context objects + // will share the same storage internally. + CefString(&settings.cache_path) = + command_line->GetSwitchValue(switches::kCachePath); + } else { + // Give each browser a unique cache path. This will create completely + // isolated context objects. + std::stringstream ss; + ss << command_line->GetSwitchValue(switches::kCachePath).ToString() << + time(NULL); + CefString(&settings.cache_path) = ss.str(); + } } return CefRequestContext::CreateContext(settings, diff --git a/tests/cefclient/browser/root_window_manager.h b/tests/cefclient/browser/root_window_manager.h index d2abdd994..e815c3501 100644 --- a/tests/cefclient/browser/root_window_manager.h +++ b/tests/cefclient/browser/root_window_manager.h @@ -72,6 +72,7 @@ class RootWindowManager : public RootWindow::Delegate { const bool terminate_when_all_windows_closed_; bool request_context_per_browser_; + bool request_context_shared_cache_; // Existing root windows. Only accessed on the main thread. typedef std::set > RootWindowSet; diff --git a/tests/cefclient/common/client_switches.cc b/tests/cefclient/common/client_switches.cc index 27442ebfe..f1a045292 100644 --- a/tests/cefclient/common/client_switches.cc +++ b/tests/cefclient/common/client_switches.cc @@ -26,6 +26,7 @@ const char kTransparentPaintingEnabled[] = "transparent-painting-enabled"; const char kShowUpdateRect[] = "show-update-rect"; const char kMouseCursorChangeDisabled[] = "mouse-cursor-change-disabled"; const char kRequestContextPerBrowser[] = "request-context-per-browser"; +const char kRequestContextSharedCache[] = "request-context-shared-cache"; const char kBackgroundColor[] = "background-color"; const char kEnableGPU[] = "enable-gpu"; const char kFilterURL[] = "filter-url"; diff --git a/tests/cefclient/common/client_switches.h b/tests/cefclient/common/client_switches.h index 797d54ede..29c7182e5 100644 --- a/tests/cefclient/common/client_switches.h +++ b/tests/cefclient/common/client_switches.h @@ -20,6 +20,7 @@ extern const char kTransparentPaintingEnabled[]; extern const char kShowUpdateRect[]; extern const char kMouseCursorChangeDisabled[]; extern const char kRequestContextPerBrowser[]; +extern const char kRequestContextSharedCache[]; extern const char kBackgroundColor[]; extern const char kEnableGPU[]; extern const char kFilterURL[];