mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			824 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			824 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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_impl.h"
 | |
| #include "libcef/browser/browser_context_proxy.h"
 | |
| #include "libcef/browser/content_browser_client.h"
 | |
| #include "libcef/browser/context.h"
 | |
| #include "libcef/browser/cookie_manager_impl.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/plugin_service.h"
 | |
| #include "content/public/browser/ssl_host_state_delegate.h"
 | |
| #include "net/http/http_cache.h"
 | |
| #include "net/http/http_transaction_factory.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";
 | |
|   }
 | |
| 
 | |
|   NOTREACHED();
 | |
|   return "UNKNOWN";
 | |
| }
 | |
| 
 | |
| // Helper for HostResolver::Resolve.
 | |
| struct ResolveHostHelper {
 | |
|   explicit ResolveHostHelper(CefRefPtr<CefResolveCallback> callback)
 | |
|       : callback_(callback) {}
 | |
| 
 | |
|   void OnResolveCompleted(int result) {
 | |
|     std::vector<CefString> resolved_ips;
 | |
| 
 | |
|     net::AddressList::const_iterator iter = address_list_.begin();
 | |
|     for (; iter != 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_;
 | |
|   net::AddressList address_list_;
 | |
|   std::unique_ptr<net::HostResolver::Request> request_;
 | |
| };
 | |
| 
 | |
| }  // 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 NULL;
 | |
|   }
 | |
| 
 | |
|   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 NULL;
 | |
|   }
 | |
| 
 | |
|   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 NULL;
 | |
|   }
 | |
| 
 | |
|   if (!other.get())
 | |
|     return NULL;
 | |
| 
 | |
|   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();
 | |
| 
 | |
|   // Delete the proxy first because it also references |browser_context_impl_|.
 | |
|   if (browser_context_proxy_)
 | |
|     browser_context_proxy_.reset(nullptr);
 | |
| 
 | |
|   if (browser_context_impl_) {
 | |
|     // May result in |browser_context_impl_| being deleted if no other
 | |
|     // CefRequestContextImpl are referencing it.
 | |
|     browser_context_impl_->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);
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::GetRequestContextImpl(
 | |
|     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
 | |
|     const RequestContextCallback& callback) {
 | |
|   if (!task_runner.get())
 | |
|     task_runner = CefTaskRunnerImpl::GetCurrentTaskRunner();
 | |
|   if (request_context_getter_impl_) {
 | |
|     // The browser context already exists.
 | |
|     DCHECK(browser_context());
 | |
|     GetRequestContextImplOnIOThread(task_runner, callback, browser_context());
 | |
|   } else {
 | |
|     // Need to initialize the browser context first.
 | |
|     GetBrowserContextOnUIThread(
 | |
|         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
 | |
|         base::Bind(&CefRequestContextImpl::GetRequestContextImplOnIOThread,
 | |
|                    this, 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()) {
 | |
|     if (browser_context()->is_proxy() &&
 | |
|         other_impl->browser_context()->is_proxy()) {
 | |
|       CefBrowserContextProxy* proxy =
 | |
|           static_cast<CefBrowserContextProxy*>(browser_context());
 | |
|       CefBrowserContextProxy* other_proxy =
 | |
|           static_cast<CefBrowserContextProxy*>(other_impl->browser_context());
 | |
|       return (proxy->parent() == other_proxy->parent() &&
 | |
|               proxy->GetHandler() == other_proxy->GetHandler());
 | |
|     }
 | |
|     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);
 | |
|   }
 | |
| 
 | |
|   if (request_context_getter_impl_ &&
 | |
|       other_impl->request_context_getter_impl_) {
 | |
|     // Both objects are initialized. Compare the request context objects.
 | |
|     return (request_context_getter_impl_ ==
 | |
|             other_impl->request_context_getter_impl_);
 | |
|   }
 | |
| 
 | |
|   // 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::GetDefaultCookieManager(
 | |
|     CefRefPtr<CefCompletionCallback> callback) {
 | |
|   CefRefPtr<CefCookieManagerImpl> cookie_manager =
 | |
|       new CefCookieManagerImpl(false);
 | |
|   cookie_manager->Initialize(this, CefString(), false, callback);
 | |
|   return cookie_manager.get();
 | |
| }
 | |
| 
 | |
| bool CefRequestContextImpl::RegisterSchemeHandlerFactory(
 | |
|     const CefString& scheme_name,
 | |
|     const CefString& domain_name,
 | |
|     CefRefPtr<CefSchemeHandlerFactory> factory) {
 | |
|   GetRequestContextImpl(
 | |
|       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
 | |
|       base::Bind(&CefRequestContextImpl::RegisterSchemeHandlerFactoryInternal,
 | |
|                  this, scheme_name, domain_name, factory));
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CefRequestContextImpl::ClearSchemeHandlerFactories() {
 | |
|   GetRequestContextImpl(
 | |
|       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
 | |
|       base::Bind(&CefRequestContextImpl::ClearSchemeHandlerFactoriesInternal,
 | |
|                  this));
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::PurgePluginListCache(bool reload_pages) {
 | |
|   GetBrowserContext(
 | |
|       BrowserThread::GetTaskRunnerForThread(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) != NULL);
 | |
| }
 | |
| 
 | |
| 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 NULL;
 | |
|   }
 | |
| 
 | |
|   // Make sure the browser context exists.
 | |
|   EnsureBrowserContext();
 | |
| 
 | |
|   PrefService* pref_service = browser_context()->GetPrefs();
 | |
|   const PrefService::Preference* pref = pref_service->FindPreference(name);
 | |
|   if (!pref)
 | |
|     return NULL;
 | |
|   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 NULL;
 | |
|   }
 | |
| 
 | |
|   // 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(
 | |
|       BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
 | |
|       base::Bind(&CefRequestContextImpl::ClearCertificateExceptionsInternal,
 | |
|                  this, callback));
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::CloseAllConnections(
 | |
|     CefRefPtr<CefCompletionCallback> callback) {
 | |
|   GetRequestContextImpl(
 | |
|       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
 | |
|       base::Bind(&CefRequestContextImpl::CloseAllConnectionsInternal, this,
 | |
|                  callback));
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::ResolveHost(
 | |
|     const CefString& origin,
 | |
|     CefRefPtr<CefResolveCallback> callback) {
 | |
|   GetRequestContextImpl(
 | |
|       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
 | |
|       base::Bind(&CefRequestContextImpl::ResolveHostInternal, this, origin,
 | |
|                  callback));
 | |
| }
 | |
| 
 | |
| cef_errorcode_t CefRequestContextImpl::ResolveHostCached(
 | |
|     const CefString& origin,
 | |
|     std::vector<CefString>& resolved_ips) {
 | |
|   resolved_ips.clear();
 | |
| 
 | |
|   if (!CEF_CURRENTLY_ON_IOT()) {
 | |
|     NOTREACHED() << "called on invalid thread";
 | |
|     return ERR_FAILED;
 | |
|   }
 | |
| 
 | |
|   if (!request_context_getter_impl_)
 | |
|     return ERR_FAILED;
 | |
| 
 | |
|   int retval = ERR_FAILED;
 | |
| 
 | |
|   net::HostResolver* host_resolver =
 | |
|       request_context_getter_impl_->GetHostResolver();
 | |
|   if (host_resolver) {
 | |
|     net::HostResolver::RequestInfo request_info(
 | |
|         net::HostPortPair::FromURL(GURL(origin.ToString())));
 | |
|     net::AddressList address_list;
 | |
|     retval = host_resolver->ResolveFromCache(request_info, &address_list,
 | |
|                                              net::NetLogWithSource());
 | |
|     if (retval == net::OK) {
 | |
|       net::AddressList::const_iterator iter = address_list.begin();
 | |
|       for (; iter != address_list.end(); ++iter)
 | |
|         resolved_ips.push_back(iter->ToString());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return static_cast<cef_errorcode_t>(retval);
 | |
| }
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| // 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_impl_);
 | |
|   DCHECK(!request_context_getter_impl_);
 | |
| 
 | |
|   if (config_.other) {
 | |
|     // Share storage with |config_.other|.
 | |
|     browser_context_impl_ = CefBrowserContextImpl::GetForContext(
 | |
|         config_.other->GetBrowserContext());
 | |
|   }
 | |
| 
 | |
|   if (!browser_context_impl_) {
 | |
|     const base::FilePath& cache_path =
 | |
|         base::FilePath(CefString(&config_.settings.cache_path));
 | |
|     if (!cache_path.empty()) {
 | |
|       // Check if a CefBrowserContextImpl is already globally registered for
 | |
|       // the specified cache path. If so then use it.
 | |
|       browser_context_impl_ =
 | |
|           CefBrowserContextImpl::GetForCachePath(cache_path);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!browser_context_impl_) {
 | |
|     // Create a new CefBrowserContextImpl instance. If the cache path is non-
 | |
|     // empty then this new instance will become the globally registered
 | |
|     // CefBrowserContextImpl for that path. Otherwise, this new instance will
 | |
|     // be a completely isolated "incongento mode" context.
 | |
|     browser_context_impl_ = new CefBrowserContextImpl(config_.settings);
 | |
|     browser_context_impl_->Initialize();
 | |
|   }
 | |
| 
 | |
|   // We'll disassociate from |browser_context_impl_| on destruction.
 | |
|   browser_context_impl_->AddCefRequestContext(this);
 | |
| 
 | |
|   // Force our settings to match |browser_context_impl_|.
 | |
|   config_.settings = browser_context_impl_->GetSettings();
 | |
| 
 | |
|   if (config_.handler.get()) {
 | |
|     // Use a proxy that will execute handler callbacks where appropriate and
 | |
|     // otherwise forward all requests to |browser_context_impl_|.
 | |
|     browser_context_proxy_.reset(new CefBrowserContextProxy(
 | |
|         this, config_.handler, browser_context_impl_));
 | |
|     browser_context_proxy_->Initialize();
 | |
|     DCHECK(!config_.is_global);
 | |
|   }
 | |
| 
 | |
|   request_context_getter_impl_ =
 | |
|       browser_context_impl_->request_context_getter().get();
 | |
|   DCHECK(request_context_getter_impl_);
 | |
| 
 | |
|   if (config_.handler.get()) {
 | |
|     // Keep the handler alive until the associated request context is
 | |
|     // destroyed.
 | |
|     request_context_getter_impl_->AddHandler(config_.handler);
 | |
|   }
 | |
| 
 | |
|   if (config_.other) {
 | |
|     // Clear the reference to |config_.other| after setting
 | |
|     // |request_context_getter_impl_|. This is the reverse order of checks in
 | |
|     // IsSharedWith().
 | |
|     config_.other = NULL;
 | |
|   }
 | |
| 
 | |
|   if (config_.handler)
 | |
|     config_.handler->OnRequestContextInitialized(this);
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::EnsureBrowserContext() {
 | |
|   CEF_REQUIRE_UIT();
 | |
|   if (!browser_context())
 | |
|     Initialize();
 | |
|   DCHECK(browser_context());
 | |
|   DCHECK(request_context_getter_impl_);
 | |
| }
 | |
| 
 | |
| 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::GetRequestContextImplOnIOThread(
 | |
|     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
 | |
|     const RequestContextCallback& callback,
 | |
|     CefBrowserContext* browser_context) {
 | |
|   if (!CEF_CURRENTLY_ON_IOT()) {
 | |
|     CEF_POST_TASK(
 | |
|         CEF_IOT,
 | |
|         base::Bind(&CefRequestContextImpl::GetRequestContextImplOnIOThread,
 | |
|                    this, task_runner, callback, browser_context));
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   DCHECK(request_context_getter_impl_);
 | |
| 
 | |
|   // Make sure the request context exists.
 | |
|   request_context_getter_impl_->GetURLRequestContext();
 | |
| 
 | |
|   if (task_runner->BelongsToCurrentThread()) {
 | |
|     // Execute the callback immediately.
 | |
|     callback.Run(request_context_getter_impl_);
 | |
|   } else {
 | |
|     // Execute the callback on the target thread.
 | |
|     task_runner->PostTask(
 | |
|         FROM_HERE, base::Bind(callback, base::WrapRefCounted(
 | |
|                                             request_context_getter_impl_)));
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::RegisterSchemeHandlerFactoryInternal(
 | |
|     const CefString& scheme_name,
 | |
|     const CefString& domain_name,
 | |
|     CefRefPtr<CefSchemeHandlerFactory> factory,
 | |
|     scoped_refptr<CefURLRequestContextGetterImpl> request_context) {
 | |
|   CEF_REQUIRE_IOT();
 | |
|   request_context->request_manager()->AddFactory(scheme_name, domain_name,
 | |
|                                                  factory);
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::ClearSchemeHandlerFactoriesInternal(
 | |
|     scoped_refptr<CefURLRequestContextGetterImpl> request_context) {
 | |
|   CEF_REQUIRE_IOT();
 | |
|   request_context->request_manager()->ClearFactories();
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::PurgePluginListCacheInternal(
 | |
|     bool reload_pages,
 | |
|     CefBrowserContext* browser_context) {
 | |
|   CEF_REQUIRE_UIT();
 | |
|   browser_context->OnPurgePluginListCache();
 | |
|   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::CloseAllConnectionsInternal(
 | |
|     CefRefPtr<CefCompletionCallback> callback,
 | |
|     scoped_refptr<CefURLRequestContextGetterImpl> request_context) {
 | |
|   CEF_REQUIRE_IOT();
 | |
| 
 | |
|   net::URLRequestContext* url_context = request_context->GetURLRequestContext();
 | |
|   if (url_context) {
 | |
|     net::HttpTransactionFactory* http_factory =
 | |
|         url_context->http_transaction_factory();
 | |
|     if (http_factory) {
 | |
|       net::HttpCache* cache = http_factory->GetCache();
 | |
|       if (cache)
 | |
|         cache->CloseAllConnections();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (callback) {
 | |
|     CEF_POST_TASK(CEF_UIT,
 | |
|                   base::Bind(&CefCompletionCallback::OnComplete, callback));
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefRequestContextImpl::ResolveHostInternal(
 | |
|     const CefString& origin,
 | |
|     CefRefPtr<CefResolveCallback> callback,
 | |
|     scoped_refptr<CefURLRequestContextGetterImpl> request_context) {
 | |
|   CEF_REQUIRE_IOT();
 | |
| 
 | |
|   int retval = ERR_FAILED;
 | |
| 
 | |
|   // |helper| will be deleted in ResolveHostHelper::OnResolveCompleted().
 | |
|   ResolveHostHelper* helper = new ResolveHostHelper(callback);
 | |
| 
 | |
|   net::HostResolver* host_resolver = request_context->GetHostResolver();
 | |
|   if (host_resolver) {
 | |
|     net::HostResolver::RequestInfo request_info(
 | |
|         net::HostPortPair::FromURL(GURL(origin.ToString())));
 | |
|     retval = host_resolver->Resolve(
 | |
|         request_info, net::DEFAULT_PRIORITY, &helper->address_list_,
 | |
|         base::Bind(&ResolveHostHelper::OnResolveCompleted,
 | |
|                    base::Unretained(helper)),
 | |
|         &helper->request_, net::NetLogWithSource());
 | |
|     if (retval == net::ERR_IO_PENDING) {
 | |
|       // The result will be delivered asynchronously via the callback.
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   helper->OnResolveCompleted(retval);
 | |
| }
 | |
| 
 | |
| CefBrowserContext* CefRequestContextImpl::browser_context() const {
 | |
|   if (browser_context_proxy_)
 | |
|     return browser_context_proxy_.get();
 | |
|   return browser_context_impl_;
 | |
| }
 |