| // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that |
| // can be found in the LICENSE file. |
| |
| #include "libcef/browser/request_context_impl.h" |
| #include "libcef/browser/browser_context.h" |
| #include "libcef/browser/content_browser_client.h" |
| #include "libcef/browser/context.h" |
| #include "libcef/browser/extensions/extension_system.h" |
| #include "libcef/browser/thread_util.h" |
| #include "libcef/common/extensions/extensions_util.h" |
| #include "libcef/common/task_runner_impl.h" |
| #include "libcef/common/values_impl.h" |
| |
| #include "base/atomic_sequence_num.h" |
| #include "base/logging.h" |
| #include "base/strings/stringprintf.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/plugin_service.h" |
| #include "content/public/browser/ssl_host_state_delegate.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "services/network/public/cpp/resolve_host_client_base.h" |
| #include "services/network/public/mojom/network_context.mojom.h" |
| |
| using content::BrowserThread; |
| |
| namespace { |
| |
| base::AtomicSequenceNumber g_next_id; |
| |
| const char* GetTypeString(base::Value::Type type) { |
| switch (type) { |
| case base::Value::Type::NONE: |
| return "NULL"; |
| case base::Value::Type::BOOLEAN: |
| return "BOOLEAN"; |
| case base::Value::Type::INTEGER: |
| return "INTEGER"; |
| case base::Value::Type::DOUBLE: |
| return "DOUBLE"; |
| case base::Value::Type::STRING: |
| return "STRING"; |
| case base::Value::Type::BINARY: |
| return "BINARY"; |
| case base::Value::Type::DICTIONARY: |
| return "DICTIONARY"; |
| case base::Value::Type::LIST: |
| return "LIST"; |
| case base::Value::Type::DEAD: |
| return "DEAD"; |
| } |
| |
| NOTREACHED(); |
| return "UNKNOWN"; |
| } |
| |
| // Helper for HostResolver::Resolve. |
| struct ResolveHostHelperOld { |
| explicit ResolveHostHelperOld(CefRefPtr<CefResolveCallback> callback) |
| : callback_(callback) {} |
| |
| void OnResolveCompleted(int result) { |
| std::vector<CefString> resolved_ips; |
| base::Optional<net::AddressList> maybe_address_list = |
| request_->GetAddressResults(); |
| if (maybe_address_list) { |
| net::AddressList::const_iterator iter = maybe_address_list->begin(); |
| for (; iter != maybe_address_list->end(); ++iter) |
| resolved_ips.push_back(iter->ToStringWithoutPort()); |
| } |
| CEF_POST_TASK( |
| CEF_UIT, |
| base::Bind(&CefResolveCallback::OnResolveCompleted, callback_, |
| static_cast<cef_errorcode_t>(result), resolved_ips)); |
| |
| delete this; |
| } |
| |
| CefRefPtr<CefResolveCallback> callback_; |
| std::unique_ptr<net::HostResolver::ResolveHostRequest> request_; |
| }; |
| |
| class ResolveHostHelper : public network::ResolveHostClientBase { |
| public: |
| explicit ResolveHostHelper(CefRefPtr<CefResolveCallback> callback) |
| : callback_(callback), receiver_(this) {} |
| |
| void Start(CefBrowserContext* browser_context, const CefString& origin) { |
| CEF_REQUIRE_UIT(); |
| |
| browser_context->GetNetworkContext()->CreateHostResolver( |
| base::nullopt, host_resolver_.BindNewPipeAndPassReceiver()); |
| |
| host_resolver_.set_disconnect_handler(base::BindOnce( |
| &ResolveHostHelper::OnComplete, base::Unretained(this), net::ERR_FAILED, |
| net::ResolveErrorInfo(net::ERR_FAILED), base::nullopt)); |
| |
| host_resolver_->ResolveHost( |
| net::HostPortPair::FromURL(GURL(origin.ToString())), |
| net::NetworkIsolationKey::Todo(), nullptr, |
| receiver_.BindNewPipeAndPassRemote()); |
| } |
| |
| private: |
| void OnComplete( |
| int32_t result, |
| const ::net::ResolveErrorInfo& resolve_error_info, |
| const base::Optional<net::AddressList>& resolved_addresses) override { |
| CEF_REQUIRE_UIT(); |
| |
| host_resolver_.reset(); |
| receiver_.reset(); |
| |
| std::vector<CefString> resolved_ips; |
| |
| if (result == net::OK) { |
| DCHECK(resolved_addresses && !resolved_addresses->empty()); |
| for (const auto& value : resolved_addresses.value()) { |
| resolved_ips.push_back(value.ToStringWithoutPort()); |
| } |
| } |
| |
| callback_->OnResolveCompleted(static_cast<cef_errorcode_t>(result), |
| resolved_ips); |
| delete this; |
| } |
| |
| CefRefPtr<CefResolveCallback> callback_; |
| |
| mojo::Remote<network::mojom::HostResolver> host_resolver_; |
| mojo::Receiver<network::mojom::ResolveHostClient> receiver_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ResolveHostHelper); |
| }; |
| |
| } // namespace |
| |
| // CefBrowserContext |
| |
| // static |
| CefRefPtr<CefRequestContext> CefRequestContext::GetGlobalContext() { |
| // Verify that the context is in a valid state. |
| if (!CONTEXT_STATE_VALID()) { |
| NOTREACHED() << "context not valid"; |
| return nullptr; |
| } |
| |
| CefRequestContextImpl::Config config; |
| config.is_global = true; |
| return CefRequestContextImpl::GetOrCreateRequestContext(config); |
| } |
| |
| // static |
| CefRefPtr<CefRequestContext> CefRequestContext::CreateContext( |
| const CefRequestContextSettings& settings, |
| CefRefPtr<CefRequestContextHandler> handler) { |
| // Verify that the context is in a valid state. |
| if (!CONTEXT_STATE_VALID()) { |
| NOTREACHED() << "context not valid"; |
| return nullptr; |
| } |
| |
| CefRequestContextImpl::Config config; |
| config.settings = settings; |
| config.handler = handler; |
| config.unique_id = g_next_id.GetNext(); |
| return CefRequestContextImpl::GetOrCreateRequestContext(config); |
| } |
| |
| // static |
| CefRefPtr<CefRequestContext> CefRequestContext::CreateContext( |
| CefRefPtr<CefRequestContext> other, |
| CefRefPtr<CefRequestContextHandler> handler) { |
| // Verify that the context is in a valid state. |
| if (!CONTEXT_STATE_VALID()) { |
| NOTREACHED() << "context not valid"; |
| return nullptr; |
| } |
| |
| if (!other.get()) |
| return nullptr; |
| |
| CefRequestContextImpl::Config config; |
| config.other = static_cast<CefRequestContextImpl*>(other.get()); |
| config.handler = handler; |
| config.unique_id = g_next_id.GetNext(); |
| return CefRequestContextImpl::GetOrCreateRequestContext(config); |
| } |
| |
| // CefRequestContextImpl |
| |
| CefRequestContextImpl::~CefRequestContextImpl() { |
| CEF_REQUIRE_UIT(); |
| |
| if (browser_context_) { |
| // May result in |browser_context_| being deleted if no other |
| // CefRequestContextImpl are referencing it. |
| browser_context_->RemoveCefRequestContext(this); |
| } |
| } |
| |
| // static |
| CefRefPtr<CefRequestContextImpl> |
| CefRequestContextImpl::CreateGlobalRequestContext( |
| const CefRequestContextSettings& settings) { |
| // Create and initialize the global context immediately. |
| Config config; |
| config.is_global = true; |
| config.settings = settings; |
| CefRefPtr<CefRequestContextImpl> impl = new CefRequestContextImpl(config); |
| impl->Initialize(); |
| return impl; |
| } |
| |
| // static |
| CefRefPtr<CefRequestContextImpl> |
| CefRequestContextImpl::GetOrCreateForRequestContext( |
| CefRefPtr<CefRequestContext> request_context) { |
| if (request_context.get()) { |
| // Use the context from the provided CefRequestContext. |
| return static_cast<CefRequestContextImpl*>(request_context.get()); |
| } |
| |
| // Use the global context. |
| Config config; |
| config.is_global = true; |
| return CefRequestContextImpl::GetOrCreateRequestContext(config); |
| } |
| |
| CefBrowserContext* CefRequestContextImpl::GetBrowserContext() { |
| EnsureBrowserContext(); |
| return browser_context(); |
| } |
| |
| void CefRequestContextImpl::GetBrowserContext( |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| const BrowserContextCallback& callback) { |
| if (!task_runner.get()) |
| task_runner = CefTaskRunnerImpl::GetCurrentTaskRunner(); |
| GetBrowserContextOnUIThread(task_runner, callback); |
| } |
| |
| bool CefRequestContextImpl::IsSame(CefRefPtr<CefRequestContext> other) { |
| CefRequestContextImpl* other_impl = |
| static_cast<CefRequestContextImpl*>(other.get()); |
| if (!other_impl) |
| return false; |
| |
| // Compare whether both are the global context. |
| if (config_.is_global && other_impl->config_.is_global) |
| return true; |
| |
| // Compare CefBrowserContext pointers if one has been associated. |
| if (browser_context() && other_impl->browser_context()) { |
| return (browser_context() == other_impl->browser_context()); |
| } else if (browser_context() || other_impl->browser_context()) { |
| return false; |
| } |
| |
| // Otherwise compare unique IDs. |
| return (config_.unique_id == other_impl->config_.unique_id); |
| } |
| |
| bool CefRequestContextImpl::IsSharingWith(CefRefPtr<CefRequestContext> other) { |
| CefRequestContextImpl* other_impl = |
| static_cast<CefRequestContextImpl*>(other.get()); |
| if (!other_impl) |
| return false; |
| |
| if (IsSame(other)) |
| return true; |
| |
| CefRefPtr<CefRequestContext> pending_other = config_.other; |
| if (pending_other.get()) { |
| // This object is not initialized but we know what context this object will |
| // share with. Compare to that other context instead. |
| return pending_other->IsSharingWith(other); |
| } |
| |
| pending_other = other_impl->config_.other; |
| if (pending_other.get()) { |
| // The other object is not initialized but we know what context that object |
| // will share with. Compare to that other context instead. |
| return pending_other->IsSharingWith(this); |
| } |
| |
| // This or the other object is not initialized. Compare the cache path values. |
| // If both are non-empty and the same then they'll share the same storage. |
| if (config_.settings.cache_path.length > 0 && |
| other_impl->config_.settings.cache_path.length > 0) { |
| return ( |
| base::FilePath(CefString(&config_.settings.cache_path)) == |
| base::FilePath(CefString(&other_impl->config_.settings.cache_path))); |
| } |
| |
| return false; |
| } |
| |
| bool CefRequestContextImpl::IsGlobal() { |
| return config_.is_global; |
| } |
| |
| CefRefPtr<CefRequestContextHandler> CefRequestContextImpl::GetHandler() { |
| return config_.handler; |
| } |
| |
| CefString CefRequestContextImpl::GetCachePath() { |
| return CefString(&config_.settings.cache_path); |
| } |
| |
| CefRefPtr<CefCookieManager> CefRequestContextImpl::GetCookieManager( |
| CefRefPtr<CefCompletionCallback> callback) { |
| CefRefPtr<CefCookieManagerImpl> cookie_manager = new CefCookieManagerImpl(); |
| InitializeCookieManagerOnUIThread(cookie_manager, callback); |
| return cookie_manager.get(); |
| } |
| |
| bool CefRequestContextImpl::RegisterSchemeHandlerFactory( |
| const CefString& scheme_name, |
| const CefString& domain_name, |
| CefRefPtr<CefSchemeHandlerFactory> factory) { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| CEF_POST_TASK(CEF_UIT, |
| base::BindOnce( |
| base::IgnoreResult( |
| &CefRequestContextImpl::RegisterSchemeHandlerFactory), |
| this, scheme_name, domain_name, factory)); |
| return true; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| browser_context()->RegisterSchemeHandlerFactory(scheme_name, domain_name, |
| factory); |
| return true; |
| } |
| |
| bool CefRequestContextImpl::ClearSchemeHandlerFactories() { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| CEF_POST_TASK( |
| CEF_UIT, |
| base::BindOnce(base::IgnoreResult( |
| &CefRequestContextImpl::ClearSchemeHandlerFactories), |
| this)); |
| return true; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| browser_context()->ClearSchemeHandlerFactories(); |
| return true; |
| } |
| |
| void CefRequestContextImpl::PurgePluginListCache(bool reload_pages) { |
| GetBrowserContext( |
| base::CreateSingleThreadTaskRunner({BrowserThread::UI}), |
| base::Bind(&CefRequestContextImpl::PurgePluginListCacheInternal, this, |
| reload_pages)); |
| } |
| |
| bool CefRequestContextImpl::HasPreference(const CefString& name) { |
| // Verify that this method is being called on the UI thread. |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return false; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| PrefService* pref_service = browser_context()->GetPrefs(); |
| return (pref_service->FindPreference(name) != nullptr); |
| } |
| |
| CefRefPtr<CefValue> CefRequestContextImpl::GetPreference( |
| const CefString& name) { |
| // Verify that this method is being called on the UI thread. |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return nullptr; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| PrefService* pref_service = browser_context()->GetPrefs(); |
| const PrefService::Preference* pref = pref_service->FindPreference(name); |
| if (!pref) |
| return nullptr; |
| return new CefValueImpl(pref->GetValue()->DeepCopy()); |
| } |
| |
| CefRefPtr<CefDictionaryValue> CefRequestContextImpl::GetAllPreferences( |
| bool include_defaults) { |
| // Verify that this method is being called on the UI thread. |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return nullptr; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| PrefService* pref_service = browser_context()->GetPrefs(); |
| |
| std::unique_ptr<base::DictionaryValue> values = |
| pref_service->GetPreferenceValues(include_defaults |
| ? PrefService::INCLUDE_DEFAULTS |
| : PrefService::EXCLUDE_DEFAULTS); |
| |
| // CefDictionaryValueImpl takes ownership of |values|. |
| return new CefDictionaryValueImpl(values.release(), true, false); |
| } |
| |
| bool CefRequestContextImpl::CanSetPreference(const CefString& name) { |
| // Verify that this method is being called on the UI thread. |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return false; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| PrefService* pref_service = browser_context()->GetPrefs(); |
| const PrefService::Preference* pref = pref_service->FindPreference(name); |
| return (pref && pref->IsUserModifiable()); |
| } |
| |
| bool CefRequestContextImpl::SetPreference(const CefString& name, |
| CefRefPtr<CefValue> value, |
| CefString& error) { |
| // Verify that this method is being called on the UI thread. |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return false; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| PrefService* pref_service = browser_context()->GetPrefs(); |
| |
| // The below validation logic should match PrefService::SetUserPrefValue. |
| |
| const PrefService::Preference* pref = pref_service->FindPreference(name); |
| if (!pref) { |
| error = "Trying to modify an unregistered preference"; |
| return false; |
| } |
| |
| if (!pref->IsUserModifiable()) { |
| error = "Trying to modify a preference that is not user modifiable"; |
| return false; |
| } |
| |
| if (!value.get()) { |
| // Reset the preference to its default value. |
| pref_service->ClearPref(name); |
| return true; |
| } |
| |
| if (!value->IsValid()) { |
| error = "A valid value is required"; |
| return false; |
| } |
| |
| CefValueImpl* impl = static_cast<CefValueImpl*>(value.get()); |
| |
| CefValueImpl::ScopedLockedValue scoped_locked_value(impl); |
| base::Value* impl_value = impl->GetValueUnsafe(); |
| |
| if (pref->GetType() != impl_value->type()) { |
| error = base::StringPrintf( |
| "Trying to set a preference of type %s to value of type %s", |
| GetTypeString(pref->GetType()), GetTypeString(impl_value->type())); |
| return false; |
| } |
| |
| // PrefService will make a DeepCopy of |impl_value|. |
| pref_service->Set(name, *impl_value); |
| return true; |
| } |
| |
| void CefRequestContextImpl::ClearCertificateExceptions( |
| CefRefPtr<CefCompletionCallback> callback) { |
| GetBrowserContext( |
| base::CreateSingleThreadTaskRunner({BrowserThread::UI}), |
| base::Bind(&CefRequestContextImpl::ClearCertificateExceptionsInternal, |
| this, callback)); |
| } |
| |
| void CefRequestContextImpl::ClearHttpAuthCredentials( |
| CefRefPtr<CefCompletionCallback> callback) { |
| GetBrowserContext( |
| base::CreateSingleThreadTaskRunner({BrowserThread::UI}), |
| base::Bind(&CefRequestContextImpl::ClearHttpAuthCredentialsInternal, this, |
| callback)); |
| } |
| |
| void CefRequestContextImpl::CloseAllConnections( |
| CefRefPtr<CefCompletionCallback> callback) { |
| GetBrowserContext( |
| base::CreateSingleThreadTaskRunner({BrowserThread::UI}), |
| base::Bind(&CefRequestContextImpl::CloseAllConnectionsInternal, this, |
| callback)); |
| } |
| |
| void CefRequestContextImpl::ResolveHost( |
| const CefString& origin, |
| CefRefPtr<CefResolveCallback> callback) { |
| GetBrowserContext(base::CreateSingleThreadTaskRunner({BrowserThread::UI}), |
| base::Bind(&CefRequestContextImpl::ResolveHostInternal, |
| this, origin, callback)); |
| } |
| |
| void CefRequestContextImpl::LoadExtension( |
| const CefString& root_directory, |
| CefRefPtr<CefDictionaryValue> manifest, |
| CefRefPtr<CefExtensionHandler> handler) { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| CEF_POST_TASK(CEF_UIT, |
| base::BindOnce(&CefRequestContextImpl::LoadExtension, this, |
| root_directory, manifest, handler)); |
| return; |
| } |
| |
| if (!extensions::ExtensionsEnabled()) { |
| if (handler) |
| handler->OnExtensionLoadFailed(ERR_ABORTED); |
| return; |
| } |
| |
| if (manifest && manifest->GetSize() > 0) { |
| CefDictionaryValueImpl* value_impl = |
| static_cast<CefDictionaryValueImpl*>(manifest.get()); |
| GetBrowserContext()->extension_system()->LoadExtension( |
| base::WrapUnique(value_impl->CopyValue()), root_directory, |
| false /* builtin */, this, handler); |
| } else { |
| GetBrowserContext()->extension_system()->LoadExtension( |
| root_directory, false /* builtin */, this, handler); |
| } |
| } |
| |
| bool CefRequestContextImpl::DidLoadExtension(const CefString& extension_id) { |
| CefRefPtr<CefExtension> extension = GetExtension(extension_id); |
| // GetLoaderContext() will return NULL for internal extensions. |
| return extension && IsSame(extension->GetLoaderContext()); |
| } |
| |
| bool CefRequestContextImpl::HasExtension(const CefString& extension_id) { |
| return !!GetExtension(extension_id); |
| } |
| |
| bool CefRequestContextImpl::GetExtensions( |
| std::vector<CefString>& extension_ids) { |
| extension_ids.clear(); |
| |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return false; |
| } |
| |
| if (!extensions::ExtensionsEnabled()) |
| return false; |
| |
| extensions::CefExtensionSystem::ExtensionMap extension_map = |
| GetBrowserContext()->extension_system()->GetExtensions(); |
| extensions::CefExtensionSystem::ExtensionMap::const_iterator it = |
| extension_map.begin(); |
| for (; it != extension_map.end(); ++it) |
| extension_ids.push_back(it->second->GetIdentifier()); |
| |
| return true; |
| } |
| |
| CefRefPtr<CefExtension> CefRequestContextImpl::GetExtension( |
| const CefString& extension_id) { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| NOTREACHED() << "called on invalid thread"; |
| return nullptr; |
| } |
| |
| if (!extensions::ExtensionsEnabled()) |
| return nullptr; |
| |
| return GetBrowserContext()->extension_system()->GetExtension(extension_id); |
| } |
| |
| CefRefPtr<CefMediaRouter> CefRequestContextImpl::GetMediaRouter() { |
| CefRefPtr<CefMediaRouterImpl> media_router = new CefMediaRouterImpl(); |
| InitializeMediaRouterOnUIThread(media_router); |
| return media_router.get(); |
| } |
| |
| void CefRequestContextImpl::OnRenderFrameCreated(int render_process_id, |
| int render_frame_id, |
| int frame_tree_node_id, |
| bool is_main_frame, |
| bool is_guest_view) { |
| browser_context_->OnRenderFrameCreated(this, render_process_id, |
| render_frame_id, frame_tree_node_id, |
| is_main_frame, is_guest_view); |
| } |
| |
| void CefRequestContextImpl::OnRenderFrameDeleted(int render_process_id, |
| int render_frame_id, |
| int frame_tree_node_id, |
| bool is_main_frame, |
| bool is_guest_view) { |
| browser_context_->OnRenderFrameDeleted(this, render_process_id, |
| render_frame_id, frame_tree_node_id, |
| is_main_frame, is_guest_view); |
| } |
| |
| // static |
| CefRefPtr<CefRequestContextImpl> |
| CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) { |
| if (config.is_global || |
| (config.other && config.other->IsGlobal() && !config.handler)) { |
| // Return the singleton global context. |
| return CefContentBrowserClient::Get()->request_context(); |
| } |
| |
| // The new context will be initialized later by EnsureBrowserContext(). |
| return new CefRequestContextImpl(config); |
| } |
| |
| CefRequestContextImpl::CefRequestContextImpl( |
| const CefRequestContextImpl::Config& config) |
| : config_(config) {} |
| |
| void CefRequestContextImpl::Initialize() { |
| CEF_REQUIRE_UIT(); |
| |
| DCHECK(!browser_context_); |
| |
| if (config_.other) { |
| // Share storage with |config_.other|. |
| browser_context_ = |
| CefBrowserContext::GetForContext(config_.other->GetBrowserContext()); |
| DCHECK(browser_context_); |
| } |
| |
| if (!browser_context_) { |
| if (!config_.is_global) { |
| // User-specified settings need to be normalized. |
| CefContext::Get()->NormalizeRequestContextSettings(&config_.settings); |
| } |
| |
| const base::FilePath& cache_path = |
| base::FilePath(CefString(&config_.settings.cache_path)); |
| if (!cache_path.empty()) { |
| // Check if a CefBrowserContext is already globally registered for |
| // the specified cache path. If so then use it. |
| browser_context_ = CefBrowserContext::GetForCachePath(cache_path); |
| } |
| } |
| |
| if (!browser_context_) { |
| // Create a new CefBrowserContext instance. If the cache path is non- |
| // empty then this new instance will become the globally registered |
| // CefBrowserContext for that path. Otherwise, this new instance will |
| // be a completely isolated "incognito mode" context. |
| browser_context_ = new CefBrowserContext(config_.settings); |
| browser_context_->Initialize(); |
| } else { |
| // Share the same settings as the existing context. |
| config_.settings = browser_context_->GetSettings(); |
| } |
| |
| // We'll disassociate from |browser_context_| on destruction. |
| browser_context_->AddCefRequestContext(this); |
| |
| if (config_.other) { |
| // Clear the reference to |config_.other| after setting |
| // |request_context_getter_|. This is the reverse order of checks in |
| // IsSharedWith(). |
| config_.other = nullptr; |
| } |
| |
| if (config_.handler) |
| config_.handler->OnRequestContextInitialized(this); |
| } |
| |
| void CefRequestContextImpl::EnsureBrowserContext() { |
| CEF_REQUIRE_UIT(); |
| if (!browser_context()) |
| Initialize(); |
| DCHECK(browser_context()); |
| } |
| |
| void CefRequestContextImpl::GetBrowserContextOnUIThread( |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| const BrowserContextCallback& callback) { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| CEF_POST_TASK( |
| CEF_UIT, base::Bind(&CefRequestContextImpl::GetBrowserContextOnUIThread, |
| this, task_runner, callback)); |
| return; |
| } |
| |
| // Make sure the browser context exists. |
| EnsureBrowserContext(); |
| |
| if (task_runner->BelongsToCurrentThread()) { |
| // Execute the callback immediately. |
| callback.Run(browser_context()); |
| } else { |
| // Execute the callback on the target thread. |
| task_runner->PostTask(FROM_HERE, base::Bind(callback, browser_context())); |
| } |
| } |
| |
| void CefRequestContextImpl::PurgePluginListCacheInternal( |
| bool reload_pages, |
| CefBrowserContext* browser_context) { |
| CEF_REQUIRE_UIT(); |
| browser_context->ClearPluginLoadDecision(-1); |
| content::PluginService::GetInstance()->PurgePluginListCache(browser_context, |
| false); |
| } |
| |
| void CefRequestContextImpl::ClearCertificateExceptionsInternal( |
| CefRefPtr<CefCompletionCallback> callback, |
| CefBrowserContext* browser_context) { |
| CEF_REQUIRE_UIT(); |
| |
| content::SSLHostStateDelegate* ssl_delegate = |
| browser_context->GetSSLHostStateDelegate(); |
| if (ssl_delegate) |
| ssl_delegate->Clear(base::Callback<bool(const std::string&)>()); |
| |
| if (callback) { |
| CEF_POST_TASK(CEF_UIT, |
| base::Bind(&CefCompletionCallback::OnComplete, callback)); |
| } |
| } |
| |
| void CefRequestContextImpl::ClearHttpAuthCredentialsInternal( |
| CefRefPtr<CefCompletionCallback> callback, |
| CefBrowserContext* browser_context) { |
| CEF_REQUIRE_UIT(); |
| |
| browser_context->GetNetworkContext()->ClearHttpAuthCache( |
| base::Time(), base::Bind(&CefCompletionCallback::OnComplete, callback)); |
| } |
| |
| void CefRequestContextImpl::CloseAllConnectionsInternal( |
| CefRefPtr<CefCompletionCallback> callback, |
| CefBrowserContext* browser_context) { |
| CEF_REQUIRE_UIT(); |
| |
| browser_context->GetNetworkContext()->CloseAllConnections( |
| base::Bind(&CefCompletionCallback::OnComplete, callback)); |
| } |
| |
| void CefRequestContextImpl::ResolveHostInternal( |
| const CefString& origin, |
| CefRefPtr<CefResolveCallback> callback, |
| CefBrowserContext* browser_context) { |
| CEF_REQUIRE_UIT(); |
| |
| // |helper| will be deleted in ResolveHostHelper::OnComplete(). |
| ResolveHostHelper* helper = new ResolveHostHelper(callback); |
| helper->Start(browser_context, origin); |
| } |
| |
| void CefRequestContextImpl::InitializeCookieManagerOnUIThread( |
| CefRefPtr<CefCookieManagerImpl> cookie_manager, |
| CefRefPtr<CefCompletionCallback> callback) { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| CEF_POST_TASK( |
| CEF_UIT, |
| base::Bind(&CefRequestContextImpl::InitializeCookieManagerOnUIThread, |
| this, cookie_manager, callback)); |
| return; |
| } |
| |
| auto browser_context = GetBrowserContext(); |
| cookie_manager->Initialize(browser_context->getter(), callback); |
| } |
| |
| void CefRequestContextImpl::InitializeMediaRouterOnUIThread( |
| CefRefPtr<CefMediaRouterImpl> media_router) { |
| if (!CEF_CURRENTLY_ON_UIT()) { |
| CEF_POST_TASK( |
| CEF_UIT, |
| base::Bind(&CefRequestContextImpl::InitializeMediaRouterOnUIThread, |
| this, media_router)); |
| return; |
| } |
| |
| auto browser_context = GetBrowserContext(); |
| media_router->Initialize(browser_context->getter()); |
| } |
| |
| CefBrowserContext* CefRequestContextImpl::browser_context() const { |
| return browser_context_; |
| } |