diff --git a/BUILD.gn b/BUILD.gn index eebbbe047..e749a4cd0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -720,6 +720,8 @@ static_library("libcef_static") { "libcef/common/net/upload_data.h", "libcef/common/net/upload_element.cc", "libcef/common/net/upload_element.h", + "libcef/common/net/url_util.cc", + "libcef/common/net/url_util.h", "libcef/common/net_service/net_service_util.cc", "libcef/common/net_service/net_service_util.h", "libcef/common/parser_impl.cc", diff --git a/include/capi/cef_media_router_capi.h b/include/capi/cef_media_router_capi.h index befb443d9..6d7b4f20a 100644 --- a/include/capi/cef_media_router_capi.h +++ b/include/capi/cef_media_router_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=3767c7759578cd4abc1c2ecef504e7ed60775abb$ +// $hash=79e4e38c732c0cfeef495c8a9726e105054012bb$ // #ifndef CEF_INCLUDE_CAPI_CEF_MEDIA_ROUTER_CAPI_H_ @@ -41,6 +41,7 @@ #pragma once #include "include/capi/cef_base_capi.h" +#include "include/capi/cef_callback_capi.h" #include "include/capi/cef_registration_capi.h" #ifdef __cplusplus @@ -110,11 +111,14 @@ typedef struct _cef_media_router_t { } cef_media_router_t; /// -// Returns the MediaRouter object associated with the global request context. -// Equivalent to calling cef_request_context_t::cef_request_context_get_global_c -// ontext()->get_media_router(). +// Returns the MediaRouter object associated with the global request context. If +// |callback| is non-NULL it will be executed asnychronously on the UI thread +// after the manager's storage has been initialized. Equivalent to calling cef_r +// equest_context_t::cef_request_context_get_global_context()->get_media_router( +// ). /// -CEF_EXPORT cef_media_router_t* cef_media_router_get_global(); +CEF_EXPORT cef_media_router_t* cef_media_router_get_global( + struct _cef_completion_callback_t* callback); /// // Implemented by the client to observe MediaRouter events and registered via diff --git a/include/capi/cef_request_context_capi.h b/include/capi/cef_request_context_capi.h index d1d7f23aa..9871a214d 100644 --- a/include/capi/cef_request_context_capi.h +++ b/include/capi/cef_request_context_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=d5079b6a5146ccd2085c3bbf948925c009d329ed$ +// $hash=2e42334fc22050e207e5a0af6fe290a592e4105f$ // #ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_ @@ -132,7 +132,7 @@ typedef struct _cef_request_context_t { /// // Returns the cookie manager for this object. If |callback| is non-NULL it - // will be executed asnychronously on the IO thread after the manager's + // will be executed asnychronously on the UI thread after the manager's // storage has been initialized. /// struct _cef_cookie_manager_t*(CEF_CALLBACK* get_cookie_manager)( @@ -356,10 +356,13 @@ typedef struct _cef_request_context_t { const cef_string_t* extension_id); /// - // Returns the MediaRouter object associated with this context. + // Returns the MediaRouter object associated with this context. If |callback| + // is non-NULL it will be executed asnychronously on the UI thread after the + // manager's context has been initialized. /// struct _cef_media_router_t*(CEF_CALLBACK* get_media_router)( - struct _cef_request_context_t* self); + struct _cef_request_context_t* self, + struct _cef_completion_callback_t* callback); } cef_request_context_t; /// diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h index 9c2ab6c8a..f1ee3c76c 100644 --- a/include/cef_api_hash.h +++ b/include/cef_api_hash.h @@ -42,13 +42,13 @@ // way that may cause binary incompatibility with other builds. The universal // hash value will change if any platform is affected whereas the platform hash // values will change only if that particular platform is affected. -#define CEF_API_HASH_UNIVERSAL "0468b890ed1832b3763cb5f16c7b007219964b06" +#define CEF_API_HASH_UNIVERSAL "d128245052a84dd90cd38fed0e6be65824d37de5" #if defined(OS_WIN) -#define CEF_API_HASH_PLATFORM "dbe7a5bb3fa66b97a57175575d870a003ce632fe" +#define CEF_API_HASH_PLATFORM "9b1a4706bf1fca26d542aa5f8b05d222f483c872" #elif defined(OS_MAC) -#define CEF_API_HASH_PLATFORM "f1f736e3e19916d0f3f11de71deff8448dc3a35f" +#define CEF_API_HASH_PLATFORM "0038a822915e3567f2434053ebc49723fe6951d5" #elif defined(OS_LINUX) -#define CEF_API_HASH_PLATFORM "de19204124690a84b9b24102f3bd41991781e044" +#define CEF_API_HASH_PLATFORM "66613a535ec6a1aafce6ece8e98cd3876f79633b" #endif #ifdef __cplusplus diff --git a/include/cef_media_router.h b/include/cef_media_router.h index a406884ec..378c3fc51 100644 --- a/include/cef_media_router.h +++ b/include/cef_media_router.h @@ -40,6 +40,7 @@ #include #include "include/cef_base.h" +#include "include/cef_callback.h" #include "include/cef_registration.h" class CefMediaObserver; @@ -59,11 +60,13 @@ class CefMediaRouter : public virtual CefBaseRefCounted { public: /// // Returns the MediaRouter object associated with the global request context. - // Equivalent to calling - // CefRequestContext::GetGlobalContext()->GetMediaRouter(). + // If |callback| is non-NULL it will be executed asnychronously on the UI + // thread after the manager's storage has been initialized. Equivalent to + // calling CefRequestContext::GetGlobalContext()->GetMediaRouter(). /// - /*--cef()--*/ - static CefRefPtr GetGlobalMediaRouter(); + /*--cef(optional_param=callback)--*/ + static CefRefPtr GetGlobalMediaRouter( + CefRefPtr callback); /// // Add an observer for MediaRouter events. The observer will remain registered diff --git a/include/cef_request_context.h b/include/cef_request_context.h index edb65da6a..ca1a55e5f 100644 --- a/include/cef_request_context.h +++ b/include/cef_request_context.h @@ -146,7 +146,7 @@ class CefRequestContext : public virtual CefBaseRefCounted { /// // Returns the cookie manager for this object. If |callback| is non-NULL it - // will be executed asnychronously on the IO thread after the manager's + // will be executed asnychronously on the UI thread after the manager's // storage has been initialized. /// /*--cef(optional_param=callback)--*/ @@ -364,10 +364,13 @@ class CefRequestContext : public virtual CefBaseRefCounted { const CefString& extension_id) = 0; /// - // Returns the MediaRouter object associated with this context. + // Returns the MediaRouter object associated with this context. If |callback| + // is non-NULL it will be executed asnychronously on the UI thread after the + // manager's context has been initialized. /// - /*--cef()--*/ - virtual CefRefPtr GetMediaRouter() = 0; + /*--cef(optional_param=callback)--*/ + virtual CefRefPtr GetMediaRouter( + CefRefPtr callback) = 0; }; #endif // CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_ diff --git a/libcef/browser/alloy/alloy_browser_context.cc b/libcef/browser/alloy/alloy_browser_context.cc index 87bc0d01b..6877382c5 100644 --- a/libcef/browser/alloy/alloy_browser_context.cc +++ b/libcef/browser/alloy/alloy_browser_context.cc @@ -113,6 +113,18 @@ AlloyBrowserContext::~AlloyBrowserContext() { } } +bool AlloyBrowserContext::IsInitialized() const { + CEF_REQUIRE_UIT(); + return !!key_; +} + +void AlloyBrowserContext::StoreOrTriggerInitCallback( + base::OnceClosure callback) { + CEF_REQUIRE_UIT(); + // Initialization is always synchronous. + std::move(callback).Run(); +} + void AlloyBrowserContext::Initialize() { CefBrowserContext::Initialize(); diff --git a/libcef/browser/alloy/alloy_browser_context.h b/libcef/browser/alloy/alloy_browser_context.h index b7b2bf366..db4154ce4 100644 --- a/libcef/browser/alloy/alloy_browser_context.h +++ b/libcef/browser/alloy/alloy_browser_context.h @@ -42,6 +42,8 @@ class AlloyBrowserContext : public ChromeProfileAlloy, // CefBrowserContext overrides. content::BrowserContext* AsBrowserContext() override { return this; } Profile* AsProfile() override { return this; } + bool IsInitialized() const override; + void StoreOrTriggerInitCallback(base::OnceClosure callback) override; void Initialize() override; void Shutdown() override; void RemoveCefRequestContext(CefRequestContextImpl* context) override; diff --git a/libcef/browser/alloy/alloy_browser_host_impl.cc b/libcef/browser/alloy/alloy_browser_host_impl.cc index 77f3b7af6..e8778dba3 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.cc +++ b/libcef/browser/alloy/alloy_browser_host_impl.cc @@ -24,6 +24,7 @@ #include "libcef/common/cef_messages.h" #include "libcef/common/cef_switches.h" #include "libcef/common/drag_data_impl.h" +#include "libcef/common/net/url_util.h" #include "libcef/common/request_impl.h" #include "libcef/common/values_impl.h" #include "libcef/features/runtime_checks.h" @@ -175,12 +176,13 @@ CefRefPtr AlloyBrowserHostImpl::Create( if (!browser) return nullptr; + GURL url = url_util::MakeGURL(create_params.url, /*fixup=*/true); + if (create_params.extension) { platform_delegate_ptr->CreateExtensionHost( - create_params.extension, create_params.url, - create_params.extension_host_type); - } else if (!create_params.url.is_empty()) { - content::OpenURLParams params(create_params.url, content::Referrer(), + create_params.extension, url, create_params.extension_host_type); + } else if (!url.is_empty()) { + content::OpenURLParams params(url, content::Referrer(), WindowOpenDisposition::CURRENT_TAB, CefFrameHostImpl::kPageTransitionExplicit, /*is_renderer_initiated=*/false); diff --git a/libcef/browser/alloy/browser_platform_delegate_alloy.cc b/libcef/browser/alloy/browser_platform_delegate_alloy.cc index 4c02ce1f9..e9b7968bd 100644 --- a/libcef/browser/alloy/browser_platform_delegate_alloy.cc +++ b/libcef/browser/alloy/browser_platform_delegate_alloy.cc @@ -12,6 +12,7 @@ #include "libcef/browser/extensions/extension_web_contents_observer.h" #include "libcef/browser/printing/print_view_manager.h" #include "libcef/common/extensions/extensions_util.h" +#include "libcef/common/net/url_util.h" #include "libcef/features/runtime_checks.h" #include "base/logging.h" @@ -58,12 +59,13 @@ content::WebContents* CefBrowserPlatformDelegateAlloy::CreateWebContents( } scoped_refptr site_instance; - if (extensions::ExtensionsEnabled() && !create_params.url.is_empty()) { + if (extensions::ExtensionsEnabled() && !create_params.url.empty()) { + GURL gurl = url_util::MakeGURL(create_params.url, /*fixup=*/true); if (!create_params.extension) { // We might be loading an extension app view where the extension URL is // provided by the client. create_params.extension = - extensions::GetExtensionForUrl(browser_context, create_params.url); + extensions::GetExtensionForUrl(browser_context, gurl); } if (create_params.extension) { if (create_params.extension_host_type == extensions::VIEW_TYPE_INVALID) { @@ -79,7 +81,7 @@ content::WebContents* CefBrowserPlatformDelegateAlloy::CreateWebContents( // ExtensionProtocolHandler::MaybeCreateJob will return false resulting in // ERR_BLOCKED_BY_CLIENT). site_instance = extensions::ProcessManager::Get(browser_context) - ->GetSiteInstanceForURL(create_params.url); + ->GetSiteInstanceForURL(gurl); DCHECK(site_instance); } } diff --git a/libcef/browser/browser_context.h b/libcef/browser/browser_context.h index 310590d3c..dce938812 100644 --- a/libcef/browser/browser_context.h +++ b/libcef/browser/browser_context.h @@ -112,6 +112,13 @@ class CefBrowserContext { virtual content::BrowserContext* AsBrowserContext() = 0; virtual Profile* AsProfile() = 0; + // Returns true if the context is fully initialized. + virtual bool IsInitialized() const = 0; + + // If the context is fully initialized execute |callback|, otherwise + // store it until the context is fully initialized. + virtual void StoreOrTriggerInitCallback(base::OnceClosure callback) = 0; + // Called from CefRequestContextImpl to track associated objects. This // object will delete itself when the count reaches zero. void AddCefRequestContext(CefRequestContextImpl* context); diff --git a/libcef/browser/browser_host_base.cc b/libcef/browser/browser_host_base.cc index 0520a5798..5670d731e 100644 --- a/libcef/browser/browser_host_base.cc +++ b/libcef/browser/browser_host_base.cc @@ -9,13 +9,13 @@ #include "libcef/browser/image_impl.h" #include "libcef/browser/navigation_entry_impl.h" #include "libcef/browser/thread_util.h" +#include "libcef/common/net/url_util.h" #include "base/logging.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" #include "chrome/browser/spellchecker/spellcheck_service.h" #include "components/favicon/core/favicon_url.h" #include "components/spellcheck/common/spellcheck_features.h" -#include "components/url_formatter/url_fixer.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/download_request_utils.h" @@ -761,16 +761,9 @@ bool CefBrowserHostBase::Navigate(const content::OpenURLParams& params) { CEF_REQUIRE_UIT(); auto web_contents = GetWebContents(); if (web_contents) { - // Fix common problems with user-typed text. Among other things, this: - // - Converts absolute file paths to "file://" URLs. - // - Normalizes "about:" and "chrome:" to "chrome://" URLs. - // - Adds the "http://" scheme if none was specified. - GURL gurl = url_formatter::FixupURL(params.url.possibly_invalid_spec(), - std::string()); - if (!gurl.is_valid()) { - LOG(ERROR) << "Invalid URL: " << params.url.possibly_invalid_spec(); + GURL gurl = params.url; + if (!url_util::FixupGURL(gurl)) return false; - } web_contents->GetController().LoadURL( gurl, params.referrer, params.transition, params.extra_headers); diff --git a/libcef/browser/browser_host_base.h b/libcef/browser/browser_host_base.h index 9ddc18aed..76d0db138 100644 --- a/libcef/browser/browser_host_base.h +++ b/libcef/browser/browser_host_base.h @@ -65,7 +65,7 @@ struct CefBrowserCreateParams { // Initial URL to load. May be empty. If this is a valid extension URL then // the browser will be created as an app view extension host. - GURL url; + CefString url; // Browser settings. CefBrowserSettings settings; diff --git a/libcef/browser/browser_host_create.cc b/libcef/browser/browser_host_create.cc index a7fc6a3dc..a6db29f72 100644 --- a/libcef/browser/browser_host_create.cc +++ b/libcef/browser/browser_host_create.cc @@ -10,8 +10,6 @@ #include "libcef/browser/thread_util.h" #include "libcef/features/runtime.h" -#include "components/url_formatter/url_fixer.h" - namespace { class CreateBrowserHelper { @@ -29,6 +27,11 @@ class CreateBrowserHelper { extra_info_(extra_info), request_context_(request_context) {} + void Run() { + CefBrowserHost::CreateBrowserSync(window_info_, client_, url_, settings_, + extra_info_, request_context_); + } + CefWindowInfo window_info_; CefRefPtr client_; CefString url_; @@ -73,19 +76,20 @@ bool CefBrowserHost::CreateBrowser( "reduced performance or runtime errors."; } - // Create the browser on the UI thread. - CreateBrowserHelper* helper = new CreateBrowserHelper( + if (!request_context) { + request_context = CefRequestContext::GetGlobalContext(); + } + + auto helper = std::make_unique( windowInfo, client, url, settings, extra_info, request_context); - CEF_POST_TASK(CEF_UIT, base::BindOnce( - [](CreateBrowserHelper* helper) { - CefBrowserHost::CreateBrowserSync( - helper->window_info_, helper->client_, - helper->url_, helper->settings_, - helper->extra_info_, - helper->request_context_); - delete helper; - }, - helper)); + + auto request_context_impl = + static_cast(request_context.get()); + + // Wait for the browser context to be initialized before creating the browser. + request_context_impl->ExecuteWhenBrowserContextInitialized(base::BindOnce( + [](std::unique_ptr helper) { helper->Run(); }, + std::move(helper))); return true; } @@ -110,9 +114,10 @@ CefRefPtr CefBrowserHost::CreateBrowserSync( return nullptr; } - // Verify that this method is being called on the UI thread. - if (!CEF_CURRENTLY_ON_UIT()) { - NOTREACHED() << "called on invalid thread"; + // Verify that the browser context is valid. + auto request_context_impl = + static_cast(request_context.get()); + if (!request_context_impl->VerifyBrowserContext()) { return nullptr; } @@ -126,15 +131,7 @@ CefRefPtr CefBrowserHost::CreateBrowserSync( CefBrowserCreateParams create_params; create_params.window_info.reset(new CefWindowInfo(windowInfo)); create_params.client = client; - create_params.url = GURL(url.ToString()); - if (!url.empty() && !create_params.url.is_valid() && - !create_params.url.has_scheme()) { - std::string fixed_scheme(url::kHttpScheme); - fixed_scheme.append(url::kStandardSchemeSeparator); - std::string new_url = url; - new_url.insert(0, fixed_scheme); - create_params.url = GURL(new_url); - } + create_params.url = url; create_params.settings = settings; create_params.extra_info = extra_info; create_params.request_context = request_context; @@ -145,22 +142,6 @@ CefRefPtr CefBrowserHost::CreateBrowserSync( // static CefRefPtr CefBrowserHostBase::Create( CefBrowserCreateParams& create_params) { - if (!create_params.url.is_empty()) { - // Fix common problems with user-typed text. Among other things, this: - // - Converts absolute file paths to "file://" URLs. - // - Normalizes "about:" and "chrome:" to "chrome://" URLs. - // - Adds the "http://" scheme if none was specified. - GURL gurl = url_formatter::FixupURL( - create_params.url.possibly_invalid_spec(), std::string()); - if (gurl.is_valid()) { - create_params.url = gurl; - } else { - LOG(ERROR) << "Invalid URL: " - << create_params.url.possibly_invalid_spec(); - create_params.url = GURL(); - } - } - if (cef::IsChromeRuntimeEnabled()) { auto browser = ChromeBrowserHostImpl::Create(create_params); return browser.get(); diff --git a/libcef/browser/chrome/chrome_browser_context.cc b/libcef/browser/chrome/chrome_browser_context.cc index f514b03fc..37888d19a 100644 --- a/libcef/browser/chrome/chrome_browser_context.cc +++ b/libcef/browser/chrome/chrome_browser_context.cc @@ -5,6 +5,7 @@ #include "libcef/browser/chrome/chrome_browser_context.h" #include "libcef/browser/prefs/browser_prefs.h" +#include "libcef/browser/thread_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/off_the_record_profile_impl.h" @@ -23,8 +24,23 @@ Profile* ChromeBrowserContext::AsProfile() { return profile_; } +bool ChromeBrowserContext::IsInitialized() const { + CEF_REQUIRE_UIT(); + return !!profile_; +} + +void ChromeBrowserContext::StoreOrTriggerInitCallback( + base::OnceClosure callback) { + CEF_REQUIRE_UIT(); + if (IsInitialized()) { + std::move(callback).Run(); + } else { + init_callbacks_.emplace_back(std::move(callback)); + } +} + void ChromeBrowserContext::InitializeAsync(base::OnceClosure initialized_cb) { - initialized_cb_ = std::move(initialized_cb); + init_callbacks_.emplace_back(std::move(initialized_cb)); CefBrowserContext::Initialize(); @@ -106,6 +122,11 @@ void ChromeBrowserContext::ProfileCreated(Profile* profile, parent_profile->NotifyOffTheRecordProfileCreated(otr_profile); } - std::move(initialized_cb_).Run(); + if (!init_callbacks_.empty()) { + for (auto& callback : init_callbacks_) { + std::move(callback).Run(); + } + init_callbacks_.clear(); + } } } diff --git a/libcef/browser/chrome/chrome_browser_context.h b/libcef/browser/chrome/chrome_browser_context.h index db8c3a726..6d4c9423c 100644 --- a/libcef/browser/chrome/chrome_browser_context.h +++ b/libcef/browser/chrome/chrome_browser_context.h @@ -22,6 +22,8 @@ class ChromeBrowserContext : public CefBrowserContext { // CefBrowserContext overrides. content::BrowserContext* AsBrowserContext() override; Profile* AsProfile() override; + bool IsInitialized() const override; + void StoreOrTriggerInitCallback(base::OnceClosure callback) override; void Shutdown() override; private: @@ -33,6 +35,8 @@ class ChromeBrowserContext : public CefBrowserContext { Profile* profile_ = nullptr; bool should_destroy_ = false; + std::vector init_callbacks_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ChromeBrowserContext); diff --git a/libcef/browser/chrome/chrome_browser_host_impl.cc b/libcef/browser/chrome/chrome_browser_host_impl.cc index 337dcab4f..76b5da71d 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.cc +++ b/libcef/browser/chrome/chrome_browser_host_impl.cc @@ -8,6 +8,7 @@ #include "libcef/browser/chrome/browser_platform_delegate_chrome.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/views/browser_view_impl.h" +#include "libcef/common/net/url_util.h" #include "libcef/features/runtime_checks.h" #include "base/logging.h" @@ -21,8 +22,6 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/pref_names.h" -#include "components/url_formatter/url_fixer.h" -#include "url/url_constants.h" #if defined(TOOLKIT_VIEWS) #include "libcef/browser/chrome/views/chrome_browser_frame.h" @@ -34,7 +33,7 @@ CefRefPtr ChromeBrowserHostImpl::Create( const CefBrowserCreateParams& params) { auto browser = CreateBrowser(params); - GURL url = params.url; + GURL url = url_util::MakeGURL(params.url, /*fixup=*/true); if (url.is_empty()) { // Chrome will navigate to kChromeUINewTabURL by default. We want to keep // the current CEF behavior of not navigating at all. Use a special URL that @@ -392,16 +391,9 @@ bool ChromeBrowserHostImpl::Navigate(const content::OpenURLParams& params) { } if (browser_) { - // Fix common problems with user-typed text. Among other things, this: - // - Converts absolute file paths to "file://" URLs. - // - Normalizes "about:" and "chrome:" to "chrome://" URLs. - // - Adds the "http://" scheme if none was specified. - GURL gurl = url_formatter::FixupURL(params.url.possibly_invalid_spec(), - std::string()); - if (!gurl.is_valid()) { - LOG(ERROR) << "Invalid URL: " << params.url.possibly_invalid_spec(); + GURL gurl = params.url; + if (!url_util::FixupGURL(gurl)) return false; - } // This is generally equivalent to calling Browser::OpenURL, except: // 1. It doesn't trigger a call to CefRequestHandler::OnOpenURLFromTab, and @@ -448,6 +440,7 @@ Browser* ChromeBrowserHostImpl::CreateBrowser( auto cef_browser_context = request_context_impl->GetBrowserContext(); CHECK(cef_browser_context); auto profile = cef_browser_context->AsProfile(); + CHECK(profile); Browser::CreateParams chrome_params = Browser::CreateParams(profile, /*user_gesture=*/false); diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index 8dcb40da3..9942e2e3a 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -5,6 +5,7 @@ #include "libcef/browser/context.h" #include "libcef/browser/browser_info_manager.h" +#include "libcef/browser/request_context_impl.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/trace_subscriber.h" #include "libcef/common/cef_switches.h" @@ -474,12 +475,19 @@ bool CefContext::HasObserver(Observer* observer) const { void CefContext::OnContextInitialized() { CEF_REQUIRE_UIT(); - // Notify the handler. if (application_) { - CefRefPtr handler = - application_->GetBrowserProcessHandler(); - if (handler) - handler->OnContextInitialized(); + // Notify the handler after the global browser context has initialized. + CefRefPtr request_context = + CefRequestContext::GetGlobalContext(); + auto impl = static_cast(request_context.get()); + impl->ExecuteWhenBrowserContextInitialized(base::BindOnce( + [](CefRefPtr app) { + CefRefPtr handler = + app->GetBrowserProcessHandler(); + if (handler) + handler->OnContextInitialized(); + }, + application_)); } } diff --git a/libcef/browser/extensions/extension_function_details.cc b/libcef/browser/extensions/extension_function_details.cc index 658444f8c..da19b2d40 100644 --- a/libcef/browser/extensions/extension_function_details.cc +++ b/libcef/browser/extensions/extension_function_details.cc @@ -366,7 +366,7 @@ base::DictionaryValue* CefExtensionFunctionDetails::OpenTab( return nullptr; CefBrowserCreateParams create_params; - create_params.url = url; + create_params.url = url.spec(); create_params.request_context = request_context; create_params.window_info.reset(new CefWindowInfo); @@ -381,9 +381,9 @@ base::DictionaryValue* CefExtensionFunctionDetails::OpenTab( CefRefPtr handler = cef_extension->GetHandler(); if (handler.get() && handler->OnBeforeBrowser(cef_extension, sender_browser.get(), - active_browser.get(), index, url.spec(), active, - *create_params.window_info, create_params.client, - create_params.settings)) { + active_browser.get(), index, create_params.url, + active, *create_params.window_info, + create_params.client, create_params.settings)) { // Cancel the browser creation. return nullptr; } diff --git a/libcef/browser/extensions/extensions_browser_client.cc b/libcef/browser/extensions/extensions_browser_client.cc index ade0ecd07..5ce037ba8 100644 --- a/libcef/browser/extensions/extensions_browser_client.cc +++ b/libcef/browser/extensions/extensions_browser_client.cc @@ -251,13 +251,13 @@ bool CefExtensionsBrowserClient::CreateBackgroundExtensionHost( } CefBrowserCreateParams create_params; - create_params.url = url; + create_params.url = url.spec(); create_params.request_context = request_context; CefRefPtr handler = cef_extension->GetHandler(); if (handler.get() && handler->OnBeforeBackgroundBrowser( - cef_extension, url.spec(), create_params.client, - create_params.settings)) { + cef_extension, create_params.url, + create_params.client, create_params.settings)) { // Cancel the background host creation. return true; } diff --git a/libcef/browser/frame_host_impl.cc b/libcef/browser/frame_host_impl.cc index b82cf00da..df800f43f 100644 --- a/libcef/browser/frame_host_impl.cc +++ b/libcef/browser/frame_host_impl.cc @@ -12,12 +12,12 @@ #include "libcef/browser/navigate_params.h" #include "libcef/browser/net_service/browser_urlrequest_impl.h" #include "libcef/common/cef_messages.h" -#include "libcef/common/frame_util.h" +#include "libcef/common/frame_util.h" +#include "libcef/common/net/url_util.h" #include "libcef/common/process_message_impl.h" #include "libcef/common/request_impl.h" #include "libcef/common/task_runner_impl.h" -#include "components/url_formatter/url_fixer.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -310,16 +310,9 @@ void CefFrameHostImpl::NotifyMoveOrResizeStarted() { void CefFrameHostImpl::Navigate(const CefNavigateParams& params) { CefMsg_LoadRequest_Params request; - // Fix common problems with user-typed text. Among other things, this: - // - Converts absolute file paths to "file://" URLs. - // - Normalizes "about:" and "chrome:" to "chrome://" URLs. - // - Adds the "http://" scheme if none was specified. - request.url = url_formatter::FixupURL(params.url.possibly_invalid_spec(), - std::string()); - if (!request.url.is_valid()) { - LOG(ERROR) << "Invalid URL: " << params.url.possibly_invalid_spec(); + request.url = params.url; + if (!url_util::FixupGURL(request.url)) return; - } request.method = params.method; request.referrer = params.referrer.url; @@ -347,16 +340,8 @@ void CefFrameHostImpl::LoadURLWithExtras(const std::string& url, if (frame_id < CefFrameHostImpl::kMainFrameId) return; - // Any necessary fixup of the URL will occur in - // [CefBrowserHostBase|CefFrameHostImpl]::Navigate(). - GURL gurl(url); - if (!url.empty() && !gurl.is_valid() && !gurl.has_scheme()) { - std::string fixed_scheme(url::kHttpScheme); - fixed_scheme.append(url::kStandardSchemeSeparator); - std::string new_url = url; - new_url.insert(0, fixed_scheme); - gurl = GURL(new_url); - } + // Any necessary fixup will occur in Navigate. + GURL gurl = url_util::MakeGURL(url, /*fixup=*/false); if (frame_id == CefFrameHostImpl::kMainFrameId) { // Load via the browser using NavigationController. diff --git a/libcef/browser/media_router/media_router_impl.cc b/libcef/browser/media_router/media_router_impl.cc index 91950f8e5..68673d792 100644 --- a/libcef/browser/media_router/media_router_impl.cc +++ b/libcef/browser/media_router/media_router_impl.cc @@ -144,11 +144,27 @@ CefMediaRouterImpl::CefMediaRouterImpl() { } void CefMediaRouterImpl::Initialize( - const CefBrowserContext::Getter& browser_context_getter) { + const CefBrowserContext::Getter& browser_context_getter, + CefRefPtr callback) { CEF_REQUIRE_UIT(); + DCHECK(!initialized_); DCHECK(!browser_context_getter.is_null()); DCHECK(browser_context_getter_.is_null()); browser_context_getter_ = browser_context_getter; + + initialized_ = true; + if (!init_callbacks_.empty()) { + for (auto& callback : init_callbacks_) { + std::move(callback).Run(); + } + init_callbacks_.clear(); + } + + if (callback) { + // Execute client callback asynchronously for consistency. + CEF_POST_TASK(CEF_UIT, base::Bind(&CefCompletionCallback::OnComplete, + callback.get())); + } } CefRefPtr CefMediaRouterImpl::AddObserver( @@ -157,7 +173,8 @@ CefRefPtr CefMediaRouterImpl::AddObserver( return nullptr; CefRefPtr registration = new CefRegistrationImpl(observer); - InitializeRegistrationOnUIThread(registration); + StoreOrTriggerInitCallback(base::BindOnce( + &CefMediaRouterImpl::InitializeRegistrationInternal, this, registration)); return registration.get(); } @@ -181,11 +198,32 @@ CefRefPtr CefMediaRouterImpl::GetSource(const CefString& urn) { } void CefMediaRouterImpl::NotifyCurrentSinks() { - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, base::BindOnce(&CefMediaRouterImpl::NotifyCurrentSinks, this)); - return; - } + StoreOrTriggerInitCallback( + base::BindOnce(&CefMediaRouterImpl::NotifyCurrentSinksInternal, this)); +} + +void CefMediaRouterImpl::CreateRoute( + CefRefPtr source, + CefRefPtr sink, + CefRefPtr callback) { + StoreOrTriggerInitCallback(base::BindOnce( + &CefMediaRouterImpl::CreateRouteInternal, this, source, sink, callback)); +} + +void CefMediaRouterImpl::NotifyCurrentRoutes() { + StoreOrTriggerInitCallback( + base::BindOnce(&CefMediaRouterImpl::NotifyCurrentRoutesInternal, this)); +} + +void CefMediaRouterImpl::InitializeRegistrationInternal( + CefRefPtr registration) { + DCHECK(ValidContext()); + + registration->Initialize(browser_context_getter_); +} + +void CefMediaRouterImpl::NotifyCurrentSinksInternal() { + DCHECK(ValidContext()); auto browser_context = GetBrowserContext(browser_context_getter_); if (!browser_context) @@ -194,21 +232,17 @@ void CefMediaRouterImpl::NotifyCurrentSinks() { browser_context->GetMediaRouterManager()->NotifyCurrentSinks(); } -void CefMediaRouterImpl::CreateRoute( +void CefMediaRouterImpl::CreateRouteInternal( CefRefPtr source, CefRefPtr sink, CefRefPtr callback) { - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMediaRouterImpl::CreateRoute, - this, source, sink, callback)); - return; - } + DCHECK(ValidContext()); std::string error; auto browser_context = GetBrowserContext(browser_context_getter_); if (!browser_context) { - error = "Context has already been destroyed"; + error = "Context is not valid"; } else if (!source) { error = "Source is empty or invalid"; } else if (!sink) { @@ -234,12 +268,8 @@ void CefMediaRouterImpl::CreateRoute( base::BindOnce(&CefMediaRouterImpl::CreateRouteCallback, this, callback)); } -void CefMediaRouterImpl::NotifyCurrentRoutes() { - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK(CEF_UIT, base::BindOnce( - &CefMediaRouterImpl::NotifyCurrentRoutes, this)); - return; - } +void CefMediaRouterImpl::NotifyCurrentRoutesInternal() { + DCHECK(ValidContext()); auto browser_context = GetBrowserContext(browser_context_getter_); if (!browser_context) @@ -248,22 +278,10 @@ void CefMediaRouterImpl::NotifyCurrentRoutes() { browser_context->GetMediaRouterManager()->NotifyCurrentRoutes(); } -void CefMediaRouterImpl::InitializeRegistrationOnUIThread( - CefRefPtr registration) { - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, - base::BindOnce(&CefMediaRouterImpl::InitializeRegistrationOnUIThread, - this, registration)); - return; - } - registration->Initialize(browser_context_getter_); -} - void CefMediaRouterImpl::CreateRouteCallback( CefRefPtr callback, const media_router::RouteRequestResult& result) { - CEF_REQUIRE_UIT(); + DCHECK(ValidContext()); if (result.result_code() != media_router::RouteRequestResult::OK) { LOG(WARNING) << "Media route creation failed: " << result.error() << " (" @@ -284,7 +302,30 @@ void CefMediaRouterImpl::CreateRouteCallback( result.error(), route); } -// static -CefRefPtr CefMediaRouter::GetGlobalMediaRouter() { - return CefRequestContext::GetGlobalContext()->GetMediaRouter(); +void CefMediaRouterImpl::StoreOrTriggerInitCallback( + base::OnceClosure callback) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK( + CEF_UIT, base::BindOnce(&CefMediaRouterImpl::StoreOrTriggerInitCallback, + this, std::move(callback))); + return; + } + + if (initialized_) { + std::move(callback).Run(); + } else { + init_callbacks_.emplace_back(std::move(callback)); + } +} + +bool CefMediaRouterImpl::ValidContext() const { + return CEF_CURRENTLY_ON_UIT() && initialized_; +} + +// CefMediaRouter methods ------------------------------------------------------ + +// static +CefRefPtr CefMediaRouter::GetGlobalMediaRouter( + CefRefPtr callback) { + return CefRequestContext::GetGlobalContext()->GetMediaRouter(callback); } diff --git a/libcef/browser/media_router/media_router_impl.h b/libcef/browser/media_router/media_router_impl.h index 05dc40851..50ff8fcf3 100644 --- a/libcef/browser/media_router/media_router_impl.h +++ b/libcef/browser/media_router/media_router_impl.h @@ -20,7 +20,8 @@ class CefMediaRouterImpl : public CefMediaRouter { // Called on the UI thread after object creation and before any other object // methods are executed on the UI thread. - void Initialize(const CefBrowserContext::Getter& browser_context_getter); + void Initialize(const CefBrowserContext::Getter& browser_context_getter, + CefRefPtr callback); // CefMediaRouter methods. CefRefPtr AddObserver( @@ -33,15 +34,29 @@ class CefMediaRouterImpl : public CefMediaRouter { void NotifyCurrentRoutes() override; private: - void InitializeRegistrationOnUIThread( + void InitializeRegistrationInternal( CefRefPtr registration); + void NotifyCurrentSinksInternal(); + void CreateRouteInternal(CefRefPtr source, + CefRefPtr sink, + CefRefPtr callback); + void NotifyCurrentRoutesInternal(); void CreateRouteCallback(CefRefPtr callback, const media_router::RouteRequestResult& result); + // If the context is fully initialized execute |callback|, otherwise + // store it until the context is fully initialized. + void StoreOrTriggerInitCallback(base::OnceClosure callback); + + bool ValidContext() const; + // Only accessed on the UI thread. Will be non-null after Initialize(). CefBrowserContext::Getter browser_context_getter_; + bool initialized_ = false; + std::vector init_callbacks_; + IMPLEMENT_REFCOUNTING(CefMediaRouterImpl); DISALLOW_COPY_AND_ASSIGN(CefMediaRouterImpl); }; diff --git a/libcef/browser/net_service/browser_urlrequest_impl.cc b/libcef/browser/net_service/browser_urlrequest_impl.cc index 2db6ce212..ca69087fb 100644 --- a/libcef/browser/net_service/browser_urlrequest_impl.cc +++ b/libcef/browser/net_service/browser_urlrequest_impl.cc @@ -144,12 +144,18 @@ class CefBrowserURLRequest::Context if (!url.is_valid()) return false; - CEF_POST_TASK( - CEF_UIT, - base::BindOnce( - &CefBrowserURLRequest::Context::GetURLLoaderFactoryGetterOnUIThread, - frame_, request_context_, weak_ptr_factory_.GetWeakPtr(), - task_runner_)); + if (!request_context_) { + request_context_ = CefRequestContext::GetGlobalContext(); + } + + auto request_context_impl = + static_cast(request_context_.get()); + + // Wait for the browser context to be initialized before continuing. + request_context_impl->ExecuteWhenBrowserContextInitialized(base::BindOnce( + &CefBrowserURLRequest::Context::GetURLLoaderFactoryGetterOnUIThread, + frame_, request_context_, weak_ptr_factory_.GetWeakPtr(), + task_runner_)); return true; } @@ -193,11 +199,12 @@ class CefBrowserURLRequest::Context // Get or create the request context and browser context. CefRefPtr request_context_impl = CefRequestContextImpl::GetOrCreateForRequestContext(request_context); - DCHECK(request_context_impl); + CHECK(request_context_impl); CefBrowserContext* cef_browser_context = request_context_impl->GetBrowserContext(); - DCHECK(cef_browser_context); + CHECK(cef_browser_context); auto browser_context = cef_browser_context->AsBrowserContext(); + CHECK(browser_context); int render_frame_id = MSG_ROUTING_NONE; scoped_refptr loader_factory_getter; diff --git a/libcef/browser/net_service/cookie_manager_impl.cc b/libcef/browser/net_service/cookie_manager_impl.cc index 632c4acd3..935cad6c3 100644 --- a/libcef/browser/net_service/cookie_manager_impl.cc +++ b/libcef/browser/net_service/cookie_manager_impl.cc @@ -123,9 +123,19 @@ void CefCookieManagerImpl::Initialize( CefBrowserContext::Getter browser_context_getter, CefRefPtr callback) { CEF_REQUIRE_UIT(); + DCHECK(!initialized_); DCHECK(!browser_context_getter.is_null()); DCHECK(browser_context_getter_.is_null()); browser_context_getter_ = browser_context_getter; + + initialized_ = true; + if (!init_callbacks_.empty()) { + for (auto& callback : init_callbacks_) { + std::move(callback).Run(); + } + init_callbacks_.clear(); + } + RunAsyncCompletionOnUIThread(callback); } @@ -134,22 +144,14 @@ bool CefCookieManagerImpl::VisitAllCookies( if (!visitor.get()) return false; - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, - base::Bind(base::IgnoreResult(&CefCookieManagerImpl::VisitAllCookies), - this, visitor)); + if (!ValidContext()) { + StoreOrTriggerInitCallback(base::BindOnce( + base::IgnoreResult(&CefCookieManagerImpl::VisitAllCookiesInternal), + this, visitor)); return true; } - auto browser_context = GetBrowserContext(browser_context_getter_); - if (!browser_context) - return false; - - GetCookieManager(browser_context) - ->GetAllCookies(base::Bind(&GetAllCookiesCallbackImpl, visitor, - browser_context_getter_)); - return true; + return VisitAllCookiesInternal(visitor); } bool CefCookieManagerImpl::VisitUrlCookies( @@ -163,14 +165,87 @@ bool CefCookieManagerImpl::VisitUrlCookies( if (!gurl.is_valid()) return false; - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, - base::Bind(base::IgnoreResult(&CefCookieManagerImpl::VisitUrlCookies), - this, url, includeHttpOnly, visitor)); + if (!ValidContext()) { + StoreOrTriggerInitCallback(base::BindOnce( + base::IgnoreResult(&CefCookieManagerImpl::VisitUrlCookiesInternal), + this, gurl, includeHttpOnly, visitor)); return true; } + return VisitUrlCookiesInternal(gurl, includeHttpOnly, visitor); +} + +bool CefCookieManagerImpl::SetCookie(const CefString& url, + const CefCookie& cookie, + CefRefPtr callback) { + GURL gurl = GURL(url.ToString()); + if (!gurl.is_valid()) + return false; + + if (!ValidContext()) { + StoreOrTriggerInitCallback(base::BindOnce( + base::IgnoreResult(&CefCookieManagerImpl::SetCookieInternal), this, + gurl, cookie, callback)); + return true; + } + + return SetCookieInternal(gurl, cookie, callback); +} + +bool CefCookieManagerImpl::DeleteCookies( + const CefString& url, + const CefString& cookie_name, + CefRefPtr callback) { + // Empty URLs are allowed but not invalid URLs. + GURL gurl = GURL(url.ToString()); + if (!gurl.is_empty() && !gurl.is_valid()) + return false; + + if (!ValidContext()) { + StoreOrTriggerInitCallback(base::BindOnce( + base::IgnoreResult(&CefCookieManagerImpl::DeleteCookiesInternal), this, + gurl, cookie_name, callback)); + return true; + } + + return DeleteCookiesInternal(gurl, cookie_name, callback); +} + +bool CefCookieManagerImpl::FlushStore( + CefRefPtr callback) { + if (!ValidContext()) { + StoreOrTriggerInitCallback(base::BindOnce( + base::IgnoreResult(&CefCookieManagerImpl::FlushStoreInternal), this, + callback)); + return true; + } + + return FlushStoreInternal(callback); +} + +bool CefCookieManagerImpl::VisitAllCookiesInternal( + CefRefPtr visitor) { + DCHECK(ValidContext()); + DCHECK(visitor); + + auto browser_context = GetBrowserContext(browser_context_getter_); + if (!browser_context) + return false; + + GetCookieManager(browser_context) + ->GetAllCookies(base::Bind(&GetAllCookiesCallbackImpl, visitor, + browser_context_getter_)); + return true; +} + +bool CefCookieManagerImpl::VisitUrlCookiesInternal( + const GURL& url, + bool includeHttpOnly, + CefRefPtr visitor) { + DCHECK(ValidContext()); + DCHECK(visitor); + DCHECK(url.is_valid()); + net::CookieOptions options; if (includeHttpOnly) options.set_include_httponly(); @@ -182,26 +257,18 @@ bool CefCookieManagerImpl::VisitUrlCookies( return false; GetCookieManager(browser_context) - ->GetCookieList(gurl, options, + ->GetCookieList(url, options, base::Bind(&GetCookiesCallbackImpl, visitor, browser_context_getter_)); return true; } -bool CefCookieManagerImpl::SetCookie(const CefString& url, - const CefCookie& cookie, - CefRefPtr callback) { - GURL gurl = GURL(url.ToString()); - if (!gurl.is_valid()) - return false; - - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, - base::Bind(base::IgnoreResult(&CefCookieManagerImpl::SetCookie), this, - url, cookie, callback)); - return true; - } +bool CefCookieManagerImpl::SetCookieInternal( + const GURL& url, + const CefCookie& cookie, + CefRefPtr callback) { + DCHECK(ValidContext()); + DCHECK(url.is_valid()); std::string name = CefString(&cookie.name).ToString(); std::string value = CefString(&cookie.value).ToString(); @@ -218,7 +285,7 @@ bool CefCookieManagerImpl::SetCookie(const CefString& url, net_service::MakeCookiePriority(cookie.priority); auto canonical_cookie = net::CanonicalCookie::CreateSanitizedCookie( - gurl, name, value, domain, path, + url, name, value, domain, path, base::Time(), // Creation time. expiration_time, base::Time(), // Last access time. @@ -243,39 +310,29 @@ bool CefCookieManagerImpl::SetCookie(const CefString& url, return false; GetCookieManager(browser_context) - ->SetCanonicalCookie(*canonical_cookie, gurl, options, + ->SetCanonicalCookie(*canonical_cookie, url, options, base::Bind(SetCookieCallbackImpl, callback)); return true; } -bool CefCookieManagerImpl::DeleteCookies( - const CefString& url, +bool CefCookieManagerImpl::DeleteCookiesInternal( + const GURL& url, const CefString& cookie_name, CefRefPtr callback) { - // Empty URLs are allowed but not invalid URLs. - GURL gurl = GURL(url.ToString()); - if (!gurl.is_empty() && !gurl.is_valid()) - return false; - - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, - base::Bind(base::IgnoreResult(&CefCookieManagerImpl::DeleteCookies), - this, url, cookie_name, callback)); - return true; - } + DCHECK(ValidContext()); + DCHECK(url.is_empty() || url.is_valid()); network::mojom::CookieDeletionFilterPtr deletion_filter = network::mojom::CookieDeletionFilter::New(); - if (gurl.is_empty()) { + if (url.is_empty()) { // Delete all cookies. } else if (cookie_name.empty()) { // Delete all matching host cookies. - deletion_filter->host_name = gurl.host(); + deletion_filter->host_name = url.host(); } else { // Delete all matching host and domain cookies. - deletion_filter->url = gurl; + deletion_filter->url = url; deletion_filter->cookie_name = cookie_name; } @@ -289,15 +346,9 @@ bool CefCookieManagerImpl::DeleteCookies( return true; } -bool CefCookieManagerImpl::FlushStore( +bool CefCookieManagerImpl::FlushStoreInternal( CefRefPtr callback) { - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK( - CEF_UIT, - base::Bind(base::IgnoreResult(&CefCookieManagerImpl::FlushStore), this, - callback)); - return true; - } + DCHECK(ValidContext()); auto browser_context = GetBrowserContext(browser_context_getter_); if (!browser_context) @@ -308,6 +359,27 @@ bool CefCookieManagerImpl::FlushStore( return true; } +void CefCookieManagerImpl::StoreOrTriggerInitCallback( + base::OnceClosure callback) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK( + CEF_UIT, + base::BindOnce(&CefCookieManagerImpl::StoreOrTriggerInitCallback, this, + std::move(callback))); + return; + } + + if (initialized_) { + std::move(callback).Run(); + } else { + init_callbacks_.emplace_back(std::move(callback)); + } +} + +bool CefCookieManagerImpl::ValidContext() const { + return CEF_CURRENTLY_ON_UIT() && initialized_; +} + // CefCookieManager methods ---------------------------------------------------- // static diff --git a/libcef/browser/net_service/cookie_manager_impl.h b/libcef/browser/net_service/cookie_manager_impl.h index 3892693c2..036cc3edf 100644 --- a/libcef/browser/net_service/cookie_manager_impl.h +++ b/libcef/browser/net_service/cookie_manager_impl.h @@ -36,9 +36,30 @@ class CefCookieManagerImpl : public CefCookieManager { bool FlushStore(CefRefPtr callback) override; private: + bool VisitAllCookiesInternal(CefRefPtr visitor); + bool VisitUrlCookiesInternal(const GURL& url, + bool includeHttpOnly, + CefRefPtr visitor); + bool SetCookieInternal(const GURL& url, + const CefCookie& cookie, + CefRefPtr callback); + bool DeleteCookiesInternal(const GURL& url, + const CefString& cookie_name, + CefRefPtr callback); + bool FlushStoreInternal(CefRefPtr callback); + + // If the context is fully initialized execute |callback|, otherwise + // store it until the context is fully initialized. + void StoreOrTriggerInitCallback(base::OnceClosure callback); + + bool ValidContext() const; + // Only accessed on the UI thread. Will be non-null after Initialize(). CefBrowserContext::Getter browser_context_getter_; + bool initialized_ = false; + std::vector init_callbacks_; + IMPLEMENT_REFCOUNTING(CefCookieManagerImpl); DISALLOW_COPY_AND_ASSIGN(CefCookieManagerImpl); }; diff --git a/libcef/browser/request_context_impl.cc b/libcef/browser/request_context_impl.cc index 21ca16d2f..47801015d 100644 --- a/libcef/browser/request_context_impl.cc +++ b/libcef/browser/request_context_impl.cc @@ -228,17 +228,67 @@ CefRequestContextImpl::GetOrCreateForRequestContext( return CefRequestContextImpl::GetOrCreateRequestContext(config); } +bool CefRequestContextImpl::VerifyBrowserContext() const { + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "called on invalid thread"; + return false; + } + + if (!browser_context() || !browser_context()->IsInitialized()) { + NOTREACHED() << "Uninitialized context"; + return false; + } + + return true; +} + CefBrowserContext* CefRequestContextImpl::GetBrowserContext() { - EnsureBrowserContext(); + CHECK(VerifyBrowserContext()); return browser_context(); } +void CefRequestContextImpl::ExecuteWhenBrowserContextInitialized( + base::OnceClosure callback) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK( + CEF_UIT, + base::BindOnce( + &CefRequestContextImpl::ExecuteWhenBrowserContextInitialized, this, + std::move(callback))); + return; + } + + EnsureBrowserContext(); + browser_context()->StoreOrTriggerInitCallback(std::move(callback)); +} + void CefRequestContextImpl::GetBrowserContext( scoped_refptr task_runner, - const BrowserContextCallback& callback) { + BrowserContextCallback callback) { if (!task_runner.get()) task_runner = CefTaskRunnerImpl::GetCurrentTaskRunner(); - GetBrowserContextOnUIThread(task_runner, callback); + + ExecuteWhenBrowserContextInitialized(base::BindOnce( + [](CefRefPtr context, + scoped_refptr task_runner, + BrowserContextCallback callback) { + CEF_REQUIRE_UIT(); + + auto browser_context = context->browser_context(); + DCHECK(browser_context->IsInitialized()); + + if (task_runner->BelongsToCurrentThread()) { + // Execute the callback immediately. + std::move(callback).Run(browser_context->getter()); + } else { + // Execute the callback on the target thread. + task_runner->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), browser_context->getter())); + } + }, + CefRefPtr(this), task_runner, + std::move(callback))); } bool CefRequestContextImpl::IsSame(CefRefPtr other) { @@ -312,7 +362,7 @@ CefString CefRequestContextImpl::GetCachePath() { CefRefPtr CefRequestContextImpl::GetCookieManager( CefRefPtr callback) { CefRefPtr cookie_manager = new CefCookieManagerImpl(); - InitializeCookieManagerOnUIThread(cookie_manager, callback); + InitializeCookieManagerInternal(cookie_manager, callback); return cookie_manager.get(); } @@ -320,56 +370,45 @@ bool CefRequestContextImpl::RegisterSchemeHandlerFactory( const CefString& scheme_name, const CefString& domain_name, CefRefPtr 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; - } + GetBrowserContext( + content::GetUIThreadTaskRunner({}), + base::BindOnce( + [](const CefString& scheme_name, const CefString& domain_name, + CefRefPtr factory, + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (browser_context) { + browser_context->RegisterSchemeHandlerFactory( + scheme_name, domain_name, factory); + } + }, + scheme_name, domain_name, factory)); - // 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; - } + GetBrowserContext( + content::GetUIThreadTaskRunner({}), + base::BindOnce([](CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (browser_context) + browser_context->ClearSchemeHandlerFactories(); + })); - // Make sure the browser context exists. - EnsureBrowserContext(); - - browser_context()->ClearSchemeHandlerFactories(); return true; } void CefRequestContextImpl::PurgePluginListCache(bool reload_pages) { GetBrowserContext( content::GetUIThreadTaskRunner({}), - base::Bind(&CefRequestContextImpl::PurgePluginListCacheInternal, this, - reload_pages)); + base::BindOnce(&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"; + if (!VerifyBrowserContext()) return false; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); PrefService* pref_service = browser_context()->AsProfile()->GetPrefs(); return (pref_service->FindPreference(name) != nullptr); @@ -377,14 +416,8 @@ bool CefRequestContextImpl::HasPreference(const CefString& name) { CefRefPtr 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"; + if (!VerifyBrowserContext()) return nullptr; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); PrefService* pref_service = browser_context()->AsProfile()->GetPrefs(); const PrefService::Preference* pref = pref_service->FindPreference(name); @@ -395,14 +428,8 @@ CefRefPtr CefRequestContextImpl::GetPreference( CefRefPtr 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"; + if (!VerifyBrowserContext()) return nullptr; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); PrefService* pref_service = browser_context()->AsProfile()->GetPrefs(); @@ -419,14 +446,8 @@ CefRefPtr CefRequestContextImpl::GetAllPreferences( } 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"; + if (!VerifyBrowserContext()) return false; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); PrefService* pref_service = browser_context()->AsProfile()->GetPrefs(); const PrefService::Preference* pref = pref_service->FindPreference(name); @@ -436,14 +457,8 @@ bool CefRequestContextImpl::CanSetPreference(const CefString& name) { bool CefRequestContextImpl::SetPreference(const CefString& name, CefRefPtr value, CefString& error) { - // Verify that this method is being called on the UI thread. - if (!CEF_CURRENTLY_ON_UIT()) { - NOTREACHED() << "called on invalid thread"; + if (!VerifyBrowserContext()) return false; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); PrefService* pref_service = browser_context()->AsProfile()->GetPrefs(); @@ -492,49 +507,53 @@ void CefRequestContextImpl::ClearCertificateExceptions( CefRefPtr callback) { GetBrowserContext( content::GetUIThreadTaskRunner({}), - base::Bind(&CefRequestContextImpl::ClearCertificateExceptionsInternal, - this, callback)); + base::BindOnce(&CefRequestContextImpl::ClearCertificateExceptionsInternal, + this, callback)); } void CefRequestContextImpl::ClearHttpAuthCredentials( CefRefPtr callback) { GetBrowserContext( content::GetUIThreadTaskRunner({}), - base::Bind(&CefRequestContextImpl::ClearHttpAuthCredentialsInternal, this, - callback)); + base::BindOnce(&CefRequestContextImpl::ClearHttpAuthCredentialsInternal, + this, callback)); } void CefRequestContextImpl::CloseAllConnections( CefRefPtr callback) { GetBrowserContext( content::GetUIThreadTaskRunner({}), - base::Bind(&CefRequestContextImpl::CloseAllConnectionsInternal, this, - callback)); + base::BindOnce(&CefRequestContextImpl::CloseAllConnectionsInternal, this, + callback)); } void CefRequestContextImpl::ResolveHost( const CefString& origin, CefRefPtr callback) { GetBrowserContext(content::GetUIThreadTaskRunner({}), - base::Bind(&CefRequestContextImpl::ResolveHostInternal, - this, origin, callback)); + base::BindOnce(&CefRequestContextImpl::ResolveHostInternal, + this, origin, callback)); } void CefRequestContextImpl::LoadExtension( const CefString& root_directory, CefRefPtr manifest, CefRefPtr handler) { - if (!CEF_CURRENTLY_ON_UIT()) { - CEF_POST_TASK(CEF_UIT, - base::BindOnce(&CefRequestContextImpl::LoadExtension, this, - root_directory, manifest, handler)); - return; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); - - browser_context()->LoadExtension(root_directory, manifest, handler, this); + GetBrowserContext(content::GetUIThreadTaskRunner({}), + base::BindOnce( + [](const CefString& root_directory, + CefRefPtr manifest, + CefRefPtr handler, + CefRefPtr self, + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (browser_context) { + browser_context->LoadExtension( + root_directory, manifest, handler, self); + } + }, + root_directory, manifest, handler, + CefRefPtr(this))); } bool CefRequestContextImpl::DidLoadExtension(const CefString& extension_id) { @@ -551,33 +570,24 @@ bool CefRequestContextImpl::GetExtensions( std::vector& extension_ids) { extension_ids.clear(); - if (!CEF_CURRENTLY_ON_UIT()) { - NOTREACHED() << "called on invalid thread"; + if (!VerifyBrowserContext()) return false; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); return browser_context()->GetExtensions(extension_ids); } CefRefPtr CefRequestContextImpl::GetExtension( const CefString& extension_id) { - if (!CEF_CURRENTLY_ON_UIT()) { - NOTREACHED() << "called on invalid thread"; + if (!VerifyBrowserContext()) return nullptr; - } - - // Make sure the browser context exists. - EnsureBrowserContext(); return browser_context()->GetExtension(extension_id); } -CefRefPtr CefRequestContextImpl::GetMediaRouter() { +CefRefPtr CefRequestContextImpl::GetMediaRouter( + CefRefPtr callback) { CefRefPtr media_router = new CefMediaRouterImpl(); - InitializeMediaRouterOnUIThread(media_router); + InitializeMediaRouterInternal(media_router, callback); return media_router.get(); } @@ -614,14 +624,12 @@ CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) { // The new context will be initialized later by EnsureBrowserContext(). CefRefPtr context = new CefRequestContextImpl(config); - if (config.handler) { - // Keep the context alive until OnRequestContextInitialized is called. - if (CEF_CURRENTLY_ON_UIT()) { - context->Initialize(); - } else { - CEF_POST_TASK( - CEF_UIT, base::BindOnce(&CefRequestContextImpl::Initialize, context)); - } + // Initialize ASAP so that any tasks blocked on initialization will execute. + if (CEF_CURRENTLY_ON_UIT()) { + context->Initialize(); + } else { + CEF_POST_TASK(CEF_UIT, + base::BindOnce(&CefRequestContextImpl::Initialize, context)); } return context; @@ -638,8 +646,8 @@ void CefRequestContextImpl::Initialize() { if (config_.other) { // Share storage with |config_.other|. - browser_context_ = config_.other->GetBrowserContext(); - DCHECK(browser_context_); + browser_context_ = config_.other->browser_context(); + CHECK(browser_context_); } if (!browser_context_) { @@ -670,7 +678,7 @@ void CefRequestContextImpl::Initialize() { } else { // Share the same settings as the existing context. config_.settings = browser_context_->settings(); - std::move(initialized_cb).Run(); + browser_context_->StoreOrTriggerInitCallback(std::move(initialized_cb)); } // We'll disassociate from |browser_context_| on destruction. @@ -701,32 +709,13 @@ void CefRequestContextImpl::EnsureBrowserContext() { DCHECK(browser_context()); } -void CefRequestContextImpl::GetBrowserContextOnUIThread( - scoped_refptr 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(); + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (!browser_context) + return; + browser_context->ClearPluginLoadDecision(-1); content::PluginService::GetInstance()->PurgePluginListCache( browser_context->AsBrowserContext(), false); @@ -734,8 +723,10 @@ void CefRequestContextImpl::PurgePluginListCacheInternal( void CefRequestContextImpl::ClearCertificateExceptionsInternal( CefRefPtr callback, - CefBrowserContext* browser_context) { - CEF_REQUIRE_UIT(); + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (!browser_context) + return; content::SSLHostStateDelegate* ssl_delegate = browser_context->AsBrowserContext()->GetSSLHostStateDelegate(); @@ -750,8 +741,10 @@ void CefRequestContextImpl::ClearCertificateExceptionsInternal( void CefRequestContextImpl::ClearHttpAuthCredentialsInternal( CefRefPtr callback, - CefBrowserContext* browser_context) { - CEF_REQUIRE_UIT(); + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (!browser_context) + return; browser_context->GetNetworkContext()->ClearHttpAuthCache( /*start_time=*/base::Time(), /*end_time=*/base::Time::Max(), @@ -760,8 +753,10 @@ void CefRequestContextImpl::ClearHttpAuthCredentialsInternal( void CefRequestContextImpl::CloseAllConnectionsInternal( CefRefPtr callback, - CefBrowserContext* browser_context) { - CEF_REQUIRE_UIT(); + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (!browser_context) + return; browser_context->GetNetworkContext()->CloseAllConnections( base::Bind(&CefCompletionCallback::OnComplete, callback)); @@ -770,41 +765,42 @@ void CefRequestContextImpl::CloseAllConnectionsInternal( void CefRequestContextImpl::ResolveHostInternal( const CefString& origin, CefRefPtr callback, - CefBrowserContext* browser_context) { - CEF_REQUIRE_UIT(); + CefBrowserContext::Getter browser_context_getter) { + auto browser_context = browser_context_getter.Run(); + if (!browser_context) + return; // |helper| will be deleted in ResolveHostHelper::OnComplete(). ResolveHostHelper* helper = new ResolveHostHelper(callback); helper->Start(browser_context, origin); } -void CefRequestContextImpl::InitializeCookieManagerOnUIThread( +void CefRequestContextImpl::InitializeCookieManagerInternal( CefRefPtr cookie_manager, CefRefPtr 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); + GetBrowserContext(content::GetUIThreadTaskRunner({}), + base::BindOnce( + [](CefRefPtr cookie_manager, + CefRefPtr callback, + CefBrowserContext::Getter browser_context_getter) { + cookie_manager->Initialize(browser_context_getter, + callback); + }, + cookie_manager, callback)); } -void CefRequestContextImpl::InitializeMediaRouterOnUIThread( - CefRefPtr 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()); +void CefRequestContextImpl::InitializeMediaRouterInternal( + CefRefPtr media_router, + CefRefPtr callback) { + GetBrowserContext(content::GetUIThreadTaskRunner({}), + base::BindOnce( + [](CefRefPtr media_router, + CefRefPtr callback, + CefBrowserContext::Getter browser_context_getter) { + media_router->Initialize(browser_context_getter, + callback); + }, + media_router, callback)); } CefBrowserContext* CefRequestContextImpl::browser_context() const { diff --git a/libcef/browser/request_context_impl.h b/libcef/browser/request_context_impl.h index ed1f84966..af09e22e2 100644 --- a/libcef/browser/request_context_impl.h +++ b/libcef/browser/request_context_impl.h @@ -30,17 +30,27 @@ class CefRequestContextImpl : public CefRequestContext { static CefRefPtr GetOrCreateForRequestContext( CefRefPtr request_context); - // Returns the browser context object. Can only be called on the UI thread. + // Verify that the browser context can be directly accessed (e.g. on the UI + // thread and initialized). + bool VerifyBrowserContext() const; + + // Returns the browser context object. Can only be called on the UI thread + // after the browser context has been initialized. CefBrowserContext* GetBrowserContext(); - // Executes |callback| either synchronously or asynchronously with the browser - // context object when it's available. If |task_runner| is NULL the callback - // will be executed on the originating thread. The resulting context object - // can only be accessed on the UI thread. - typedef base::Callback BrowserContextCallback; + // If the context is fully initialized execute |callback|, otherwise + // store it until the context is fully initialized. + void ExecuteWhenBrowserContextInitialized(base::OnceClosure callback); + + // Executes |callback| either synchronously or asynchronously after the + // browser context object has been initialized. If |task_runner| is NULL the + // callback will be executed on the originating thread. The resulting getter + // can only be executed on the UI thread. + using BrowserContextCallback = + base::OnceCallback; void GetBrowserContext( scoped_refptr task_runner, - const BrowserContextCallback& callback); + BrowserContextCallback callback); bool IsSame(CefRefPtr other) override; bool IsSharingWith(CefRefPtr other) override; @@ -77,7 +87,8 @@ class CefRequestContextImpl : public CefRequestContext { bool HasExtension(const CefString& extension_id) override; bool GetExtensions(std::vector& extension_ids) override; CefRefPtr GetExtension(const CefString& extension_id) override; - CefRefPtr GetMediaRouter() override; + CefRefPtr GetMediaRouter( + CefRefPtr callback) override; const CefRequestContextSettings& settings() const { return config_.settings; } @@ -133,29 +144,27 @@ class CefRequestContextImpl : public CefRequestContext { // Make sure the browser context exists. Only called on the UI thread. void EnsureBrowserContext(); - void GetBrowserContextOnUIThread( - scoped_refptr task_runner, - const BrowserContextCallback& callback); - - void PurgePluginListCacheInternal(bool reload_pages, - CefBrowserContext* browser_context); + void PurgePluginListCacheInternal( + bool reload_pages, + CefBrowserContext::Getter browser_context_getter); void ClearCertificateExceptionsInternal( CefRefPtr callback, - CefBrowserContext* browser_context); + CefBrowserContext::Getter browser_context_getter); void ClearHttpAuthCredentialsInternal( CefRefPtr callback, - CefBrowserContext* browser_context); - void CloseAllConnectionsInternal(CefRefPtr callback, - CefBrowserContext* browser_context); + CefBrowserContext::Getter browser_context_getter); + void CloseAllConnectionsInternal( + CefRefPtr callback, + CefBrowserContext::Getter browser_context_getter); void ResolveHostInternal(const CefString& origin, CefRefPtr callback, - CefBrowserContext* browser_context); + CefBrowserContext::Getter browser_context_getter); - void InitializeCookieManagerOnUIThread( + void InitializeCookieManagerInternal( CefRefPtr cookie_manager, CefRefPtr callback); - void InitializeMediaRouterOnUIThread( - CefRefPtr media_router); + void InitializeMediaRouterInternal(CefRefPtr media_router, + CefRefPtr callback); CefBrowserContext* browser_context() const; diff --git a/libcef/browser/views/browser_view_impl.cc b/libcef/browser/views/browser_view_impl.cc index 26dbfa47a..139dff2ad 100644 --- a/libcef/browser/views/browser_view_impl.cc +++ b/libcef/browser/views/browser_view_impl.cc @@ -8,6 +8,7 @@ #include "libcef/browser/browser_util.h" #include "libcef/browser/chrome/views/chrome_browser_view.h" #include "libcef/browser/context.h" +#include "libcef/browser/request_context_impl.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/views/window_impl.h" @@ -48,6 +49,18 @@ CefRefPtr CefBrowserViewImpl::Create( CefRefPtr delegate) { CEF_REQUIRE_UIT_RETURN(nullptr); + if (!request_context) { + request_context = CefRequestContext::GetGlobalContext(); + } + + // Verify that the browser context is valid. Do this here instead of risking + // potential browser creation failure when this view is added to the window. + auto request_context_impl = + static_cast(request_context.get()); + if (!request_context_impl->VerifyBrowserContext()) { + return nullptr; + } + CefRefPtr browser_view = new CefBrowserViewImpl(delegate); browser_view->SetPendingBrowserCreateParams(client, url, settings, extra_info, request_context); @@ -207,7 +220,7 @@ void CefBrowserViewImpl::SetPendingBrowserCreateParams( DCHECK(!pending_browser_create_params_); pending_browser_create_params_.reset(new CefBrowserCreateParams()); pending_browser_create_params_->client = client; - pending_browser_create_params_->url = GURL(url.ToString()); + pending_browser_create_params_->url = url; pending_browser_create_params_->settings = settings; pending_browser_create_params_->extra_info = extra_info; pending_browser_create_params_->request_context = request_context; diff --git a/libcef/common/net/url_util.cc b/libcef/common/net/url_util.cc new file mode 100644 index 000000000..0c45d174a --- /dev/null +++ b/libcef/common/net/url_util.cc @@ -0,0 +1,41 @@ +// Copyright (c) 2021 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/common/net/url_util.h" + +#include "base/logging.h" +#include "components/url_formatter/url_fixer.h" + +namespace url_util { + +GURL MakeGURL(const CefString& url, bool fixup) { + GURL gurl = GURL(url.ToString()); + if (!url.empty() && !gurl.is_valid() && !gurl.has_scheme()) { + std::string fixed_scheme(url::kHttpScheme); + fixed_scheme.append(url::kStandardSchemeSeparator); + std::string new_url = url; + new_url.insert(0, fixed_scheme); + gurl = GURL(new_url); + } + if (fixup) + FixupGURL(gurl); + return gurl; +} + +bool FixupGURL(GURL& gurl) { + if (!gurl.is_empty()) { + GURL fixup_url = + url_formatter::FixupURL(gurl.possibly_invalid_spec(), std::string()); + if (fixup_url.is_valid()) { + gurl = fixup_url; + } else { + LOG(ERROR) << "Invalid URL: " << gurl.possibly_invalid_spec(); + gurl = GURL(); + return false; + } + } + return true; +} + +} // namespace url_util diff --git a/libcef/common/net/url_util.h b/libcef/common/net/url_util.h new file mode 100644 index 000000000..d5c0112cc --- /dev/null +++ b/libcef/common/net/url_util.h @@ -0,0 +1,27 @@ +// Copyright (c) 2021 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. + +#ifndef CEF_LIBCEF_COMMON_NET_URL_UTIL_H_ +#define CEF_LIBCEF_COMMON_NET_URL_UTIL_H_ +#pragma once + +#include "include/cef_base.h" + +class GURL; + +namespace url_util { + +// Convert |url| to a GURL, adding a scheme prefix if necessary. +// If |fixup| is true then FixupGURL() will also be called. +GURL MakeGURL(const CefString& url, bool fixup); + +// Fix common problems with user-typed text. Among other things, this: +// - Converts absolute file paths to "file://" URLs. +// - Normalizes "about:" and "chrome:" to "chrome://" URLs +// Modifies |gurl| if necessary. Returns true if |gurl| is empty or valid. +bool FixupGURL(GURL& gurl); + +} // namespace url_util + +#endif // CEF_LIBCEF_COMMON_NET_URL_UTIL_H_ diff --git a/libcef_dll/cpptoc/media_router_cpptoc.cc b/libcef_dll/cpptoc/media_router_cpptoc.cc index dfa64c525..bacf732eb 100644 --- a/libcef_dll/cpptoc/media_router_cpptoc.cc +++ b/libcef_dll/cpptoc/media_router_cpptoc.cc @@ -9,26 +9,31 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=3deccadb24380ee63afe228ca2a91b90e96affca$ +// $hash=f60f51701b15100a8ad9463adfe0deb37c2d6b4f$ // #include "libcef_dll/cpptoc/media_router_cpptoc.h" #include "libcef_dll/cpptoc/media_sink_cpptoc.h" #include "libcef_dll/cpptoc/media_source_cpptoc.h" #include "libcef_dll/cpptoc/registration_cpptoc.h" +#include "libcef_dll/ctocpp/completion_callback_ctocpp.h" #include "libcef_dll/ctocpp/media_observer_ctocpp.h" #include "libcef_dll/ctocpp/media_route_create_callback_ctocpp.h" #include "libcef_dll/shutdown_checker.h" // GLOBAL FUNCTIONS - Body may be edited by hand. -CEF_EXPORT cef_media_router_t* cef_media_router_get_global() { +CEF_EXPORT cef_media_router_t* cef_media_router_get_global( + cef_completion_callback_t* callback) { shutdown_checker::AssertNotShutdown(); // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + // Unverified params: callback + // Execute - CefRefPtr _retval = CefMediaRouter::GetGlobalMediaRouter(); + CefRefPtr _retval = CefMediaRouter::GetGlobalMediaRouter( + CefCompletionCallbackCToCpp::Wrap(callback)); // Return type: refptr_same return CefMediaRouterCppToC::Wrap(_retval); diff --git a/libcef_dll/cpptoc/request_context_cpptoc.cc b/libcef_dll/cpptoc/request_context_cpptoc.cc index 95194705b..fd3d1af8b 100644 --- a/libcef_dll/cpptoc/request_context_cpptoc.cc +++ b/libcef_dll/cpptoc/request_context_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=3e91639f70988c2a48470e380c7317db5f27153e$ +// $hash=38ae668703b71d27d2bcd7cd9230817edd5b8f41$ // #include "libcef_dll/cpptoc/request_context_cpptoc.h" @@ -542,16 +542,19 @@ request_context_get_extension(struct _cef_request_context_t* self, } cef_media_router_t* CEF_CALLBACK -request_context_get_media_router(struct _cef_request_context_t* self) { +request_context_get_media_router(struct _cef_request_context_t* self, + cef_completion_callback_t* callback) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING DCHECK(self); if (!self) return NULL; + // Unverified params: callback // Execute CefRefPtr _retval = - CefRequestContextCppToC::Get(self)->GetMediaRouter(); + CefRequestContextCppToC::Get(self)->GetMediaRouter( + CefCompletionCallbackCToCpp::Wrap(callback)); // Return type: refptr_same return CefMediaRouterCppToC::Wrap(_retval); diff --git a/libcef_dll/ctocpp/media_router_ctocpp.cc b/libcef_dll/ctocpp/media_router_ctocpp.cc index 6085b8e81..51e76b58f 100644 --- a/libcef_dll/ctocpp/media_router_ctocpp.cc +++ b/libcef_dll/ctocpp/media_router_ctocpp.cc @@ -9,10 +9,11 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=ae6ec27ec52df5eb0db397c27b0df4969474dc0c$ +// $hash=8e7b2e3e8124ede620b8a04116656550949f89f1$ // #include "libcef_dll/ctocpp/media_router_ctocpp.h" +#include "libcef_dll/cpptoc/completion_callback_cpptoc.h" #include "libcef_dll/cpptoc/media_observer_cpptoc.h" #include "libcef_dll/cpptoc/media_route_create_callback_cpptoc.h" #include "libcef_dll/ctocpp/media_sink_ctocpp.h" @@ -23,13 +24,17 @@ // STATIC METHODS - Body may be edited by hand. NO_SANITIZE("cfi-icall") -CefRefPtr CefMediaRouter::GetGlobalMediaRouter() { +CefRefPtr CefMediaRouter::GetGlobalMediaRouter( + CefRefPtr callback) { shutdown_checker::AssertNotShutdown(); // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + // Unverified params: callback + // Execute - cef_media_router_t* _retval = cef_media_router_get_global(); + cef_media_router_t* _retval = + cef_media_router_get_global(CefCompletionCallbackCppToC::Wrap(callback)); // Return type: refptr_same return CefMediaRouterCToCpp::Wrap(_retval); diff --git a/libcef_dll/ctocpp/request_context_ctocpp.cc b/libcef_dll/ctocpp/request_context_ctocpp.cc index 8924e11cd..d358aed81 100644 --- a/libcef_dll/ctocpp/request_context_ctocpp.cc +++ b/libcef_dll/ctocpp/request_context_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=fde747bf60e627912a0f242a2475af69be80f298$ +// $hash=67bc021917c8f7d1e386859bbfae6e007b292f45$ // #include "libcef_dll/ctocpp/request_context_ctocpp.h" @@ -527,15 +527,19 @@ CefRefPtr CefRequestContextCToCpp::GetExtension( } NO_SANITIZE("cfi-icall") -CefRefPtr CefRequestContextCToCpp::GetMediaRouter() { +CefRefPtr CefRequestContextCToCpp::GetMediaRouter( + CefRefPtr callback) { cef_request_context_t* _struct = GetStruct(); if (CEF_MEMBER_MISSING(_struct, get_media_router)) return nullptr; // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + // Unverified params: callback + // Execute - cef_media_router_t* _retval = _struct->get_media_router(_struct); + cef_media_router_t* _retval = _struct->get_media_router( + _struct, CefCompletionCallbackCppToC::Wrap(callback)); // Return type: refptr_same return CefMediaRouterCToCpp::Wrap(_retval); diff --git a/libcef_dll/ctocpp/request_context_ctocpp.h b/libcef_dll/ctocpp/request_context_ctocpp.h index a755f3cd5..314110af2 100644 --- a/libcef_dll/ctocpp/request_context_ctocpp.h +++ b/libcef_dll/ctocpp/request_context_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=f54014218a54c7925d85df2f162fd51962dac2ce$ +// $hash=0aff81f2ccc5881001e9fd61cc6e349253fb2ac5$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_CTOCPP_H_ @@ -75,7 +75,8 @@ class CefRequestContextCToCpp bool HasExtension(const CefString& extension_id) OVERRIDE; bool GetExtensions(std::vector& extension_ids) OVERRIDE; CefRefPtr GetExtension(const CefString& extension_id) OVERRIDE; - CefRefPtr GetMediaRouter() OVERRIDE; + CefRefPtr GetMediaRouter( + CefRefPtr callback) OVERRIDE; }; #endif // CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_CTOCPP_H_ diff --git a/libcef_dll/wrapper/libcef_dll_dylib.cc b/libcef_dll/wrapper/libcef_dll_dylib.cc index 65d4494c9..67655ef1d 100644 --- a/libcef_dll/wrapper/libcef_dll_dylib.cc +++ b/libcef_dll/wrapper/libcef_dll_dylib.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=51090c9b8afc79ae98d70fe84c98bc7c8a433c3a$ +// $hash=9fbe1de9cf7f32c551c535e190d4c82b4947765d$ // #include @@ -203,7 +203,8 @@ typedef struct _cef_cookie_manager_t* ( struct _cef_completion_callback_t*); typedef struct _cef_drag_data_t* (*cef_drag_data_create_ptr)(); typedef struct _cef_image_t* (*cef_image_create_ptr)(); -typedef struct _cef_media_router_t* (*cef_media_router_get_global_ptr)(); +typedef struct _cef_media_router_t* (*cef_media_router_get_global_ptr)( + struct _cef_completion_callback_t*); typedef struct _cef_menu_model_t* (*cef_menu_model_create_ptr)( struct _cef_menu_model_delegate_t*); typedef struct _cef_print_settings_t* (*cef_print_settings_create_ptr)(); @@ -1093,8 +1094,8 @@ int cef_create_url(const struct _cef_urlparts_t* parts, cef_string_t* url) { } NO_SANITIZE("cfi-icall") -cef_string_userfree_t - cef_format_url_for_security_display(const cef_string_t* origin_url) { +cef_string_userfree_t cef_format_url_for_security_display( + const cef_string_t* origin_url) { return g_libcef_pointers.cef_format_url_for_security_display(origin_url); } @@ -1315,8 +1316,9 @@ NO_SANITIZE("cfi-icall") struct _cef_image_t* cef_image_create() { } NO_SANITIZE("cfi-icall") -struct _cef_media_router_t* cef_media_router_get_global() { - return g_libcef_pointers.cef_media_router_get_global(); +struct _cef_media_router_t* cef_media_router_get_global( + struct _cef_completion_callback_t* callback) { + return g_libcef_pointers.cef_media_router_get_global(callback); } NO_SANITIZE("cfi-icall") @@ -1579,54 +1581,46 @@ struct _cef_translator_test_t* cef_translator_test_create() { } NO_SANITIZE("cfi-icall") -struct - _cef_translator_test_ref_ptr_library_t* cef_translator_test_ref_ptr_library_create( - int value) { +struct _cef_translator_test_ref_ptr_library_t* +cef_translator_test_ref_ptr_library_create(int value) { return g_libcef_pointers.cef_translator_test_ref_ptr_library_create(value); } NO_SANITIZE("cfi-icall") -struct - _cef_translator_test_ref_ptr_library_child_t* cef_translator_test_ref_ptr_library_child_create( - int value, - int other_value) { +struct _cef_translator_test_ref_ptr_library_child_t* +cef_translator_test_ref_ptr_library_child_create(int value, int other_value) { return g_libcef_pointers.cef_translator_test_ref_ptr_library_child_create( value, other_value); } NO_SANITIZE("cfi-icall") -struct - _cef_translator_test_ref_ptr_library_child_child_t* cef_translator_test_ref_ptr_library_child_child_create( - int value, - int other_value, - int other_other_value) { +struct _cef_translator_test_ref_ptr_library_child_child_t* +cef_translator_test_ref_ptr_library_child_child_create(int value, + int other_value, + int other_other_value) { return g_libcef_pointers .cef_translator_test_ref_ptr_library_child_child_create( value, other_value, other_other_value); } NO_SANITIZE("cfi-icall") -struct - _cef_translator_test_scoped_library_t* cef_translator_test_scoped_library_create( - int value) { +struct _cef_translator_test_scoped_library_t* +cef_translator_test_scoped_library_create(int value) { return g_libcef_pointers.cef_translator_test_scoped_library_create(value); } NO_SANITIZE("cfi-icall") -struct - _cef_translator_test_scoped_library_child_t* cef_translator_test_scoped_library_child_create( - int value, - int other_value) { +struct _cef_translator_test_scoped_library_child_t* +cef_translator_test_scoped_library_child_create(int value, int other_value) { return g_libcef_pointers.cef_translator_test_scoped_library_child_create( value, other_value); } NO_SANITIZE("cfi-icall") -struct - _cef_translator_test_scoped_library_child_child_t* cef_translator_test_scoped_library_child_child_create( - int value, - int other_value, - int other_other_value) { +struct _cef_translator_test_scoped_library_child_child_t* +cef_translator_test_scoped_library_child_child_create(int value, + int other_value, + int other_other_value) { return g_libcef_pointers .cef_translator_test_scoped_library_child_child_create(value, other_value, other_other_value); diff --git a/tests/cefclient/browser/media_router_test.cc b/tests/cefclient/browser/media_router_test.cc index ddc1354c6..4fec578ba 100644 --- a/tests/cefclient/browser/media_router_test.cc +++ b/tests/cefclient/browser/media_router_test.cc @@ -543,7 +543,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler { } CefRefPtr media_router = - browser->GetHost()->GetRequestContext()->GetMediaRouter(); + browser->GetHost()->GetRequestContext()->GetMediaRouter(nullptr); SubscriptionState* state = new SubscriptionState(); state->query_id = query_id; diff --git a/tests/ceftests/preference_unittest.cc b/tests/ceftests/preference_unittest.cc index f687f31dd..737e45f94 100644 --- a/tests/ceftests/preference_unittest.cc +++ b/tests/ceftests/preference_unittest.cc @@ -398,6 +398,19 @@ void ValidateGet(CefRefPtr context, class TestRequestContextHandler : public CefRequestContextHandler { public: TestRequestContextHandler() {} + explicit TestRequestContextHandler(CefRefPtr event) + : event_(event) {} + + void OnRequestContextInitialized( + CefRefPtr context) override { + if (event_) { + event_->Signal(); + event_ = nullptr; + } + } + + private: + CefRefPtr event_; IMPLEMENT_REFCOUNTING(TestRequestContextHandler); }; @@ -452,9 +465,11 @@ TEST(PreferenceTest, GlobalSetGetShared) { // Unassociated context. CefRequestContextSettings settings; - CefRefPtr context4 = - CefRequestContext::CreateContext(settings, nullptr); + CefRefPtr context4 = CefRequestContext::CreateContext( + settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context4.get()); + // Wait for the context to be fully initialized. + event->Wait(); // Set/get the values on the first context. *PendingAction() = "Set/get the values on the first context"; @@ -495,9 +510,11 @@ TEST(PreferenceTest, CustomDefaults) { CefWaitableEvent::CreateWaitableEvent(true, false); CefRequestContextSettings settings; - CefRefPtr context = - CefRequestContext::CreateContext(settings, nullptr); + CefRefPtr context = CefRequestContext::CreateContext( + settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context.get()); + // Wait for the context to be fully initialized. + event->Wait(); ValidateDefaults(context, false, event); event->Wait(); @@ -509,9 +526,11 @@ TEST(PreferenceTest, CustomSetGet) { CefWaitableEvent::CreateWaitableEvent(true, false); CefRequestContextSettings settings; - CefRefPtr context = - CefRequestContext::CreateContext(settings, nullptr); + CefRefPtr context = CefRequestContext::CreateContext( + settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context.get()); + // Wait for the context to be fully initialized. + event->Wait(); ValidateSetGet(context, event); event->Wait(); @@ -527,9 +546,11 @@ TEST(PreferenceTest, CustomSetGetShared) { CefWaitableEvent::CreateWaitableEvent(true, false); CefRequestContextSettings settings; - CefRefPtr context = - CefRequestContext::CreateContext(settings, nullptr); + CefRefPtr context = CefRequestContext::CreateContext( + settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context.get()); + // Wait for the context to be fully initialized. + event->Wait(); // Sharing storage. CefRefPtr context2 = @@ -542,9 +563,11 @@ TEST(PreferenceTest, CustomSetGetShared) { EXPECT_TRUE(context3.get()); // Unassociated context. - CefRefPtr context4 = - CefRequestContext::CreateContext(settings, nullptr); + CefRefPtr context4 = CefRequestContext::CreateContext( + settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context4.get()); + // Wait for the context to be fully initialized. + event->Wait(); // Set/get the values on the first context. *PendingAction() = "Set/get the values on the first context";