• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "libcef/browser/request_context_impl.h"
6 #include "libcef/browser/browser_context.h"
7 #include "libcef/browser/context.h"
8 #include "libcef/browser/thread_util.h"
9 #include "libcef/common/app_manager.h"
10 #include "libcef/common/task_runner_impl.h"
11 #include "libcef/common/values_impl.h"
12 
13 #include "base/atomic_sequence_num.h"
14 #include "base/logging.h"
15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "components/prefs/pref_service.h"
18 #include "content/public/browser/browser_task_traits.h"
19 #include "content/public/browser/plugin_service.h"
20 #include "content/public/browser/ssl_host_state_delegate.h"
21 #include "mojo/public/cpp/bindings/pending_receiver.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 #include "services/network/public/cpp/resolve_host_client_base.h"
24 #include "services/network/public/mojom/network_context.mojom.h"
25 
26 using content::BrowserThread;
27 
28 namespace {
29 
30 base::AtomicSequenceNumber g_next_id;
31 
GetTypeString(base::Value::Type type)32 const char* GetTypeString(base::Value::Type type) {
33   switch (type) {
34     case base::Value::Type::NONE:
35       return "NULL";
36     case base::Value::Type::BOOLEAN:
37       return "BOOLEAN";
38     case base::Value::Type::INTEGER:
39       return "INTEGER";
40     case base::Value::Type::DOUBLE:
41       return "DOUBLE";
42     case base::Value::Type::STRING:
43       return "STRING";
44     case base::Value::Type::BINARY:
45       return "BINARY";
46     case base::Value::Type::DICTIONARY:
47       return "DICTIONARY";
48     case base::Value::Type::LIST:
49       return "LIST";
50     case base::Value::Type::DEAD:
51       return "DEAD";
52   }
53 
54   NOTREACHED();
55   return "UNKNOWN";
56 }
57 
58 // Helper for HostResolver::Resolve.
59 struct ResolveHostHelperOld {
ResolveHostHelperOld__anon601216fd0111::ResolveHostHelperOld60   explicit ResolveHostHelperOld(CefRefPtr<CefResolveCallback> callback)
61       : callback_(callback) {}
62 
OnResolveCompleted__anon601216fd0111::ResolveHostHelperOld63   void OnResolveCompleted(int result) {
64     std::vector<CefString> resolved_ips;
65     base::Optional<net::AddressList> maybe_address_list =
66         request_->GetAddressResults();
67     if (maybe_address_list) {
68       net::AddressList::const_iterator iter = maybe_address_list->begin();
69       for (; iter != maybe_address_list->end(); ++iter)
70         resolved_ips.push_back(iter->ToStringWithoutPort());
71     }
72     CEF_POST_TASK(
73         CEF_UIT,
74         base::Bind(&CefResolveCallback::OnResolveCompleted, callback_,
75                    static_cast<cef_errorcode_t>(result), resolved_ips));
76 
77     delete this;
78   }
79 
80   CefRefPtr<CefResolveCallback> callback_;
81   std::unique_ptr<net::HostResolver::ResolveHostRequest> request_;
82 };
83 
84 class ResolveHostHelper : public network::ResolveHostClientBase {
85  public:
ResolveHostHelper(CefRefPtr<CefResolveCallback> callback)86   explicit ResolveHostHelper(CefRefPtr<CefResolveCallback> callback)
87       : callback_(callback), receiver_(this) {}
88 
Start(CefBrowserContext * browser_context,const CefString & origin)89   void Start(CefBrowserContext* browser_context, const CefString& origin) {
90     CEF_REQUIRE_UIT();
91 
92     browser_context->GetNetworkContext()->CreateHostResolver(
93         base::nullopt, host_resolver_.BindNewPipeAndPassReceiver());
94 
95     host_resolver_.set_disconnect_handler(base::BindOnce(
96         &ResolveHostHelper::OnComplete, base::Unretained(this), net::ERR_FAILED,
97         net::ResolveErrorInfo(net::ERR_FAILED), base::nullopt));
98 
99     host_resolver_->ResolveHost(
100         net::HostPortPair::FromURL(GURL(origin.ToString())),
101         net::NetworkIsolationKey::CreateTransient(), nullptr,
102         receiver_.BindNewPipeAndPassRemote());
103   }
104 
105  private:
OnComplete(int32_t result,const::net::ResolveErrorInfo & resolve_error_info,const base::Optional<net::AddressList> & resolved_addresses)106   void OnComplete(
107       int32_t result,
108       const ::net::ResolveErrorInfo& resolve_error_info,
109       const base::Optional<net::AddressList>& resolved_addresses) override {
110     CEF_REQUIRE_UIT();
111 
112     host_resolver_.reset();
113     receiver_.reset();
114 
115     std::vector<CefString> resolved_ips;
116 
117     if (result == net::OK) {
118       DCHECK(resolved_addresses && !resolved_addresses->empty());
119       for (const auto& value : resolved_addresses.value()) {
120         resolved_ips.push_back(value.ToStringWithoutPort());
121       }
122     }
123 
124     callback_->OnResolveCompleted(static_cast<cef_errorcode_t>(result),
125                                   resolved_ips);
126     delete this;
127   }
128 
129   CefRefPtr<CefResolveCallback> callback_;
130 
131   mojo::Remote<network::mojom::HostResolver> host_resolver_;
132   mojo::Receiver<network::mojom::ResolveHostClient> receiver_;
133 
134   DISALLOW_COPY_AND_ASSIGN(ResolveHostHelper);
135 };
136 
137 }  // namespace
138 
139 // CefBrowserContext
140 
141 // static
GetGlobalContext()142 CefRefPtr<CefRequestContext> CefRequestContext::GetGlobalContext() {
143   // Verify that the context is in a valid state.
144   if (!CONTEXT_STATE_VALID()) {
145     NOTREACHED() << "context not valid";
146     return nullptr;
147   }
148 
149   CefRequestContextImpl::Config config;
150   config.is_global = true;
151   return CefRequestContextImpl::GetOrCreateRequestContext(config);
152 }
153 
154 // static
CreateContext(const CefRequestContextSettings & settings,CefRefPtr<CefRequestContextHandler> handler)155 CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
156     const CefRequestContextSettings& settings,
157     CefRefPtr<CefRequestContextHandler> handler) {
158   // Verify that the context is in a valid state.
159   if (!CONTEXT_STATE_VALID()) {
160     NOTREACHED() << "context not valid";
161     return nullptr;
162   }
163 
164   CefRequestContextImpl::Config config;
165   config.settings = settings;
166   config.handler = handler;
167   config.unique_id = g_next_id.GetNext();
168   return CefRequestContextImpl::GetOrCreateRequestContext(config);
169 }
170 
171 // static
CreateContext(CefRefPtr<CefRequestContext> other,CefRefPtr<CefRequestContextHandler> handler)172 CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
173     CefRefPtr<CefRequestContext> other,
174     CefRefPtr<CefRequestContextHandler> handler) {
175   // Verify that the context is in a valid state.
176   if (!CONTEXT_STATE_VALID()) {
177     NOTREACHED() << "context not valid";
178     return nullptr;
179   }
180 
181   if (!other.get())
182     return nullptr;
183 
184   CefRequestContextImpl::Config config;
185   config.other = static_cast<CefRequestContextImpl*>(other.get());
186   config.handler = handler;
187   config.unique_id = g_next_id.GetNext();
188   return CefRequestContextImpl::GetOrCreateRequestContext(config);
189 }
190 
191 // CefRequestContextImpl
192 
~CefRequestContextImpl()193 CefRequestContextImpl::~CefRequestContextImpl() {
194   CEF_REQUIRE_UIT();
195 
196   if (browser_context_) {
197     // May result in |browser_context_| being deleted if no other
198     // CefRequestContextImpl are referencing it.
199     browser_context_->RemoveCefRequestContext(this);
200   }
201 }
202 
203 // static
204 CefRefPtr<CefRequestContextImpl>
CreateGlobalRequestContext(const CefRequestContextSettings & settings)205 CefRequestContextImpl::CreateGlobalRequestContext(
206     const CefRequestContextSettings& settings) {
207   // Create and initialize the global context immediately.
208   Config config;
209   config.is_global = true;
210   config.settings = settings;
211   CefRefPtr<CefRequestContextImpl> impl = new CefRequestContextImpl(config);
212   impl->Initialize();
213   return impl;
214 }
215 
216 // static
217 CefRefPtr<CefRequestContextImpl>
GetOrCreateForRequestContext(CefRefPtr<CefRequestContext> request_context)218 CefRequestContextImpl::GetOrCreateForRequestContext(
219     CefRefPtr<CefRequestContext> request_context) {
220   if (request_context.get()) {
221     // Use the context from the provided CefRequestContext.
222     return static_cast<CefRequestContextImpl*>(request_context.get());
223   }
224 
225   // Use the global context.
226   Config config;
227   config.is_global = true;
228   return CefRequestContextImpl::GetOrCreateRequestContext(config);
229 }
230 
VerifyBrowserContext() const231 bool CefRequestContextImpl::VerifyBrowserContext() const {
232   if (!CEF_CURRENTLY_ON_UIT()) {
233     NOTREACHED() << "called on invalid thread";
234     return false;
235   }
236 
237   if (!browser_context() || !browser_context()->IsInitialized()) {
238     NOTREACHED() << "Uninitialized context";
239     return false;
240   }
241 
242   return true;
243 }
244 
GetBrowserContext()245 CefBrowserContext* CefRequestContextImpl::GetBrowserContext() {
246   CHECK(VerifyBrowserContext());
247   return browser_context();
248 }
249 
ExecuteWhenBrowserContextInitialized(base::OnceClosure callback)250 void CefRequestContextImpl::ExecuteWhenBrowserContextInitialized(
251     base::OnceClosure callback) {
252   if (!CEF_CURRENTLY_ON_UIT()) {
253     CEF_POST_TASK(
254         CEF_UIT,
255         base::BindOnce(
256             &CefRequestContextImpl::ExecuteWhenBrowserContextInitialized, this,
257             std::move(callback)));
258     return;
259   }
260 
261   EnsureBrowserContext();
262   browser_context()->StoreOrTriggerInitCallback(std::move(callback));
263 }
264 
GetBrowserContext(scoped_refptr<base::SingleThreadTaskRunner> task_runner,BrowserContextCallback callback)265 void CefRequestContextImpl::GetBrowserContext(
266     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
267     BrowserContextCallback callback) {
268   if (!task_runner.get())
269     task_runner = CefTaskRunnerImpl::GetCurrentTaskRunner();
270 
271   ExecuteWhenBrowserContextInitialized(base::BindOnce(
272       [](CefRefPtr<CefRequestContextImpl> context,
273          scoped_refptr<base::SingleThreadTaskRunner> task_runner,
274          BrowserContextCallback callback) {
275         CEF_REQUIRE_UIT();
276 
277         auto browser_context = context->browser_context();
278         DCHECK(browser_context->IsInitialized());
279 
280         if (task_runner->BelongsToCurrentThread()) {
281           // Execute the callback immediately.
282           std::move(callback).Run(browser_context->getter());
283         } else {
284           // Execute the callback on the target thread.
285           task_runner->PostTask(
286               FROM_HERE,
287               base::BindOnce(std::move(callback), browser_context->getter()));
288         }
289       },
290       CefRefPtr<CefRequestContextImpl>(this), task_runner,
291       std::move(callback)));
292 }
293 
IsSame(CefRefPtr<CefRequestContext> other)294 bool CefRequestContextImpl::IsSame(CefRefPtr<CefRequestContext> other) {
295   CefRequestContextImpl* other_impl =
296       static_cast<CefRequestContextImpl*>(other.get());
297   if (!other_impl)
298     return false;
299 
300   // Compare whether both are the global context.
301   if (config_.is_global && other_impl->config_.is_global)
302     return true;
303 
304   // Compare CefBrowserContext pointers if one has been associated.
305   if (browser_context() && other_impl->browser_context()) {
306     return (browser_context() == other_impl->browser_context());
307   } else if (browser_context() || other_impl->browser_context()) {
308     return false;
309   }
310 
311   // Otherwise compare unique IDs.
312   return (config_.unique_id == other_impl->config_.unique_id);
313 }
314 
IsSharingWith(CefRefPtr<CefRequestContext> other)315 bool CefRequestContextImpl::IsSharingWith(CefRefPtr<CefRequestContext> other) {
316   CefRequestContextImpl* other_impl =
317       static_cast<CefRequestContextImpl*>(other.get());
318   if (!other_impl)
319     return false;
320 
321   if (IsSame(other))
322     return true;
323 
324   CefRefPtr<CefRequestContext> pending_other = config_.other;
325   if (pending_other.get()) {
326     // This object is not initialized but we know what context this object will
327     // share with. Compare to that other context instead.
328     return pending_other->IsSharingWith(other);
329   }
330 
331   pending_other = other_impl->config_.other;
332   if (pending_other.get()) {
333     // The other object is not initialized but we know what context that object
334     // will share with. Compare to that other context instead.
335     return pending_other->IsSharingWith(this);
336   }
337 
338   // This or the other object is not initialized. Compare the cache path values.
339   // If both are non-empty and the same then they'll share the same storage.
340   if (config_.settings.cache_path.length > 0 &&
341       other_impl->config_.settings.cache_path.length > 0) {
342     return (
343         base::FilePath(CefString(&config_.settings.cache_path)) ==
344         base::FilePath(CefString(&other_impl->config_.settings.cache_path)));
345   }
346 
347   return false;
348 }
349 
IsGlobal()350 bool CefRequestContextImpl::IsGlobal() {
351   return config_.is_global;
352 }
353 
GetHandler()354 CefRefPtr<CefRequestContextHandler> CefRequestContextImpl::GetHandler() {
355   return config_.handler;
356 }
357 
GetCachePath()358 CefString CefRequestContextImpl::GetCachePath() {
359   return CefString(&config_.settings.cache_path);
360 }
361 
GetCookieManager(CefRefPtr<CefCompletionCallback> callback)362 CefRefPtr<CefCookieManager> CefRequestContextImpl::GetCookieManager(
363     CefRefPtr<CefCompletionCallback> callback) {
364   CefRefPtr<CefCookieManagerImpl> cookie_manager = new CefCookieManagerImpl();
365   InitializeCookieManagerInternal(cookie_manager, callback);
366   return cookie_manager.get();
367 }
368 
RegisterSchemeHandlerFactory(const CefString & scheme_name,const CefString & domain_name,CefRefPtr<CefSchemeHandlerFactory> factory)369 bool CefRequestContextImpl::RegisterSchemeHandlerFactory(
370     const CefString& scheme_name,
371     const CefString& domain_name,
372     CefRefPtr<CefSchemeHandlerFactory> factory) {
373   GetBrowserContext(
374       content::GetUIThreadTaskRunner({}),
375       base::BindOnce(
376           [](const CefString& scheme_name, const CefString& domain_name,
377              CefRefPtr<CefSchemeHandlerFactory> factory,
378              CefBrowserContext::Getter browser_context_getter) {
379             auto browser_context = browser_context_getter.Run();
380             if (browser_context) {
381               browser_context->RegisterSchemeHandlerFactory(
382                   scheme_name, domain_name, factory);
383             }
384           },
385           scheme_name, domain_name, factory));
386 
387   return true;
388 }
389 
ClearSchemeHandlerFactories()390 bool CefRequestContextImpl::ClearSchemeHandlerFactories() {
391   GetBrowserContext(
392       content::GetUIThreadTaskRunner({}),
393       base::BindOnce([](CefBrowserContext::Getter browser_context_getter) {
394         auto browser_context = browser_context_getter.Run();
395         if (browser_context)
396           browser_context->ClearSchemeHandlerFactories();
397       }));
398 
399   return true;
400 }
401 
PurgePluginListCache(bool reload_pages)402 void CefRequestContextImpl::PurgePluginListCache(bool reload_pages) {
403   GetBrowserContext(
404       content::GetUIThreadTaskRunner({}),
405       base::BindOnce(&CefRequestContextImpl::PurgePluginListCacheInternal, this,
406                      reload_pages));
407 }
408 
HasPreference(const CefString & name)409 bool CefRequestContextImpl::HasPreference(const CefString& name) {
410   if (!VerifyBrowserContext())
411     return false;
412 
413   PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
414   return (pref_service->FindPreference(name) != nullptr);
415 }
416 
GetPreference(const CefString & name)417 CefRefPtr<CefValue> CefRequestContextImpl::GetPreference(
418     const CefString& name) {
419   if (!VerifyBrowserContext())
420     return nullptr;
421 
422   PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
423   const PrefService::Preference* pref = pref_service->FindPreference(name);
424   if (!pref)
425     return nullptr;
426   return new CefValueImpl(pref->GetValue()->DeepCopy());
427 }
428 
GetAllPreferences(bool include_defaults)429 CefRefPtr<CefDictionaryValue> CefRequestContextImpl::GetAllPreferences(
430     bool include_defaults) {
431   if (!VerifyBrowserContext())
432     return nullptr;
433 
434   PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
435 
436   base::Value values = pref_service->GetPreferenceValues(
437       include_defaults ? PrefService::INCLUDE_DEFAULTS
438                        : PrefService::EXCLUDE_DEFAULTS);
439 
440   // CefDictionaryValueImpl takes ownership of |values|.
441   return new CefDictionaryValueImpl(
442       base::DictionaryValue::From(
443           base::Value::ToUniquePtrValue(std::move(values)))
444           .release(),
445       true, false);
446 }
447 
CanSetPreference(const CefString & name)448 bool CefRequestContextImpl::CanSetPreference(const CefString& name) {
449   if (!VerifyBrowserContext())
450     return false;
451 
452   PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
453   const PrefService::Preference* pref = pref_service->FindPreference(name);
454   return (pref && pref->IsUserModifiable());
455 }
456 
SetPreference(const CefString & name,CefRefPtr<CefValue> value,CefString & error)457 bool CefRequestContextImpl::SetPreference(const CefString& name,
458                                           CefRefPtr<CefValue> value,
459                                           CefString& error) {
460   if (!VerifyBrowserContext())
461     return false;
462 
463   PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
464 
465   // The below validation logic should match PrefService::SetUserPrefValue.
466 
467   const PrefService::Preference* pref = pref_service->FindPreference(name);
468   if (!pref) {
469     error = "Trying to modify an unregistered preference";
470     return false;
471   }
472 
473   if (!pref->IsUserModifiable()) {
474     error = "Trying to modify a preference that is not user modifiable";
475     return false;
476   }
477 
478   if (!value.get()) {
479     // Reset the preference to its default value.
480     pref_service->ClearPref(name);
481     return true;
482   }
483 
484   if (!value->IsValid()) {
485     error = "A valid value is required";
486     return false;
487   }
488 
489   CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
490 
491   CefValueImpl::ScopedLockedValue scoped_locked_value(impl);
492   base::Value* impl_value = impl->GetValueUnsafe();
493 
494   if (pref->GetType() != impl_value->type()) {
495     error = base::StringPrintf(
496         "Trying to set a preference of type %s to value of type %s",
497         GetTypeString(pref->GetType()), GetTypeString(impl_value->type()));
498     return false;
499   }
500 
501   // PrefService will make a DeepCopy of |impl_value|.
502   pref_service->Set(name, *impl_value);
503   return true;
504 }
505 
ClearCertificateExceptions(CefRefPtr<CefCompletionCallback> callback)506 void CefRequestContextImpl::ClearCertificateExceptions(
507     CefRefPtr<CefCompletionCallback> callback) {
508   GetBrowserContext(
509       content::GetUIThreadTaskRunner({}),
510       base::BindOnce(&CefRequestContextImpl::ClearCertificateExceptionsInternal,
511                      this, callback));
512 }
513 
ClearHttpAuthCredentials(CefRefPtr<CefCompletionCallback> callback)514 void CefRequestContextImpl::ClearHttpAuthCredentials(
515     CefRefPtr<CefCompletionCallback> callback) {
516   GetBrowserContext(
517       content::GetUIThreadTaskRunner({}),
518       base::BindOnce(&CefRequestContextImpl::ClearHttpAuthCredentialsInternal,
519                      this, callback));
520 }
521 
CloseAllConnections(CefRefPtr<CefCompletionCallback> callback)522 void CefRequestContextImpl::CloseAllConnections(
523     CefRefPtr<CefCompletionCallback> callback) {
524   GetBrowserContext(
525       content::GetUIThreadTaskRunner({}),
526       base::BindOnce(&CefRequestContextImpl::CloseAllConnectionsInternal, this,
527                      callback));
528 }
529 
ResolveHost(const CefString & origin,CefRefPtr<CefResolveCallback> callback)530 void CefRequestContextImpl::ResolveHost(
531     const CefString& origin,
532     CefRefPtr<CefResolveCallback> callback) {
533   GetBrowserContext(content::GetUIThreadTaskRunner({}),
534                     base::BindOnce(&CefRequestContextImpl::ResolveHostInternal,
535                                    this, origin, callback));
536 }
537 
LoadExtension(const CefString & root_directory,CefRefPtr<CefDictionaryValue> manifest,CefRefPtr<CefExtensionHandler> handler)538 void CefRequestContextImpl::LoadExtension(
539     const CefString& root_directory,
540     CefRefPtr<CefDictionaryValue> manifest,
541     CefRefPtr<CefExtensionHandler> handler) {
542   GetBrowserContext(content::GetUIThreadTaskRunner({}),
543                     base::BindOnce(
544                         [](const CefString& root_directory,
545                            CefRefPtr<CefDictionaryValue> manifest,
546                            CefRefPtr<CefExtensionHandler> handler,
547                            CefRefPtr<CefRequestContextImpl> self,
548                            CefBrowserContext::Getter browser_context_getter) {
549                           auto browser_context = browser_context_getter.Run();
550                           if (browser_context) {
551                             browser_context->LoadExtension(
552                                 root_directory, manifest, handler, self);
553                           }
554                         },
555                         root_directory, manifest, handler,
556                         CefRefPtr<CefRequestContextImpl>(this)));
557 }
558 
DidLoadExtension(const CefString & extension_id)559 bool CefRequestContextImpl::DidLoadExtension(const CefString& extension_id) {
560   CefRefPtr<CefExtension> extension = GetExtension(extension_id);
561   // GetLoaderContext() will return NULL for internal extensions.
562   return extension && IsSame(extension->GetLoaderContext());
563 }
564 
HasExtension(const CefString & extension_id)565 bool CefRequestContextImpl::HasExtension(const CefString& extension_id) {
566   return !!GetExtension(extension_id);
567 }
568 
GetExtensions(std::vector<CefString> & extension_ids)569 bool CefRequestContextImpl::GetExtensions(
570     std::vector<CefString>& extension_ids) {
571   extension_ids.clear();
572 
573   if (!VerifyBrowserContext())
574     return false;
575 
576   return browser_context()->GetExtensions(extension_ids);
577 }
578 
GetExtension(const CefString & extension_id)579 CefRefPtr<CefExtension> CefRequestContextImpl::GetExtension(
580     const CefString& extension_id) {
581   if (!VerifyBrowserContext())
582     return nullptr;
583 
584   return browser_context()->GetExtension(extension_id);
585 }
586 
GetMediaRouter(CefRefPtr<CefCompletionCallback> callback)587 CefRefPtr<CefMediaRouter> CefRequestContextImpl::GetMediaRouter(
588     CefRefPtr<CefCompletionCallback> callback) {
589   CefRefPtr<CefMediaRouterImpl> media_router = new CefMediaRouterImpl();
590   InitializeMediaRouterInternal(media_router, callback);
591   return media_router.get();
592 }
593 
OnRenderFrameCreated(int render_process_id,int render_frame_id,int frame_tree_node_id,bool is_main_frame,bool is_guest_view)594 void CefRequestContextImpl::OnRenderFrameCreated(int render_process_id,
595                                                  int render_frame_id,
596                                                  int frame_tree_node_id,
597                                                  bool is_main_frame,
598                                                  bool is_guest_view) {
599   browser_context_->OnRenderFrameCreated(this, render_process_id,
600                                          render_frame_id, frame_tree_node_id,
601                                          is_main_frame, is_guest_view);
602 }
603 
OnRenderFrameDeleted(int render_process_id,int render_frame_id,int frame_tree_node_id,bool is_main_frame,bool is_guest_view)604 void CefRequestContextImpl::OnRenderFrameDeleted(int render_process_id,
605                                                  int render_frame_id,
606                                                  int frame_tree_node_id,
607                                                  bool is_main_frame,
608                                                  bool is_guest_view) {
609   browser_context_->OnRenderFrameDeleted(this, render_process_id,
610                                          render_frame_id, frame_tree_node_id,
611                                          is_main_frame, is_guest_view);
612 }
613 
614 // static
615 CefRefPtr<CefRequestContextImpl>
GetOrCreateRequestContext(const Config & config)616 CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) {
617   if (config.is_global ||
618       (config.other && config.other->IsGlobal() && !config.handler)) {
619     // Return the singleton global context.
620     return static_cast<CefRequestContextImpl*>(
621         CefAppManager::Get()->GetGlobalRequestContext().get());
622   }
623 
624   // The new context will be initialized later by EnsureBrowserContext().
625   CefRefPtr<CefRequestContextImpl> context = new CefRequestContextImpl(config);
626 
627   // Initialize ASAP so that any tasks blocked on initialization will execute.
628   if (CEF_CURRENTLY_ON_UIT()) {
629     context->Initialize();
630   } else {
631     CEF_POST_TASK(CEF_UIT,
632                   base::BindOnce(&CefRequestContextImpl::Initialize, context));
633   }
634 
635   return context;
636 }
637 
CefRequestContextImpl(const CefRequestContextImpl::Config & config)638 CefRequestContextImpl::CefRequestContextImpl(
639     const CefRequestContextImpl::Config& config)
640     : config_(config) {}
641 
Initialize()642 void CefRequestContextImpl::Initialize() {
643   CEF_REQUIRE_UIT();
644 
645   DCHECK(!browser_context_);
646 
647   if (config_.other) {
648     // Share storage with |config_.other|.
649     browser_context_ = config_.other->browser_context();
650     CHECK(browser_context_);
651   }
652 
653   if (!browser_context_) {
654     if (!config_.is_global) {
655       // User-specified settings need to be normalized.
656       CefContext::Get()->NormalizeRequestContextSettings(&config_.settings);
657     }
658 
659     const base::FilePath& cache_path =
660         base::FilePath(CefString(&config_.settings.cache_path));
661     if (!cache_path.empty()) {
662       // Check if a CefBrowserContext is already globally registered for
663       // the specified cache path. If so then use it.
664       browser_context_ = CefBrowserContext::FromCachePath(cache_path);
665     }
666   }
667 
668   auto initialized_cb =
669       base::BindOnce(&CefRequestContextImpl::BrowserContextInitialized, this);
670 
671   if (!browser_context_) {
672     // Create a new CefBrowserContext instance. If the cache path is non-
673     // empty then this new instance will become the globally registered
674     // CefBrowserContext for that path. Otherwise, this new instance will
675     // be a completely isolated "incognito mode" context.
676     browser_context_ = CefAppManager::Get()->CreateNewBrowserContext(
677         config_.settings, std::move(initialized_cb));
678   } else {
679     // Share the same settings as the existing context.
680     config_.settings = browser_context_->settings();
681     browser_context_->StoreOrTriggerInitCallback(std::move(initialized_cb));
682   }
683 
684   // We'll disassociate from |browser_context_| on destruction.
685   browser_context_->AddCefRequestContext(this);
686 
687   if (config_.other) {
688     // Clear the reference to |config_.other| after setting
689     // |request_context_getter_|. This is the reverse order of checks in
690     // IsSharedWith().
691     config_.other = nullptr;
692   }
693 }
694 
BrowserContextInitialized()695 void CefRequestContextImpl::BrowserContextInitialized() {
696   if (config_.handler) {
697     // Always execute asynchronously so the current call stack can unwind.
698     CEF_POST_TASK(
699         CEF_UIT,
700         base::BindOnce(&CefRequestContextHandler::OnRequestContextInitialized,
701                        config_.handler, CefRefPtr<CefRequestContext>(this)));
702   }
703 }
704 
EnsureBrowserContext()705 void CefRequestContextImpl::EnsureBrowserContext() {
706   CEF_REQUIRE_UIT();
707   if (!browser_context())
708     Initialize();
709   DCHECK(browser_context());
710 }
711 
PurgePluginListCacheInternal(bool reload_pages,CefBrowserContext::Getter browser_context_getter)712 void CefRequestContextImpl::PurgePluginListCacheInternal(
713     bool reload_pages,
714     CefBrowserContext::Getter browser_context_getter) {
715   auto browser_context = browser_context_getter.Run();
716   if (!browser_context)
717     return;
718 
719   browser_context->ClearPluginLoadDecision(-1);
720   content::PluginService::GetInstance()->PurgePluginListCache(
721       browser_context->AsBrowserContext(), false);
722 }
723 
ClearCertificateExceptionsInternal(CefRefPtr<CefCompletionCallback> callback,CefBrowserContext::Getter browser_context_getter)724 void CefRequestContextImpl::ClearCertificateExceptionsInternal(
725     CefRefPtr<CefCompletionCallback> callback,
726     CefBrowserContext::Getter browser_context_getter) {
727   auto browser_context = browser_context_getter.Run();
728   if (!browser_context)
729     return;
730 
731   content::SSLHostStateDelegate* ssl_delegate =
732       browser_context->AsBrowserContext()->GetSSLHostStateDelegate();
733   if (ssl_delegate)
734     ssl_delegate->Clear(base::Callback<bool(const std::string&)>());
735 
736   if (callback) {
737     CEF_POST_TASK(CEF_UIT,
738                   base::Bind(&CefCompletionCallback::OnComplete, callback));
739   }
740 }
741 
ClearHttpAuthCredentialsInternal(CefRefPtr<CefCompletionCallback> callback,CefBrowserContext::Getter browser_context_getter)742 void CefRequestContextImpl::ClearHttpAuthCredentialsInternal(
743     CefRefPtr<CefCompletionCallback> callback,
744     CefBrowserContext::Getter browser_context_getter) {
745   auto browser_context = browser_context_getter.Run();
746   if (!browser_context)
747     return;
748 
749   browser_context->GetNetworkContext()->ClearHttpAuthCache(
750       /*start_time=*/base::Time(), /*end_time=*/base::Time::Max(),
751       base::Bind(&CefCompletionCallback::OnComplete, callback));
752 }
753 
CloseAllConnectionsInternal(CefRefPtr<CefCompletionCallback> callback,CefBrowserContext::Getter browser_context_getter)754 void CefRequestContextImpl::CloseAllConnectionsInternal(
755     CefRefPtr<CefCompletionCallback> callback,
756     CefBrowserContext::Getter browser_context_getter) {
757   auto browser_context = browser_context_getter.Run();
758   if (!browser_context)
759     return;
760 
761   browser_context->GetNetworkContext()->CloseAllConnections(
762       base::Bind(&CefCompletionCallback::OnComplete, callback));
763 }
764 
ResolveHostInternal(const CefString & origin,CefRefPtr<CefResolveCallback> callback,CefBrowserContext::Getter browser_context_getter)765 void CefRequestContextImpl::ResolveHostInternal(
766     const CefString& origin,
767     CefRefPtr<CefResolveCallback> callback,
768     CefBrowserContext::Getter browser_context_getter) {
769   auto browser_context = browser_context_getter.Run();
770   if (!browser_context)
771     return;
772 
773   // |helper| will be deleted in ResolveHostHelper::OnComplete().
774   ResolveHostHelper* helper = new ResolveHostHelper(callback);
775   helper->Start(browser_context, origin);
776 }
777 
InitializeCookieManagerInternal(CefRefPtr<CefCookieManagerImpl> cookie_manager,CefRefPtr<CefCompletionCallback> callback)778 void CefRequestContextImpl::InitializeCookieManagerInternal(
779     CefRefPtr<CefCookieManagerImpl> cookie_manager,
780     CefRefPtr<CefCompletionCallback> callback) {
781   GetBrowserContext(content::GetUIThreadTaskRunner({}),
782                     base::BindOnce(
783                         [](CefRefPtr<CefCookieManagerImpl> cookie_manager,
784                            CefRefPtr<CefCompletionCallback> callback,
785                            CefBrowserContext::Getter browser_context_getter) {
786                           cookie_manager->Initialize(browser_context_getter,
787                                                      callback);
788                         },
789                         cookie_manager, callback));
790 }
791 
InitializeMediaRouterInternal(CefRefPtr<CefMediaRouterImpl> media_router,CefRefPtr<CefCompletionCallback> callback)792 void CefRequestContextImpl::InitializeMediaRouterInternal(
793     CefRefPtr<CefMediaRouterImpl> media_router,
794     CefRefPtr<CefCompletionCallback> callback) {
795   GetBrowserContext(content::GetUIThreadTaskRunner({}),
796                     base::BindOnce(
797                         [](CefRefPtr<CefMediaRouterImpl> media_router,
798                            CefRefPtr<CefCompletionCallback> callback,
799                            CefBrowserContext::Getter browser_context_getter) {
800                           media_router->Initialize(browser_context_getter,
801                                                    callback);
802                         },
803                         media_router, callback));
804 }
805 
browser_context() const806 CefBrowserContext* CefRequestContextImpl::browser_context() const {
807   return browser_context_;
808 }
809