• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "libcef/browser/browser_context.h"
6 
7 #include <map>
8 #include <utility>
9 
10 #include "libcef/browser/context.h"
11 #include "libcef/browser/media_router/media_router_manager.h"
12 #include "libcef/browser/request_context_impl.h"
13 #include "libcef/browser/thread_util.h"
14 #include "libcef/common/cef_switches.h"
15 #include "libcef/common/frame_util.h"
16 #include "libcef/features/runtime.h"
17 
18 #include "base/files/file_util.h"
19 #include "base/lazy_instance.h"
20 #include "base/logging.h"
21 #include "base/no_destructor.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/string_util.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/browser_task_traits.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/storage_partition.h"
29 
30 using content::BrowserThread;
31 
32 namespace {
33 
34 // Manages the global list of Impl instances.
35 class ImplManager {
36  public:
37   using Vector = std::vector<CefBrowserContext*>;
38 
ImplManager()39   ImplManager() {}
40 
41   ImplManager(const ImplManager&) = delete;
42   ImplManager& operator=(const ImplManager&) = delete;
43 
~ImplManager()44   ~ImplManager() {
45     DCHECK(all_.empty());
46     DCHECK(map_.empty());
47   }
48 
AddImpl(CefBrowserContext * impl)49   void AddImpl(CefBrowserContext* impl) {
50     CEF_REQUIRE_UIT();
51     DCHECK(!IsValidImpl(impl));
52     all_.push_back(impl);
53   }
54 
RemoveImpl(CefBrowserContext * impl,const base::FilePath & path)55   void RemoveImpl(CefBrowserContext* impl, const base::FilePath& path) {
56     CEF_REQUIRE_UIT();
57 
58     Vector::iterator it = GetImplPos(impl);
59     DCHECK(it != all_.end());
60     all_.erase(it);
61 
62     if (!path.empty()) {
63       PathMap::iterator it = map_.find(path);
64       DCHECK(it != map_.end());
65       if (it != map_.end())
66         map_.erase(it);
67     }
68   }
69 
IsValidImpl(const CefBrowserContext * impl)70   bool IsValidImpl(const CefBrowserContext* impl) {
71     CEF_REQUIRE_UIT();
72     return GetImplPos(impl) != all_.end();
73   }
74 
GetImplFromGlobalId(const content::GlobalRenderFrameHostId & global_id,bool require_frame_match)75   CefBrowserContext* GetImplFromGlobalId(
76       const content::GlobalRenderFrameHostId& global_id,
77       bool require_frame_match) {
78     CEF_REQUIRE_UIT();
79     for (const auto& context : all_) {
80       if (context->IsAssociatedContext(global_id, require_frame_match)) {
81         return context;
82       }
83     }
84     return nullptr;
85   }
86 
GetImplFromBrowserContext(const content::BrowserContext * context)87   CefBrowserContext* GetImplFromBrowserContext(
88       const content::BrowserContext* context) {
89     CEF_REQUIRE_UIT();
90     if (!context)
91       return nullptr;
92 
93     for (const auto& bc : all_) {
94       if (bc->AsBrowserContext() == context)
95         return bc;
96     }
97     return nullptr;
98   }
99 
SetImplPath(CefBrowserContext * impl,const base::FilePath & path)100   void SetImplPath(CefBrowserContext* impl, const base::FilePath& path) {
101     CEF_REQUIRE_UIT();
102     DCHECK(!path.empty());
103     DCHECK(IsValidImpl(impl));
104     DCHECK(GetImplFromPath(path) == nullptr);
105     map_.insert(std::make_pair(path, impl));
106   }
107 
GetImplFromPath(const base::FilePath & path)108   CefBrowserContext* GetImplFromPath(const base::FilePath& path) {
109     CEF_REQUIRE_UIT();
110     DCHECK(!path.empty());
111     PathMap::const_iterator it = map_.find(path);
112     if (it != map_.end())
113       return it->second;
114     return nullptr;
115   }
116 
GetAllImpl() const117   const Vector GetAllImpl() const { return all_; }
118 
119  private:
GetImplPos(const CefBrowserContext * impl)120   Vector::iterator GetImplPos(const CefBrowserContext* impl) {
121     Vector::iterator it = all_.begin();
122     for (; it != all_.end(); ++it) {
123       if (*it == impl)
124         return it;
125     }
126     return all_.end();
127   }
128 
129   using PathMap = std::map<base::FilePath, CefBrowserContext*>;
130   PathMap map_;
131 
132   Vector all_;
133 };
134 
135 #if DCHECK_IS_ON()
136 // Because of DCHECK()s in the object destructor.
137 base::LazyInstance<ImplManager>::DestructorAtExit g_manager =
138     LAZY_INSTANCE_INITIALIZER;
139 #else
140 base::LazyInstance<ImplManager>::Leaky g_manager = LAZY_INSTANCE_INITIALIZER;
141 #endif
142 
GetSelf(base::WeakPtr<CefBrowserContext> self)143 CefBrowserContext* GetSelf(base::WeakPtr<CefBrowserContext> self) {
144   CEF_REQUIRE_UIT();
145   return self.get();
146 }
147 
MakeSupportedSchemes(const CefString & schemes_list,bool include_defaults)148 CefBrowserContext::CookieableSchemes MakeSupportedSchemes(
149     const CefString& schemes_list,
150     bool include_defaults) {
151   std::vector<std::string> all_schemes;
152   if (!schemes_list.empty()) {
153     all_schemes =
154         base::SplitString(schemes_list.ToString(), std::string(","),
155                           base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
156   }
157 
158   if (include_defaults) {
159     // Add default schemes that should always support cookies.
160     // This list should match CookieMonster::kDefaultCookieableSchemes.
161     all_schemes.push_back("http");
162     all_schemes.push_back("https");
163     all_schemes.push_back("ws");
164     all_schemes.push_back("wss");
165   }
166 
167   return absl::make_optional(all_schemes);
168 }
169 
170 }  // namespace
171 
CefBrowserContext(const CefRequestContextSettings & settings)172 CefBrowserContext::CefBrowserContext(const CefRequestContextSettings& settings)
173     : settings_(settings), weak_ptr_factory_(this) {
174   g_manager.Get().AddImpl(this);
175   getter_ = base::BindRepeating(GetSelf, weak_ptr_factory_.GetWeakPtr());
176 }
177 
~CefBrowserContext()178 CefBrowserContext::~CefBrowserContext() {
179   CEF_REQUIRE_UIT();
180 #if DCHECK_IS_ON()
181   DCHECK(is_shutdown_);
182 #endif
183 }
184 
Initialize()185 void CefBrowserContext::Initialize() {
186   cache_path_ = base::FilePath(CefString(&settings_.cache_path));
187 
188   if (!cache_path_.empty())
189     g_manager.Get().SetImplPath(this, cache_path_);
190 
191   iothread_state_ = base::MakeRefCounted<CefIOThreadState>();
192 
193   if (settings_.cookieable_schemes_list.length > 0 ||
194       settings_.cookieable_schemes_exclude_defaults) {
195     cookieable_schemes_ =
196         MakeSupportedSchemes(CefString(&settings_.cookieable_schemes_list),
197                              !settings_.cookieable_schemes_exclude_defaults);
198   }
199 }
200 
Shutdown()201 void CefBrowserContext::Shutdown() {
202   CEF_REQUIRE_UIT();
203 
204 #if DCHECK_IS_ON()
205   is_shutdown_ = true;
206 #endif
207 
208   // No CefRequestContext should be referencing this object any longer.
209   DCHECK(request_context_set_.empty());
210 
211   // Unregister the context first to avoid re-entrancy during shutdown.
212   g_manager.Get().RemoveImpl(this, cache_path_);
213 
214   // Destroy objects that may hold references to the MediaRouter.
215   media_router_manager_.reset();
216 
217   // Invalidate any Getter references to this object.
218   weak_ptr_factory_.InvalidateWeakPtrs();
219 }
220 
AddCefRequestContext(CefRequestContextImpl * context)221 void CefBrowserContext::AddCefRequestContext(CefRequestContextImpl* context) {
222   CEF_REQUIRE_UIT();
223   request_context_set_.insert(context);
224 }
225 
RemoveCefRequestContext(CefRequestContextImpl * context)226 void CefBrowserContext::RemoveCefRequestContext(
227     CefRequestContextImpl* context) {
228   CEF_REQUIRE_UIT();
229 
230   request_context_set_.erase(context);
231 
232   // Delete ourselves when the reference count reaches zero.
233   if (request_context_set_.empty()) {
234     Shutdown();
235 
236     // Allow the current call stack to unwind before deleting |this|.
237     content::BrowserThread::DeleteSoon(CEF_UIT, FROM_HERE, this);
238   }
239 }
240 
241 // static
FromCachePath(const base::FilePath & cache_path)242 CefBrowserContext* CefBrowserContext::FromCachePath(
243     const base::FilePath& cache_path) {
244   return g_manager.Get().GetImplFromPath(cache_path);
245 }
246 
247 // static
FromGlobalId(const content::GlobalRenderFrameHostId & global_id,bool require_frame_match)248 CefBrowserContext* CefBrowserContext::FromGlobalId(
249     const content::GlobalRenderFrameHostId& global_id,
250     bool require_frame_match) {
251   return g_manager.Get().GetImplFromGlobalId(global_id, require_frame_match);
252 }
253 
254 // static
FromBrowserContext(const content::BrowserContext * context)255 CefBrowserContext* CefBrowserContext::FromBrowserContext(
256     const content::BrowserContext* context) {
257   return g_manager.Get().GetImplFromBrowserContext(context);
258 }
259 
260 // static
FromProfile(const Profile * profile)261 CefBrowserContext* CefBrowserContext::FromProfile(const Profile* profile) {
262   auto* cef_context = FromBrowserContext(profile);
263   if (cef_context)
264     return cef_context;
265 
266   if (cef::IsChromeRuntimeEnabled()) {
267     auto* original_profile = profile->GetOriginalProfile();
268     if (original_profile != profile) {
269       // With the Chrome runtime if the user launches an incognito window via
270       // the UI we might be associated with the original Profile instead of the
271       // (current) incognito profile.
272       return FromBrowserContext(original_profile);
273     }
274   }
275 
276   return nullptr;
277 }
278 
279 // static
GetAll()280 std::vector<CefBrowserContext*> CefBrowserContext::GetAll() {
281   return g_manager.Get().GetAllImpl();
282 }
283 
OnRenderFrameCreated(CefRequestContextImpl * request_context,const content::GlobalRenderFrameHostId & global_id,bool is_main_frame,bool is_guest_view)284 void CefBrowserContext::OnRenderFrameCreated(
285     CefRequestContextImpl* request_context,
286     const content::GlobalRenderFrameHostId& global_id,
287     bool is_main_frame,
288     bool is_guest_view) {
289   CEF_REQUIRE_UIT();
290   DCHECK(frame_util::IsValidGlobalId(global_id));
291 
292   render_id_set_.insert(global_id);
293 
294   CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
295   if (handler) {
296     handler_map_.AddHandler(global_id, handler);
297 
298     CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::AddHandler,
299                                           iothread_state_, global_id, handler));
300   }
301 }
302 
OnRenderFrameDeleted(CefRequestContextImpl * request_context,const content::GlobalRenderFrameHostId & global_id,bool is_main_frame,bool is_guest_view)303 void CefBrowserContext::OnRenderFrameDeleted(
304     CefRequestContextImpl* request_context,
305     const content::GlobalRenderFrameHostId& global_id,
306     bool is_main_frame,
307     bool is_guest_view) {
308   CEF_REQUIRE_UIT();
309   DCHECK(frame_util::IsValidGlobalId(global_id));
310 
311   auto it1 = render_id_set_.find(global_id);
312   if (it1 != render_id_set_.end())
313     render_id_set_.erase(it1);
314 
315   CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
316   if (handler) {
317     handler_map_.RemoveHandler(global_id);
318 
319     CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::RemoveHandler,
320                                           iothread_state_, global_id));
321   }
322 }
323 
GetHandler(const content::GlobalRenderFrameHostId & global_id,bool require_frame_match) const324 CefRefPtr<CefRequestContextHandler> CefBrowserContext::GetHandler(
325     const content::GlobalRenderFrameHostId& global_id,
326     bool require_frame_match) const {
327   CEF_REQUIRE_UIT();
328   return handler_map_.GetHandler(global_id, require_frame_match);
329 }
330 
IsAssociatedContext(const content::GlobalRenderFrameHostId & global_id,bool require_frame_match) const331 bool CefBrowserContext::IsAssociatedContext(
332     const content::GlobalRenderFrameHostId& global_id,
333     bool require_frame_match) const {
334   CEF_REQUIRE_UIT();
335 
336   if (frame_util::IsValidGlobalId(global_id)) {
337     const auto it1 = render_id_set_.find(global_id);
338     if (it1 != render_id_set_.end())
339       return true;
340   }
341 
342   if (frame_util::IsValidChildId(global_id.child_id) && !require_frame_match) {
343     // Choose an arbitrary handler for the same process.
344     for (const auto& render_ids : render_id_set_) {
345       if (render_ids.child_id == global_id.child_id)
346         return true;
347     }
348   }
349 
350   return false;
351 }
352 
RegisterSchemeHandlerFactory(const CefString & scheme_name,const CefString & domain_name,CefRefPtr<CefSchemeHandlerFactory> factory)353 void CefBrowserContext::RegisterSchemeHandlerFactory(
354     const CefString& scheme_name,
355     const CefString& domain_name,
356     CefRefPtr<CefSchemeHandlerFactory> factory) {
357   CEF_POST_TASK(
358       CEF_IOT,
359       base::BindOnce(&CefIOThreadState::RegisterSchemeHandlerFactory,
360                      iothread_state_, scheme_name, domain_name, factory));
361 }
362 
ClearSchemeHandlerFactories()363 void CefBrowserContext::ClearSchemeHandlerFactories() {
364   CEF_POST_TASK(CEF_IOT,
365                 base::BindOnce(&CefIOThreadState::ClearSchemeHandlerFactories,
366                                iothread_state_));
367 }
368 
LoadExtension(const CefString & root_directory,CefRefPtr<CefDictionaryValue> manifest,CefRefPtr<CefExtensionHandler> handler,CefRefPtr<CefRequestContext> loader_context)369 void CefBrowserContext::LoadExtension(
370     const CefString& root_directory,
371     CefRefPtr<CefDictionaryValue> manifest,
372     CefRefPtr<CefExtensionHandler> handler,
373     CefRefPtr<CefRequestContext> loader_context) {
374   NOTIMPLEMENTED();
375   if (handler)
376     handler->OnExtensionLoadFailed(ERR_ABORTED);
377 }
378 
GetExtensions(std::vector<CefString> & extension_ids)379 bool CefBrowserContext::GetExtensions(std::vector<CefString>& extension_ids) {
380   NOTIMPLEMENTED();
381   return false;
382 }
383 
GetExtension(const CefString & extension_id)384 CefRefPtr<CefExtension> CefBrowserContext::GetExtension(
385     const CefString& extension_id) {
386   NOTIMPLEMENTED();
387   return nullptr;
388 }
389 
UnloadExtension(const CefString & extension_id)390 bool CefBrowserContext::UnloadExtension(const CefString& extension_id) {
391   NOTIMPLEMENTED();
392   return false;
393 }
394 
IsPrintPreviewSupported() const395 bool CefBrowserContext::IsPrintPreviewSupported() const {
396   return true;
397 }
398 
GetNetworkContext()399 network::mojom::NetworkContext* CefBrowserContext::GetNetworkContext() {
400   CEF_REQUIRE_UIT();
401   auto browser_context = AsBrowserContext();
402   return browser_context->GetDefaultStoragePartition()->GetNetworkContext();
403 }
404 
GetMediaRouterManager()405 CefMediaRouterManager* CefBrowserContext::GetMediaRouterManager() {
406   CEF_REQUIRE_UIT();
407   if (!media_router_manager_) {
408     media_router_manager_.reset(new CefMediaRouterManager(AsBrowserContext()));
409   }
410   return media_router_manager_.get();
411 }
412 
GetCookieableSchemes() const413 CefBrowserContext::CookieableSchemes CefBrowserContext::GetCookieableSchemes()
414     const {
415   CEF_REQUIRE_UIT();
416   if (cookieable_schemes_)
417     return cookieable_schemes_;
418 
419   return GetGlobalCookieableSchemes();
420 }
421 
422 // static
423 CefBrowserContext::CookieableSchemes
GetGlobalCookieableSchemes()424 CefBrowserContext::GetGlobalCookieableSchemes() {
425   CEF_REQUIRE_UIT();
426 
427   static base::NoDestructor<CookieableSchemes> schemes(
428       []() -> CookieableSchemes {
429         const auto& settings = CefContext::Get()->settings();
430         if (settings.cookieable_schemes_list.length > 0 ||
431             settings.cookieable_schemes_exclude_defaults) {
432           return MakeSupportedSchemes(
433               CefString(&settings.cookieable_schemes_list),
434               !settings.cookieable_schemes_exclude_defaults);
435         }
436         return absl::nullopt;
437       }());
438   return *schemes;
439 }
440