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