• 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/features/runtime.h"
16 
17 #include "base/files/file_util.h"
18 #include "base/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/no_destructor.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_util.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_task_traits.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/storage_partition.h"
28 
29 using content::BrowserThread;
30 
31 namespace {
32 
33 // Manages the global list of Impl instances.
34 class ImplManager {
35  public:
36   typedef std::vector<CefBrowserContext*> Vector;
37 
ImplManager()38   ImplManager() {}
~ImplManager()39   ~ImplManager() {
40     DCHECK(all_.empty());
41     DCHECK(map_.empty());
42   }
43 
AddImpl(CefBrowserContext * impl)44   void AddImpl(CefBrowserContext* impl) {
45     CEF_REQUIRE_UIT();
46     DCHECK(!IsValidImpl(impl));
47     all_.push_back(impl);
48   }
49 
RemoveImpl(CefBrowserContext * impl,const base::FilePath & path)50   void RemoveImpl(CefBrowserContext* impl, const base::FilePath& path) {
51     CEF_REQUIRE_UIT();
52 
53     Vector::iterator it = GetImplPos(impl);
54     DCHECK(it != all_.end());
55     all_.erase(it);
56 
57     if (!path.empty()) {
58       PathMap::iterator it = map_.find(path);
59       DCHECK(it != map_.end());
60       if (it != map_.end())
61         map_.erase(it);
62     }
63   }
64 
IsValidImpl(const CefBrowserContext * impl)65   bool IsValidImpl(const CefBrowserContext* impl) {
66     CEF_REQUIRE_UIT();
67     return GetImplPos(impl) != all_.end();
68   }
69 
GetImplFromIDs(int render_process_id,int render_frame_id,int frame_tree_node_id,bool require_frame_match)70   CefBrowserContext* GetImplFromIDs(int render_process_id,
71                                     int render_frame_id,
72                                     int frame_tree_node_id,
73                                     bool require_frame_match) {
74     CEF_REQUIRE_UIT();
75     for (const auto& context : all_) {
76       if (context->IsAssociatedContext(render_process_id, render_frame_id,
77                                        frame_tree_node_id,
78                                        require_frame_match)) {
79         return context;
80       }
81     }
82     return nullptr;
83   }
84 
GetImplFromBrowserContext(const content::BrowserContext * context)85   CefBrowserContext* GetImplFromBrowserContext(
86       const content::BrowserContext* context) {
87     CEF_REQUIRE_UIT();
88     if (!context)
89       return nullptr;
90 
91     for (const auto& bc : all_) {
92       if (bc->AsBrowserContext() == context)
93         return bc;
94     }
95     return nullptr;
96   }
97 
SetImplPath(CefBrowserContext * impl,const base::FilePath & path)98   void SetImplPath(CefBrowserContext* impl, const base::FilePath& path) {
99     CEF_REQUIRE_UIT();
100     DCHECK(!path.empty());
101     DCHECK(IsValidImpl(impl));
102     DCHECK(GetImplFromPath(path) == nullptr);
103     map_.insert(std::make_pair(path, impl));
104   }
105 
GetImplFromPath(const base::FilePath & path)106   CefBrowserContext* GetImplFromPath(const base::FilePath& path) {
107     CEF_REQUIRE_UIT();
108     DCHECK(!path.empty());
109     PathMap::const_iterator it = map_.find(path);
110     if (it != map_.end())
111       return it->second;
112     return nullptr;
113   }
114 
GetAllImpl() const115   const Vector GetAllImpl() const { return all_; }
116 
117  private:
GetImplPos(const CefBrowserContext * impl)118   Vector::iterator GetImplPos(const CefBrowserContext* impl) {
119     Vector::iterator it = all_.begin();
120     for (; it != all_.end(); ++it) {
121       if (*it == impl)
122         return it;
123     }
124     return all_.end();
125   }
126 
127   typedef std::map<base::FilePath, CefBrowserContext*> PathMap;
128   PathMap map_;
129 
130   Vector all_;
131 
132   DISALLOW_COPY_AND_ASSIGN(ImplManager);
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 base::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 
AddCefRequestContext(CefRequestContextImpl * context)218 void CefBrowserContext::AddCefRequestContext(CefRequestContextImpl* context) {
219   CEF_REQUIRE_UIT();
220   request_context_set_.insert(context);
221 }
222 
RemoveCefRequestContext(CefRequestContextImpl * context)223 void CefBrowserContext::RemoveCefRequestContext(
224     CefRequestContextImpl* context) {
225   CEF_REQUIRE_UIT();
226 
227   request_context_set_.erase(context);
228 
229   // Delete ourselves when the reference count reaches zero.
230   if (request_context_set_.empty()) {
231     Shutdown();
232     delete this;
233   }
234 }
235 
236 // static
FromCachePath(const base::FilePath & cache_path)237 CefBrowserContext* CefBrowserContext::FromCachePath(
238     const base::FilePath& cache_path) {
239   return g_manager.Get().GetImplFromPath(cache_path);
240 }
241 
242 // static
FromIDs(int render_process_id,int render_frame_id,int frame_tree_node_id,bool require_frame_match)243 CefBrowserContext* CefBrowserContext::FromIDs(int render_process_id,
244                                               int render_frame_id,
245                                               int frame_tree_node_id,
246                                               bool require_frame_match) {
247   return g_manager.Get().GetImplFromIDs(render_process_id, render_frame_id,
248                                         frame_tree_node_id,
249                                         require_frame_match);
250 }
251 
252 // static
FromBrowserContext(const content::BrowserContext * context)253 CefBrowserContext* CefBrowserContext::FromBrowserContext(
254     const content::BrowserContext* context) {
255   return g_manager.Get().GetImplFromBrowserContext(context);
256 }
257 
258 // static
FromProfile(const Profile * profile)259 CefBrowserContext* CefBrowserContext::FromProfile(const Profile* profile) {
260   auto* cef_context = FromBrowserContext(profile);
261   if (cef_context)
262     return cef_context;
263 
264   if (cef::IsChromeRuntimeEnabled()) {
265     auto* original_profile = profile->GetOriginalProfile();
266     if (original_profile != profile) {
267       // With the Chrome runtime if the user launches an incognito window via
268       // the UI we might be associated with the original Profile instead of the
269       // (current) incognito profile.
270       return FromBrowserContext(original_profile);
271     }
272   }
273 
274   return nullptr;
275 }
276 
277 // static
GetAll()278 std::vector<CefBrowserContext*> CefBrowserContext::GetAll() {
279   return g_manager.Get().GetAllImpl();
280 }
281 
OnRenderFrameCreated(CefRequestContextImpl * request_context,int render_process_id,int render_frame_id,int frame_tree_node_id,bool is_main_frame,bool is_guest_view)282 void CefBrowserContext::OnRenderFrameCreated(
283     CefRequestContextImpl* request_context,
284     int render_process_id,
285     int render_frame_id,
286     int frame_tree_node_id,
287     bool is_main_frame,
288     bool is_guest_view) {
289   CEF_REQUIRE_UIT();
290   DCHECK_GE(render_process_id, 0);
291   DCHECK_GE(render_frame_id, 0);
292   DCHECK_GE(frame_tree_node_id, 0);
293 
294   render_id_set_.insert(std::make_pair(render_process_id, render_frame_id));
295   node_id_set_.insert(frame_tree_node_id);
296 
297   CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
298   if (handler) {
299     handler_map_.AddHandler(render_process_id, render_frame_id,
300                             frame_tree_node_id, handler);
301 
302     CEF_POST_TASK(CEF_IOT,
303                   base::Bind(&CefIOThreadState::AddHandler, iothread_state_,
304                              render_process_id, render_frame_id,
305                              frame_tree_node_id, handler));
306   }
307 }
308 
OnRenderFrameDeleted(CefRequestContextImpl * request_context,int render_process_id,int render_frame_id,int frame_tree_node_id,bool is_main_frame,bool is_guest_view)309 void CefBrowserContext::OnRenderFrameDeleted(
310     CefRequestContextImpl* request_context,
311     int render_process_id,
312     int render_frame_id,
313     int frame_tree_node_id,
314     bool is_main_frame,
315     bool is_guest_view) {
316   CEF_REQUIRE_UIT();
317   DCHECK_GE(render_process_id, 0);
318   DCHECK_GE(render_frame_id, 0);
319   DCHECK_GE(frame_tree_node_id, 0);
320 
321   auto it1 =
322       render_id_set_.find(std::make_pair(render_process_id, render_frame_id));
323   if (it1 != render_id_set_.end())
324     render_id_set_.erase(it1);
325 
326   auto it2 = node_id_set_.find(frame_tree_node_id);
327   if (it2 != node_id_set_.end())
328     node_id_set_.erase(it2);
329 
330   CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
331   if (handler) {
332     handler_map_.RemoveHandler(render_process_id, render_frame_id,
333                                frame_tree_node_id);
334 
335     CEF_POST_TASK(CEF_IOT, base::Bind(&CefIOThreadState::RemoveHandler,
336                                       iothread_state_, render_process_id,
337                                       render_frame_id, frame_tree_node_id));
338   }
339 
340   if (is_main_frame) {
341     ClearPluginLoadDecision(render_process_id);
342   }
343 }
344 
GetHandler(int render_process_id,int render_frame_id,int frame_tree_node_id,bool require_frame_match) const345 CefRefPtr<CefRequestContextHandler> CefBrowserContext::GetHandler(
346     int render_process_id,
347     int render_frame_id,
348     int frame_tree_node_id,
349     bool require_frame_match) const {
350   CEF_REQUIRE_UIT();
351   return handler_map_.GetHandler(render_process_id, render_frame_id,
352                                  frame_tree_node_id, require_frame_match);
353 }
354 
IsAssociatedContext(int render_process_id,int render_frame_id,int frame_tree_node_id,bool require_frame_match) const355 bool CefBrowserContext::IsAssociatedContext(int render_process_id,
356                                             int render_frame_id,
357                                             int frame_tree_node_id,
358                                             bool require_frame_match) const {
359   CEF_REQUIRE_UIT();
360 
361   if (render_process_id >= 0 && render_frame_id >= 0) {
362     const auto it1 =
363         render_id_set_.find(std::make_pair(render_process_id, render_frame_id));
364     if (it1 != render_id_set_.end())
365       return true;
366   }
367 
368   if (frame_tree_node_id >= 0) {
369     const auto it2 = node_id_set_.find(frame_tree_node_id);
370     if (it2 != node_id_set_.end())
371       return true;
372   }
373 
374   if (render_process_id >= 0 && !require_frame_match) {
375     // Choose an arbitrary handler for the same process.
376     for (const auto& render_ids : render_id_set_) {
377       if (render_ids.first == render_process_id)
378         return true;
379     }
380   }
381 
382   return false;
383 }
384 
AddPluginLoadDecision(int render_process_id,const base::FilePath & plugin_path,bool is_main_frame,const url::Origin & main_frame_origin,chrome::mojom::PluginStatus status)385 void CefBrowserContext::AddPluginLoadDecision(
386     int render_process_id,
387     const base::FilePath& plugin_path,
388     bool is_main_frame,
389     const url::Origin& main_frame_origin,
390     chrome::mojom::PluginStatus status) {
391   CEF_REQUIRE_UIT();
392   DCHECK_GE(render_process_id, 0);
393   DCHECK(!plugin_path.empty());
394 
395   plugin_load_decision_map_.insert(std::make_pair(
396       std::make_pair(std::make_pair(render_process_id, plugin_path),
397                      std::make_pair(is_main_frame, main_frame_origin)),
398       status));
399 }
400 
HasPluginLoadDecision(int render_process_id,const base::FilePath & plugin_path,bool is_main_frame,const url::Origin & main_frame_origin,chrome::mojom::PluginStatus * status) const401 bool CefBrowserContext::HasPluginLoadDecision(
402     int render_process_id,
403     const base::FilePath& plugin_path,
404     bool is_main_frame,
405     const url::Origin& main_frame_origin,
406     chrome::mojom::PluginStatus* status) const {
407   CEF_REQUIRE_UIT();
408   DCHECK_GE(render_process_id, 0);
409   DCHECK(!plugin_path.empty());
410 
411   PluginLoadDecisionMap::const_iterator it = plugin_load_decision_map_.find(
412       std::make_pair(std::make_pair(render_process_id, plugin_path),
413                      std::make_pair(is_main_frame, main_frame_origin)));
414   if (it == plugin_load_decision_map_.end())
415     return false;
416 
417   *status = it->second;
418   return true;
419 }
420 
ClearPluginLoadDecision(int render_process_id)421 void CefBrowserContext::ClearPluginLoadDecision(int render_process_id) {
422   CEF_REQUIRE_UIT();
423 
424   if (render_process_id == -1) {
425     plugin_load_decision_map_.clear();
426   } else {
427     PluginLoadDecisionMap::iterator it = plugin_load_decision_map_.begin();
428     while (it != plugin_load_decision_map_.end()) {
429       if (it->first.first.first == render_process_id)
430         it = plugin_load_decision_map_.erase(it);
431       else
432         ++it;
433     }
434   }
435 }
436 
RegisterSchemeHandlerFactory(const CefString & scheme_name,const CefString & domain_name,CefRefPtr<CefSchemeHandlerFactory> factory)437 void CefBrowserContext::RegisterSchemeHandlerFactory(
438     const CefString& scheme_name,
439     const CefString& domain_name,
440     CefRefPtr<CefSchemeHandlerFactory> factory) {
441   CEF_POST_TASK(CEF_IOT,
442                 base::Bind(&CefIOThreadState::RegisterSchemeHandlerFactory,
443                            iothread_state_, scheme_name, domain_name, factory));
444 }
445 
ClearSchemeHandlerFactories()446 void CefBrowserContext::ClearSchemeHandlerFactories() {
447   CEF_POST_TASK(CEF_IOT,
448                 base::Bind(&CefIOThreadState::ClearSchemeHandlerFactories,
449                            iothread_state_));
450 }
451 
LoadExtension(const CefString & root_directory,CefRefPtr<CefDictionaryValue> manifest,CefRefPtr<CefExtensionHandler> handler,CefRefPtr<CefRequestContext> loader_context)452 void CefBrowserContext::LoadExtension(
453     const CefString& root_directory,
454     CefRefPtr<CefDictionaryValue> manifest,
455     CefRefPtr<CefExtensionHandler> handler,
456     CefRefPtr<CefRequestContext> loader_context) {
457   NOTIMPLEMENTED();
458   if (handler)
459     handler->OnExtensionLoadFailed(ERR_ABORTED);
460 }
461 
GetExtensions(std::vector<CefString> & extension_ids)462 bool CefBrowserContext::GetExtensions(std::vector<CefString>& extension_ids) {
463   NOTIMPLEMENTED();
464   return false;
465 }
466 
GetExtension(const CefString & extension_id)467 CefRefPtr<CefExtension> CefBrowserContext::GetExtension(
468     const CefString& extension_id) {
469   NOTIMPLEMENTED();
470   return nullptr;
471 }
472 
UnloadExtension(const CefString & extension_id)473 bool CefBrowserContext::UnloadExtension(const CefString& extension_id) {
474   NOTIMPLEMENTED();
475   return false;
476 }
477 
IsPrintPreviewSupported() const478 bool CefBrowserContext::IsPrintPreviewSupported() const {
479   return true;
480 }
481 
GetNetworkContext()482 network::mojom::NetworkContext* CefBrowserContext::GetNetworkContext() {
483   CEF_REQUIRE_UIT();
484   auto browser_context = AsBrowserContext();
485   return browser_context->GetDefaultStoragePartition(browser_context)
486       ->GetNetworkContext();
487 }
488 
GetMediaRouterManager()489 CefMediaRouterManager* CefBrowserContext::GetMediaRouterManager() {
490   CEF_REQUIRE_UIT();
491   if (!media_router_manager_) {
492     media_router_manager_.reset(new CefMediaRouterManager(AsBrowserContext()));
493   }
494   return media_router_manager_.get();
495 }
496 
GetCookieableSchemes() const497 CefBrowserContext::CookieableSchemes CefBrowserContext::GetCookieableSchemes()
498     const {
499   CEF_REQUIRE_UIT();
500   if (cookieable_schemes_)
501     return cookieable_schemes_;
502 
503   return GetGlobalCookieableSchemes();
504 }
505 
506 // static
507 CefBrowserContext::CookieableSchemes
GetGlobalCookieableSchemes()508 CefBrowserContext::GetGlobalCookieableSchemes() {
509   CEF_REQUIRE_UIT();
510 
511   static base::NoDestructor<CookieableSchemes> schemes(
512       []() -> CookieableSchemes {
513         const auto& settings = CefContext::Get()->settings();
514         if (settings.cookieable_schemes_list.length > 0 ||
515             settings.cookieable_schemes_exclude_defaults) {
516           return MakeSupportedSchemes(
517               CefString(&settings.cookieable_schemes_list),
518               !settings.cookieable_schemes_exclude_defaults);
519         }
520         return base::nullopt;
521       }());
522   return *schemes;
523 }
524