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