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