diff --git a/BUILD.gn b/BUILD.gn index 6275a1c2d..d258a62b4 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -946,6 +946,7 @@ template("cef_pak_scaled") { repack("pak_${target_name}") { # Each input pak file should also have a deps line for completeness. + # Add associated .h files in the make_pack_header("resources") target. sources = [ "$root_gen_dir/blink/public/resources/blink_image_resources_${percent}_percent.pak", "$root_gen_dir/chrome/renderer_resources_${percent}_percent.pak", @@ -993,6 +994,8 @@ cef_pak_scaled("200_percent") { # Generate devtools_resources.pak. repack("pak_devtools") { + # Each input pak file should also have a deps line for completeness. + # Add associated .h files in the make_pack_header("resources") target. sources = [ "$root_gen_dir/blink/devtools_resources.pak", ] @@ -1010,6 +1013,7 @@ repack("pak_devtools") { # Generate cef_extensions.pak. repack("pak_extensions") { # Each input pak file should also have a deps line for completeness. + # Add associated .h files in the make_pack_header("resources") target. sources = [ "$root_gen_dir/chrome/component_extension_resources.pak", "$root_gen_dir/extensions/extensions_renderer_resources.pak", @@ -1069,12 +1073,15 @@ grit("cef_resources") { # Generate cef.pak. repack("pak") { # Each input pak file should also have a deps line for completeness. + # Add associated .h files in the make_pack_header("resources") target. sources = [ "$root_gen_dir/blink/public/resources/blink_resources.pak", "$root_gen_dir/chrome/browser_resources.pak", + "$root_gen_dir/chrome/net_internals_resources.pak", "$root_gen_dir/chrome/common_resources.pak", "$root_gen_dir/components/components_resources.pak", "$root_gen_dir/cef/cef_resources.pak", + "$root_gen_dir/content/browser/tracing/tracing_resources.pak", "$root_gen_dir/content/content_resources.pak", "$root_gen_dir/net/net_resources.pak", ] @@ -1085,9 +1092,11 @@ repack("pak") { public_deps = [ "//third_party/WebKit/public:resources_grit", "//chrome/browser:resources", + "//chrome/browser/resources:net_internals_resources", "//chrome/common:resources", "//components/resources:components_resources", ":cef_resources", + "//content/browser/tracing:resources", "//content:resources", "//net:net_resources", ] @@ -1127,11 +1136,16 @@ make_pack_header("resources") { header = "$root_out_dir/includes/include/cef_pack_resources.h" inputs = [ "$root_gen_dir/blink/grit/devtools_resources.h", + "$root_gen_dir/blink/public/resources/grit/blink_image_resources.h", "$root_gen_dir/blink/public/resources/grit/blink_resources.h", "$root_gen_dir/cef/grit/cef_resources.h", "$root_gen_dir/chrome/grit/browser_resources.h", "$root_gen_dir/chrome/grit/common_resources.h", "$root_gen_dir/chrome/grit/component_extension_resources.h", + "$root_gen_dir/chrome/grit/net_internals_resources.h", + "$root_gen_dir/chrome/grit/renderer_resources.h", + "$root_gen_dir/components/grit/components_resources.h", + "$root_gen_dir/content/browser/tracing/grit/tracing_resources.h", "$root_gen_dir/content/grit/content_resources.h", "$root_gen_dir/extensions/grit/extensions_browser_resources.h", "$root_gen_dir/extensions/grit/extensions_renderer_resources.h", @@ -1148,6 +1162,7 @@ make_pack_header("strings") { header = "$root_out_dir/includes/include/cef_pack_strings.h" inputs = [ "$root_gen_dir/cef/grit/cef_strings.h", + "$root_gen_dir/chrome/grit/chromium_strings.h", "$root_gen_dir/chrome/grit/generated_resources.h", "$root_gen_dir/chrome/grit/locale_settings.h", "$root_gen_dir/chrome/grit/platform_locale_settings.h", @@ -1396,6 +1411,7 @@ cef_unittests_sources = [ "tests/unittests/v8_unittest.cc", "tests/unittests/values_unittest.cc", "tests/unittests/version_unittest.cc", + "tests/unittests/webui_unittest.cc", "tests/unittests/xml_reader_unittest.cc", "tests/unittests/zip_reader_unittest.cc", ] diff --git a/cef_repack_locales.gni b/cef_repack_locales.gni index 42c15c2b6..38cb66980 100644 --- a/cef_repack_locales.gni +++ b/cef_repack_locales.gni @@ -27,8 +27,10 @@ template("_repack_one_locale") { visibility = invoker.visibility # Each input pak file should also have a deps line for completeness. + # Add associated .h files in the make_pack_header("strings") target. sources = [ "${root_gen_dir}/cef/cef_strings_${locale}.pak", + "${root_gen_dir}/chrome/chromium_strings_${locale}.pak", "${root_gen_dir}/chrome/generated_resources_${locale}.pak", "${root_gen_dir}/chrome/locale_settings_${locale}.pak", "${root_gen_dir}/chrome/platform_locale_settings_${locale}.pak", @@ -45,6 +47,7 @@ template("_repack_one_locale") { # listed both here and in the libcef_static target. public_deps = [ ":cef_strings", + "//chrome/app:chromium_strings", "//chrome/app:generated_resources", "//chrome/app/resources:locale_settings", "//chrome/app/resources:platform_locale_settings", diff --git a/libcef/browser/browser_context_proxy.cc b/libcef/browser/browser_context_proxy.cc index 1dae886c5..8d9186ef7 100644 --- a/libcef/browser/browser_context_proxy.cc +++ b/libcef/browser/browser_context_proxy.cc @@ -17,6 +17,7 @@ #include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/resource_context_impl.h" #include "content/browser/streams/stream_context.h" +#include "content/browser/webui/url_data_manager.h" #include "content/public/browser/storage_partition.h" namespace { @@ -47,6 +48,10 @@ bool ShouldProxyUserData(const void* key) { if (key == kFontFamilyCacheKey) return true; + // If this value is not proxied WebUI will fail to load. + if (key == content::URLDataManager::GetUserDataKey()) + return true; + return false; } @@ -69,6 +74,14 @@ CefBrowserContextProxy::~CefBrowserContextProxy() { parent_->RemoveProxy(this); } +void CefBrowserContextProxy::Initialize() { + CefBrowserContext::Initialize(); + + // This object's CefResourceContext needs to proxy some UserData requests to + // the parent object's CefResourceContext. + resource_context()->set_parent(parent_->resource_context()); +} + base::SupportsUserData::Data* CefBrowserContextProxy::GetUserData(const void* key) const { if (ShouldProxyUserData(key)) diff --git a/libcef/browser/browser_context_proxy.h b/libcef/browser/browser_context_proxy.h index f2d396089..969b820ef 100644 --- a/libcef/browser/browser_context_proxy.h +++ b/libcef/browser/browser_context_proxy.h @@ -23,6 +23,9 @@ class CefBrowserContextProxy : public CefBrowserContext { CefBrowserContextProxy(CefRefPtr handler, scoped_refptr parent); + // Must be called immediately after this object is created. + void Initialize() override; + // SupportsUserData methods. Data* GetUserData(const void* key) const override; void SetUserData(const void* key, Data* data) override; diff --git a/libcef/browser/browser_main.cc b/libcef/browser/browser_main.cc index 694d6d3b7..aa02f8cf8 100644 --- a/libcef/browser/browser_main.cc +++ b/libcef/browser/browser_main.cc @@ -17,6 +17,7 @@ #include "libcef/browser/extensions/browser_context_keyed_service_factories.h" #include "libcef/browser/extensions/extensions_browser_client.h" #include "libcef/browser/extensions/extension_system_factory.h" +#include "libcef/browser/net/chrome_scheme_handler.h" #include "libcef/browser/thread_util.h" #include "libcef/common/extensions/extensions_client.h" #include "libcef/common/extensions/extensions_util.h" @@ -27,10 +28,8 @@ #include "base/message_loop/message_loop.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/plugins/plugin_finder.h" -#include "content/browser/webui/content_web_ui_controller_factory.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/gpu_data_manager.h" -#include "content/public/browser/web_ui_controller_factory.h" #include "content/public/common/content_switches.h" #include "device/geolocation/access_token_store.h" #include "device/geolocation/geolocation_delegate.h" @@ -141,11 +140,6 @@ void CefBrowserMainParts::ToolkitInitialized() { } void CefBrowserMainParts::PostMainMessageLoopStart() { - // Don't use the default WebUI controller factory because is conflicts with - // CEF's internal handling of "chrome://tracing". - content::WebUIControllerFactory::UnregisterFactoryForTesting( - content::ContentWebUIControllerFactory::GetInstance()); - #if defined(OS_LINUX) printing::PrintingContextLinux::SetCreatePrintDialogFunction( &CefPrintDialogLinux::CreatePrintDialog); @@ -202,6 +196,8 @@ void CefBrowserMainParts::PreMainMessageLoopRun() { device::GeolocationProvider::SetGeolocationDelegate( new CefGeolocationDelegate( global_browser_context_->request_context().get())); + + scheme::RegisterWebUIControllerFactory(); } void CefBrowserMainParts::PostMainMessageLoopRun() { diff --git a/libcef/browser/chrome_browser_process_stub.cc b/libcef/browser/chrome_browser_process_stub.cc index e8bd29a9c..4a76b82e1 100644 --- a/libcef/browser/chrome_browser_process_stub.cc +++ b/libcef/browser/chrome_browser_process_stub.cc @@ -11,25 +11,46 @@ #include "libcef/common/cef_switches.h" #include "base/command_line.h" +#include "chrome/browser/net/chrome_net_log_helper.h" #include "chrome/browser/printing/print_job_manager.h" +#include "components/net_log/chrome_net_log.h" +#include "content/public/common/content_switches.h" #include "ui/message_center/message_center.h" ChromeBrowserProcessStub::ChromeBrowserProcessStub() : initialized_(false), + context_initialized_(false), shutdown_(false), locale_("en-US") { chrome::SetBrowserContextIncognitoHelper(this); } ChromeBrowserProcessStub::~ChromeBrowserProcessStub() { - DCHECK(!initialized_ || shutdown_); + DCHECK((!initialized_ && !context_initialized_) || shutdown_); g_browser_process = NULL; chrome::SetBrowserContextIncognitoHelper(nullptr); } -void ChromeBrowserProcessStub::Initialize() { - CEF_REQUIRE_UIT(); +void ChromeBrowserProcessStub::Initialize( + const base::CommandLine& command_line) { DCHECK(!initialized_); + DCHECK(!context_initialized_); + DCHECK(!shutdown_); + + base::FilePath net_log_path; + if (command_line.HasSwitch(switches::kLogNetLog)) + net_log_path = command_line.GetSwitchValuePath(switches::kLogNetLog); + net_log_.reset(new net_log::ChromeNetLog( + net_log_path, GetNetCaptureModeFromCommandLine(command_line), + command_line.GetCommandLineString(), std::string())); + + initialized_ = true; +} + +void ChromeBrowserProcessStub::OnContextInitialized() { + CEF_REQUIRE_UIT(); + DCHECK(initialized_); + DCHECK(!context_initialized_); DCHECK(!shutdown_); // Must be created after the NotificationService. @@ -37,12 +58,13 @@ void ChromeBrowserProcessStub::Initialize() { profile_manager_.reset(new ChromeProfileManagerStub()); event_router_forwarder_ = new extensions::EventRouterForwarder(); - initialized_ = true; + context_initialized_ = true; } void ChromeBrowserProcessStub::Shutdown() { CEF_REQUIRE_UIT(); DCHECK(initialized_); + DCHECK(context_initialized_); DCHECK(!shutdown_); // Wait for the pending print jobs to finish. Don't do this later, since @@ -58,146 +80,149 @@ void ChromeBrowserProcessStub::Shutdown() { } void ChromeBrowserProcessStub::ResourceDispatcherHostCreated() { - NOTIMPLEMENTED(); + NOTREACHED(); }; void ChromeBrowserProcessStub::EndSession() { - NOTIMPLEMENTED(); + NOTREACHED(); }; metrics_services_manager::MetricsServicesManager* ChromeBrowserProcessStub::GetMetricsServicesManager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } metrics::MetricsService* ChromeBrowserProcessStub::metrics_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } rappor::RapporService* ChromeBrowserProcessStub::rappor_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } IOThread* ChromeBrowserProcessStub::io_thread() { - NOTIMPLEMENTED(); return NULL; } WatchDogThread* ChromeBrowserProcessStub::watchdog_thread() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } ProfileManager* ChromeBrowserProcessStub::profile_manager() { + DCHECK(context_initialized_); return profile_manager_.get(); } PrefService* ChromeBrowserProcessStub::local_state() { - NOTIMPLEMENTED(); - return NULL; + DCHECK(context_initialized_); + return profile_manager_->GetLastUsedProfile( + profile_manager_->user_data_dir())->GetPrefs(); } net::URLRequestContextGetter* ChromeBrowserProcessStub::system_request_context() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } variations::VariationsService* ChromeBrowserProcessStub::variations_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } BrowserProcessPlatformPart* ChromeBrowserProcessStub::platform_part() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } extensions::EventRouterForwarder* ChromeBrowserProcessStub::extension_event_router_forwarder() { + DCHECK(context_initialized_); return event_router_forwarder_.get(); } NotificationUIManager* ChromeBrowserProcessStub::notification_ui_manager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } NotificationPlatformBridge* ChromeBrowserProcessStub::notification_platform_bridge() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } message_center::MessageCenter* ChromeBrowserProcessStub::message_center() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } policy::BrowserPolicyConnector* ChromeBrowserProcessStub::browser_policy_connector() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } policy::PolicyService* ChromeBrowserProcessStub::policy_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } IconManager* ChromeBrowserProcessStub::icon_manager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } GpuModeManager* ChromeBrowserProcessStub::gpu_mode_manager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } GpuProfileCache* ChromeBrowserProcessStub::gpu_profile_cache() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } void ChromeBrowserProcessStub::CreateDevToolsHttpProtocolHandler( const std::string& ip, uint16_t port) { - NOTIMPLEMENTED(); + NOTREACHED(); } void ChromeBrowserProcessStub::CreateDevToolsAutoOpener() { - NOTIMPLEMENTED(); + NOTREACHED(); } bool ChromeBrowserProcessStub::IsShuttingDown() { - NOTIMPLEMENTED(); + NOTREACHED(); return false; } printing::PrintJobManager* ChromeBrowserProcessStub::print_job_manager() { + DCHECK(context_initialized_); return print_job_manager_.get(); } printing::PrintPreviewDialogController* ChromeBrowserProcessStub::print_preview_dialog_controller() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } printing::BackgroundPrintingManager* ChromeBrowserProcessStub::background_printing_manager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } IntranetRedirectDetector* ChromeBrowserProcessStub::intranet_redirect_detector() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } @@ -211,45 +236,45 @@ void ChromeBrowserProcessStub::SetApplicationLocale(const std::string& locale) { } DownloadStatusUpdater* ChromeBrowserProcessStub::download_status_updater() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } DownloadRequestLimiter* ChromeBrowserProcessStub::download_request_limiter() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } BackgroundModeManager* ChromeBrowserProcessStub::background_mode_manager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } void ChromeBrowserProcessStub::set_background_mode_manager_for_test( std::unique_ptr manager) { - NOTIMPLEMENTED(); + NOTREACHED(); } StatusTray* ChromeBrowserProcessStub::status_tray() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } safe_browsing::SafeBrowsingService* ChromeBrowserProcessStub::safe_browsing_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } safe_browsing::ClientSideDetectionService* ChromeBrowserProcessStub::safe_browsing_detection_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } subresource_filter::RulesetService* ChromeBrowserProcessStub::subresource_filter_ruleset_service() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } @@ -259,75 +284,75 @@ void ChromeBrowserProcessStub::StartAutoupdateTimer() { #endif net_log::ChromeNetLog* ChromeBrowserProcessStub::net_log() { - NOTIMPLEMENTED(); - return NULL; + DCHECK(initialized_); + return net_log_.get(); } component_updater::ComponentUpdateService* ChromeBrowserProcessStub::component_updater() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } CRLSetFetcher* ChromeBrowserProcessStub::crl_set_fetcher() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } component_updater::PnaclComponentInstaller* ChromeBrowserProcessStub::pnacl_component_installer() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } component_updater::SupervisedUserWhitelistInstaller* ChromeBrowserProcessStub::supervised_user_whitelist_installer() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } MediaFileSystemRegistry* ChromeBrowserProcessStub::media_file_system_registry() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } bool ChromeBrowserProcessStub::created_local_state() const { - NOTIMPLEMENTED(); + NOTREACHED(); return false; } #if defined(ENABLE_WEBRTC) WebRtcLogUploader* ChromeBrowserProcessStub::webrtc_log_uploader() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } #endif network_time::NetworkTimeTracker* ChromeBrowserProcessStub::network_time_tracker() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } gcm::GCMDriver* ChromeBrowserProcessStub::gcm_driver() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } shell_integration::DefaultWebClientState ChromeBrowserProcessStub::CachedDefaultWebClientState() { - NOTIMPLEMENTED(); + NOTREACHED(); return shell_integration::UNKNOWN_DEFAULT; } memory::TabManager* ChromeBrowserProcessStub::GetTabManager() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } PhysicalWebDataSource* ChromeBrowserProcessStub::GetPhysicalWebDataSource() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } diff --git a/libcef/browser/chrome_browser_process_stub.h b/libcef/browser/chrome_browser_process_stub.h index 360bb7f18..0376430af 100644 --- a/libcef/browser/chrome_browser_process_stub.h +++ b/libcef/browser/chrome_browser_process_stub.h @@ -33,7 +33,8 @@ class ChromeBrowserProcessStub : public BrowserProcess, ChromeBrowserProcessStub(); ~ChromeBrowserProcessStub() override; - void Initialize(); + void Initialize(const base::CommandLine& command_line); + void OnContextInitialized(); void Shutdown(); // BrowserProcess implementation. @@ -117,12 +118,14 @@ class ChromeBrowserProcessStub : public BrowserProcess, private: bool initialized_; + bool context_initialized_; bool shutdown_; std::string locale_; std::unique_ptr print_job_manager_; std::unique_ptr profile_manager_; scoped_refptr event_router_forwarder_; + std::unique_ptr net_log_; DISALLOW_COPY_AND_ASSIGN(ChromeBrowserProcessStub); }; diff --git a/libcef/browser/chrome_profile_manager_stub.cc b/libcef/browser/chrome_profile_manager_stub.cc index e71a34f92..4ccdcb315 100644 --- a/libcef/browser/chrome_profile_manager_stub.cc +++ b/libcef/browser/chrome_profile_manager_stub.cc @@ -6,6 +6,25 @@ #include "libcef/browser/chrome_profile_manager_stub.h" #include "libcef/browser/browser_context_impl.h" +#include "libcef/browser/content_browser_client.h" + +namespace { + +// Return the active browser context. This is primarily called from Chrome code +// that handles WebUI views and wishes to associate the view's data with a +// particular context (profile). Chrome stores multiple profiles in sub- +// directories of |user_data_dir| and then uses ProfileManager to track which +// profile (sub-directory name) was last active. +// +// TODO(cef): To most closely match Chrome behavior this should return the +// context for the currently active browser (e.g. the browser with input focus). +// Return the main context for now since we don't currently have a good way to +// determine that. +CefBrowserContextImpl* GetActiveBrowserContext() { + return CefContentBrowserClient::Get()->browser_context().get(); +} + +} // namespace ChromeProfileManagerStub::ChromeProfileManagerStub() : ProfileManager(base::FilePath()) { @@ -18,7 +37,15 @@ Profile* ChromeProfileManagerStub::GetProfile( const base::FilePath& profile_dir) { scoped_refptr browser_context = CefBrowserContextImpl::GetForCachePath(profile_dir); - DCHECK(browser_context); + if (!browser_context) { + // ProfileManager makes assumptions about profile directory paths that do + // not match CEF usage. For example, the default Chrome profile name is + // "Default" so it will append that sub-directory name to an empty + // |user_data_dir| value and then call this method. Use the active context + // in cases such as this where we don't understand what ProfileManager is + // asking for. + browser_context = GetActiveBrowserContext(); + } return browser_context.get(); } @@ -29,3 +56,10 @@ bool ChromeProfileManagerStub::IsValidProfile(const void* profile) { reinterpret_cast( const_cast(profile))).get(); } + +Profile* ChromeProfileManagerStub::GetLastUsedProfile( + const base::FilePath& user_data_dir) { + // Override this method to avoid having to register prefs::kProfileLastUsed, + // usage of which doesn't make sense for CEF. + return GetActiveBrowserContext(); +} diff --git a/libcef/browser/chrome_profile_manager_stub.h b/libcef/browser/chrome_profile_manager_stub.h index 1c8639517..549ff75fb 100644 --- a/libcef/browser/chrome_profile_manager_stub.h +++ b/libcef/browser/chrome_profile_manager_stub.h @@ -18,6 +18,7 @@ class ChromeProfileManagerStub : public ProfileManager { Profile* GetProfile(const base::FilePath& profile_dir) override; bool IsValidProfile(const void* profile) override; + Profile* GetLastUsedProfile(const base::FilePath& user_data_dir) override; private: DISALLOW_COPY_AND_ASSIGN(ChromeProfileManagerStub); diff --git a/libcef/browser/chrome_profile_stub.cc b/libcef/browser/chrome_profile_stub.cc index b632ca37e..26c9e0bca 100644 --- a/libcef/browser/chrome_profile_stub.cc +++ b/libcef/browser/chrome_profile_stub.cc @@ -5,38 +5,38 @@ #include "libcef/browser/chrome_profile_stub.h" -ChromeProfileStub::ChromeProfileStub(){ +ChromeProfileStub::ChromeProfileStub() { } ChromeProfileStub::~ChromeProfileStub() { } scoped_refptr ChromeProfileStub::GetIOTaskRunner() { - NOTIMPLEMENTED(); + NOTREACHED(); return scoped_refptr(); } std::string ChromeProfileStub::GetProfileUserName() const { - NOTIMPLEMENTED(); + NOTREACHED(); return std::string(); } Profile::ProfileType ChromeProfileStub::GetProfileType() const { - NOTIMPLEMENTED(); + NOTREACHED(); return REGULAR_PROFILE; } Profile* ChromeProfileStub::GetOffTheRecordProfile() { - NOTIMPLEMENTED(); + NOTREACHED(); return NULL; } void ChromeProfileStub::DestroyOffTheRecordProfile() { - NOTIMPLEMENTED(); + NOTREACHED(); } bool ChromeProfileStub::HasOffTheRecordProfile() { - NOTIMPLEMENTED(); + NOTREACHED(); return false; } @@ -44,100 +44,100 @@ Profile* ChromeProfileStub::GetOriginalProfile() { return this; } -bool ChromeProfileStub::IsSupervised() const { +bool ChromeProfileStub::IsSupervised() const { return false; } -bool ChromeProfileStub::IsChild() const { - NOTIMPLEMENTED(); +bool ChromeProfileStub::IsChild() const { return false; } -bool ChromeProfileStub::IsLegacySupervised() const { - NOTIMPLEMENTED(); +bool ChromeProfileStub::IsLegacySupervised() const { + NOTREACHED(); return false; } ExtensionSpecialStoragePolicy* - ChromeProfileStub::GetExtensionSpecialStoragePolicy() { - NOTIMPLEMENTED(); + ChromeProfileStub::GetExtensionSpecialStoragePolicy() { + NOTREACHED(); return NULL; } -PrefService* ChromeProfileStub::GetOffTheRecordPrefs() { - NOTIMPLEMENTED(); +PrefService* ChromeProfileStub::GetOffTheRecordPrefs() { + NOTREACHED(); return NULL; } net::URLRequestContextGetter* - ChromeProfileStub::GetRequestContextForExtensions() { - NOTIMPLEMENTED(); + ChromeProfileStub::GetRequestContextForExtensions() { + // TODO(cef): Consider creating a separate context for extensions to match + // Chrome behavior. + return GetRequestContext(); +} + +net::SSLConfigService* ChromeProfileStub::GetSSLConfigService() { + NOTREACHED(); return NULL; } -net::SSLConfigService* ChromeProfileStub::GetSSLConfigService() { - NOTIMPLEMENTED(); - return NULL; -} - -bool ChromeProfileStub::IsSameProfile(Profile* profile) { - NOTIMPLEMENTED(); +bool ChromeProfileStub::IsSameProfile(Profile* profile) { + NOTREACHED(); return false; } -base::Time ChromeProfileStub::GetStartTime() const { - NOTIMPLEMENTED(); +base::Time ChromeProfileStub::GetStartTime() const { + NOTREACHED(); return base::Time(); } -base::FilePath ChromeProfileStub::last_selected_directory() { - NOTIMPLEMENTED(); +base::FilePath ChromeProfileStub::last_selected_directory() { + NOTREACHED(); return base::FilePath(); } void ChromeProfileStub::set_last_selected_directory( - const base::FilePath& path) { - NOTIMPLEMENTED(); + const base::FilePath& path) { + NOTREACHED(); } -PrefProxyConfigTracker* ChromeProfileStub::GetProxyConfigTracker() { - NOTIMPLEMENTED(); +PrefProxyConfigTracker* ChromeProfileStub::GetProxyConfigTracker() { + NOTREACHED(); return NULL; } -chrome_browser_net::Predictor* ChromeProfileStub::GetNetworkPredictor() { - NOTIMPLEMENTED(); +chrome_browser_net::Predictor* ChromeProfileStub::GetNetworkPredictor() { + NOTREACHED(); return NULL; } DevToolsNetworkControllerHandle* - ChromeProfileStub::GetDevToolsNetworkControllerHandle() { - NOTIMPLEMENTED(); + ChromeProfileStub::GetDevToolsNetworkControllerHandle() { + NOTREACHED(); return NULL; } void ChromeProfileStub::ClearNetworkingHistorySince( base::Time time, - const base::Closure& completion) { - NOTIMPLEMENTED(); + const base::Closure& completion) { + NOTREACHED(); } -GURL ChromeProfileStub::GetHomePage() { - NOTIMPLEMENTED(); +GURL ChromeProfileStub::GetHomePage() { + NOTREACHED(); return GURL(); } bool ChromeProfileStub::WasCreatedByVersionOrLater( - const std::string& version) { - NOTIMPLEMENTED(); + const std::string& version) { + NOTREACHED(); return false; } void ChromeProfileStub::SetExitType(ExitType exit_type) { - NOTIMPLEMENTED(); + NOTREACHED(); } Profile::ExitType ChromeProfileStub::GetLastSessionExitType() { - NOTIMPLEMENTED(); + NOTREACHED(); return EXIT_NORMAL; } diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index 1e729fe82..ed09d54cd 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -48,7 +48,6 @@ #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/plugin_service_impl.h" #include "content/public/browser/browser_ppapi_host.h" -#include "content/public/browser/browser_url_handler.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/navigation_handle.h" @@ -848,9 +847,7 @@ void CefContentBrowserClient::OverrideWebkitPrefs( void CefContentBrowserClient::BrowserURLHandlerCreated( content::BrowserURLHandler* handler) { - // Used to redirect about: URLs to chrome: URLs. - handler->AddHandlerPair(&scheme::WillHandleBrowserAboutURL, - content::BrowserURLHandler::null_handler()); + scheme::BrowserURLHandlerCreated(handler); } std::string CefContentBrowserClient::GetDefaultDownloadName() { diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index 101ba7161..d8930b57b 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -307,6 +307,9 @@ bool CefContext::Initialize(const CefMainArgs& args, if (exit_code >= 0) return false; + static_cast(g_browser_process)->Initialize( + *base::CommandLine::ForCurrentProcess()); + // Run the process. Results in a call to CefMainDelegate::RunProcess() which // will create the browser runner and message loop without blocking. exit_code = main_runner_->Run(); @@ -389,7 +392,8 @@ void CefContext::PopulateRequestContextSettings( void CefContext::OnContextInitialized() { CEF_REQUIRE_UIT(); - static_cast(g_browser_process)->Initialize(); + static_cast(g_browser_process)-> + OnContextInitialized(); #if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) CefWidevineLoader::GetInstance()->OnContextInitialized(); diff --git a/libcef/browser/net/chrome_scheme_handler.cc b/libcef/browser/net/chrome_scheme_handler.cc index 8f7ece21b..a7f744577 100644 --- a/libcef/browser/net/chrome_scheme_handler.cc +++ b/libcef/browser/net/chrome_scheme_handler.cc @@ -5,6 +5,7 @@ #include "libcef/browser/net/chrome_scheme_handler.h" +#include #include #include #include @@ -19,6 +20,7 @@ #include "base/command_line.h" #include "base/files/file_util.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/path_service.h" @@ -27,16 +29,15 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "cef/grit/cef_resources.h" -#include "components/grit/components_resources.h" -#include "content/browser/net/view_http_cache_job_factory.h" -#include "content/browser/net/view_blob_internals_job_factory.h" +#include "chrome/browser/browser_about_handler.h" +#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" +#include "chrome/common/url_constants.h" +#include "content/browser/webui/content_web_ui_controller_factory.h" +#include "content/public/browser/browser_url_handler.h" #include "content/public/common/url_constants.h" #include "content/public/common/user_agent.h" #include "ipc/ipc_channel.h" #include "net/url_request/url_request.h" -#include "ui/base/webui/web_ui_util.h" -#include "ui/resources/grit/webui_resources.h" -#include "ui/resources/grit/webui_resources_map.h" #include "v8/include/v8.h" namespace scheme { @@ -45,38 +46,282 @@ const char kChromeURL[] = "chrome://"; namespace { -const char kChromeCreditsDomain[] = "credits"; -const char kChromeLicenseDomain[] = "license"; -const char kChromeResourcesDomain[] = "resources"; -const char kChromeVersionDomain[] = "version"; +const char kChromeUILicenseHost[] = "license"; +const char kChromeUIWebUIHostsHost[] = "webui-hosts"; -enum ChromeDomain { - CHROME_UNKNOWN = 0, - CHROME_CREDITS, - CHROME_LICENSE, - CHROME_RESOURCES, - CHROME_VERSION, +// Chrome hosts implemented by WebUI. +// Some WebUI handlers have Chrome dependencies that may fail in CEF without +// additional changes. Do not add new hosts to this list without also manually +// testing all related functionality in CEF. +const char* kAllowedWebUIHosts[] = { + content::kChromeUIAppCacheInternalsHost, + content::kChromeUIAccessibilityHost, + content::kChromeUIBlobInternalsHost, + chrome::kChromeUICreditsHost, + content::kChromeUIGpuHost, + content::kChromeUIHistogramHost, + content::kChromeUIIndexedDBInternalsHost, + content::kChromeUIMediaInternalsHost, + chrome::kChromeUINetExportHost, + chrome::kChromeUINetInternalsHost, + content::kChromeUINetworkErrorHost, + content::kChromeUINetworkErrorsListingHost, + content::kChromeUINetworkViewCacheHost, + content::kChromeUIResourcesHost, + content::kChromeUIServiceWorkerInternalsHost, + chrome::kChromeUISystemInfoHost, + content::kChromeUITracingHost, + content::kChromeUIWebRTCInternalsHost, }; -ChromeDomain GetChromeDomain(const std::string& domain_name) { - static struct { - const char* name; - ChromeDomain domain; - } domains[] = { - { kChromeCreditsDomain, CHROME_CREDITS }, - { kChromeLicenseDomain, CHROME_LICENSE }, - { kChromeResourcesDomain, CHROME_RESOURCES }, - { kChromeVersionDomain, CHROME_VERSION }, - }; +enum ChromeHostId { + CHROME_UNKNOWN = 0, + CHROME_LICENSE, + CHROME_VERSION, + CHROME_WEBUI_HOSTS, +}; - for (size_t i = 0; i < sizeof(domains) / sizeof(domains[0]); ++i) { - if (base::EqualsCaseInsensitiveASCII(domains[i].name, domain_name.c_str())) - return domains[i].domain; +// Chrome hosts implemented by CEF. +const struct { + const char* host; + ChromeHostId host_id; +} kAllowedCefHosts[] = { + { kChromeUILicenseHost, CHROME_LICENSE }, + { chrome::kChromeUIVersionHost, CHROME_VERSION }, + { kChromeUIWebUIHostsHost, CHROME_WEBUI_HOSTS }, +}; + +ChromeHostId GetChromeHostId(const std::string& host) { + for (size_t i = 0; + i < sizeof(kAllowedCefHosts) / sizeof(kAllowedCefHosts[0]); ++i) { + if (base::EqualsCaseInsensitiveASCII(kAllowedCefHosts[i].host, + host.c_str())) { + return kAllowedCefHosts[i].host_id; + } } return CHROME_UNKNOWN; } +void GetAllowedHosts(std::vector* hosts) { + for (size_t i = 0; + i < sizeof(kAllowedCefHosts) / sizeof(kAllowedCefHosts[0]); ++i) { + hosts->push_back(kAllowedCefHosts[i].host); + } + + for (size_t i = 0; + i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) { + hosts->push_back(kAllowedWebUIHosts[i]); + } +} + +// Intercepts all WebUI calls and either blocks them or forwards them to the +// Content or Chrome WebUI factory as appropriate. +class CefWebUIControllerFactory : public content::WebUIControllerFactory { + public: + // Returns true if WebUI is allowed to handle the specified |url|. + static bool AllowWebUIForURL(const GURL& url) { + if (!url.SchemeIs(content::kChromeUIScheme)) + return false; + + for (size_t i = 0; + i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) { + if (base::EqualsCaseInsensitiveASCII(kAllowedWebUIHosts[i], + url.host().c_str())) { + return true; + } + } + + return false; + } + + content::WebUIController* CreateWebUIControllerForURL( + content::WebUI* web_ui, + const GURL& url) const override { + content::WebUIController* controller = nullptr; + if (!AllowWebUIForURL(url)) + return controller; + + controller = content::ContentWebUIControllerFactory::GetInstance()-> + CreateWebUIControllerForURL(web_ui, url); + if (controller != nullptr) + return controller; + + controller = ChromeWebUIControllerFactory::GetInstance()-> + CreateWebUIControllerForURL(web_ui, url); + if (controller != nullptr) + return controller; + + return nullptr; + } + + content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context, + const GURL& url) const override { + content::WebUI::TypeID type = content::WebUI::kNoWebUI; + if (!AllowWebUIForURL(url)) + return type; + + type = content::ContentWebUIControllerFactory::GetInstance()->GetWebUIType( + browser_context, url); + if (type != content::WebUI::kNoWebUI) + return type; + + type = ChromeWebUIControllerFactory::GetInstance()->GetWebUIType( + browser_context, url); + if (type != content::WebUI::kNoWebUI) + return type; + + return content::WebUI::kNoWebUI; + } + + bool UseWebUIForURL(content::BrowserContext* browser_context, + const GURL& url) const override { + if (!AllowWebUIForURL(url)) + return false; + + if (content::ContentWebUIControllerFactory::GetInstance()->UseWebUIForURL( + browser_context, url) || + ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL( + browser_context, url)) { + return true; + } + + return false; + } + + bool UseWebUIBindingsForURL(content::BrowserContext* browser_context, + const GURL& url) const override { + if (!AllowWebUIForURL(url)) + return false; + + if (content::ContentWebUIControllerFactory::GetInstance()-> + UseWebUIBindingsForURL(browser_context, url) || + ChromeWebUIControllerFactory::GetInstance()->UseWebUIBindingsForURL( + browser_context, url)) { + return true; + } + + return false; + } + + static void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) { + // about: handler. Must come before chrome: handler, since it will + // rewrite about: urls to chrome: URLs and then expect chrome: to + // actually handle them. Also relies on a preliminary fixup phase. + handler->SetFixupHandler(&FixupBrowserAboutURL); + handler->AddHandlerPair(&WillHandleBrowserAboutURL, + content::BrowserURLHandler::null_handler()); + + // chrome: & friends. + handler->AddHandlerPair(&HandleWebUI, &HandleWebUIReverse); + } + + static CefWebUIControllerFactory* GetInstance(); + + protected: + CefWebUIControllerFactory() {} + ~CefWebUIControllerFactory() override {} + + private: + friend struct base::DefaultLazyInstanceTraits; + + // From chrome/browser/chrome_content_browser_client.cc + + // Returns a copy of the given url with its host set to given host and path + // set to given path. Other parts of the url will be the same. + static GURL ReplaceURLHostAndPath(const GURL& url, + const std::string& host, + const std::string& path) { + url::Replacements replacements; + replacements.SetHost(host.c_str(), url::Component(0, host.length())); + replacements.SetPath(path.c_str(), url::Component(0, path.length())); + return url.ReplaceComponents(replacements); + } + + // Maps "foo://bar/baz/" to "foo://chrome/bar/baz/". + static GURL AddUberHost(const GURL& url) { + const std::string uber_host = chrome::kChromeUIUberHost; + std::string new_path; + url.host_piece().AppendToString(&new_path); + url.path_piece().AppendToString(&new_path); + + return ReplaceURLHostAndPath(url, uber_host, new_path); + } + + // If url->host() is "chrome" and url->path() has characters other than the + // first slash, changes the url from "foo://chrome/bar/" to "foo://bar/" and + // returns true. Otherwise returns false. + static bool RemoveUberHost(GURL* url) { + if (url->host() != chrome::kChromeUIUberHost) + return false; + + if (url->path().empty() || url->path() == "/") + return false; + + const std::string old_path = url->path(); + + const std::string::size_type separator = old_path.find('/', 1); + std::string new_host; + std::string new_path; + if (separator == std::string::npos) { + new_host = old_path.substr(1); + } else { + new_host = old_path.substr(1, separator - 1); + new_path = old_path.substr(separator); + } + + // Do not allow URLs with paths empty before the first slash since we can't + // have an empty host. (e.g "foo://chrome//") + if (new_host.empty()) + return false; + + *url = ReplaceURLHostAndPath(*url, new_host, new_path); + + DCHECK(url->is_valid()); + + return true; + } + + // Handles rewriting Web UI URLs. + static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context) { + // Do not handle special URLs such as "about:foo" + if (!url->host().empty()) { + const GURL chrome_url = AddUberHost(*url); + + // Handle valid "chrome://chrome/foo" URLs so the reverse handler will + // be called. + if (GetInstance()->UseWebUIForURL(browser_context, chrome_url)) + return true; + } + + if (!GetInstance()->UseWebUIForURL(browser_context, *url)) + return false; + + return true; + } + + // Reverse URL handler for Web UI. Maps "chrome://chrome/foo/" to + // "chrome://foo/". + static bool HandleWebUIReverse(GURL* url, + content::BrowserContext* browser_context) { + if (!url->is_valid() || !url->SchemeIs(content::kChromeUIScheme)) + return false; + + return RemoveUberHost(url); + } + + DISALLOW_COPY_AND_ASSIGN(CefWebUIControllerFactory); +}; + +base::LazyInstance::Leaky + g_web_ui_controller_factory = LAZY_INSTANCE_INITIALIZER; + +// static +CefWebUIControllerFactory* CefWebUIControllerFactory::GetInstance() { + return &g_web_ui_controller_factory.Get(); +} + + std::string GetOSType() { #if defined(OS_WIN) return "Windows"; @@ -186,49 +431,6 @@ class TemplateParser { std::string ident_end_; }; -// From content/browser/webui/shared_resources_data_source.cc. -using ResourcesMap = base::hash_map; - -// TODO(rkc): Once we have a separate source for apps, remove '*/apps/' aliases. -const char* const kPathAliases[][2] = { - {"../../../third_party/polymer/v1_0/components-chromium/", "polymer/v1_0/"}, - {"../../../third_party/web-animations-js/sources/", - "polymer/v1_0/web-animations-js/"}, - {"../../views/resources/default_100_percent/common/", "images/apps/"}, - {"../../views/resources/default_200_percent/common/", "images/2x/apps/"}, - {"../../webui/resources/cr_elements/", "cr_elements/"}}; - -void AddResource(const std::string& path, - int resource_id, - ResourcesMap* resources_map) { - if (!resources_map->insert(std::make_pair(path, resource_id)).second) - NOTREACHED() << "Redefinition of '" << path << "'"; -} - -const ResourcesMap* CreateResourcesMap() { - ResourcesMap* result = new ResourcesMap(); - for (size_t i = 0; i < kWebuiResourcesSize; ++i) { - const std::string resource_name = kWebuiResources[i].name; - const int resource_id = kWebuiResources[i].value; - AddResource(resource_name, resource_id, result); - for (const char* const (&alias)[2] : kPathAliases) { - if (base::StartsWith(resource_name, alias[0], - base::CompareCase::SENSITIVE)) { - AddResource(alias[1] + resource_name.substr(strlen(alias[0])), - resource_id, result); - } - } - } - - return result; -} - -const ResourcesMap& GetResourcesMap() { - // This pointer will be intentionally leaked on shutdown. - static const ResourcesMap* resources_map = CreateResourcesMap(); - return *resources_map; -} - class Delegate : public InternalHandlerDelegate { public: Delegate() {} @@ -243,49 +445,33 @@ class Delegate : public InternalHandlerDelegate { bool handled = false; - ChromeDomain domain = GetChromeDomain(url.host()); - switch (domain) { - case CHROME_CREDITS: - handled = OnCredits(path, action); - break; + ChromeHostId host_id = GetChromeHostId(url.host()); + switch (host_id) { case CHROME_LICENSE: handled = OnLicense(action); break; - case CHROME_RESOURCES: - handled = OnResources(path, action); - break; case CHROME_VERSION: handled = OnVersion(browser, action); break; + case CHROME_WEBUI_HOSTS: + handled = OnWebUIHosts(action); + break; default: break; } - if (!handled && domain != CHROME_VERSION) { + if (!handled && host_id != CHROME_VERSION) { LOG(INFO) << "Reguest for unknown chrome resource: " << url.spec().c_str(); - if (domain != CHROME_RESOURCES) { - action->redirect_url = - GURL(std::string(kChromeURL) + kChromeVersionDomain); - return true; - } + action->redirect_url = + GURL(std::string(kChromeURL) + chrome::kChromeUIVersionHost); + return true; } return handled; } - bool OnCredits(const std::string& path, Action* action) { - if (path == "credits.js") { - action->resource_id = IDR_ABOUT_UI_CREDITS_JS; - } else { - action->mime_type = "text/html"; - action->resource_id = IDR_ABOUT_UI_CREDITS_HTML; - action->encoding = Action::ENCODING_BROTLI; - } - return true; - } - bool OnLicense(Action* action) { base::StringPiece piece = CefContentClient::Get()->GetDataResource( IDR_CEF_LICENSE_TXT, ui::SCALE_FACTOR_NONE); @@ -305,33 +491,6 @@ class Delegate : public InternalHandlerDelegate { return true; } - bool OnResources(const std::string& path, Action* action) { - // Implementation based on SharedResourcesDataSource::StartDataRequest. - const ResourcesMap& resources_map = GetResourcesMap(); - auto it = resources_map.find(path); - int resource_id = (it != resources_map.end()) ? it->second : -1; - - if (resource_id == -1) { - NOTREACHED() << "Failed to find resource id for " << path; - return false; - } - - if (resource_id == IDR_WEBUI_CSS_TEXT_DEFAULTS || - resource_id == IDR_WEBUI_CSS_TEXT_DEFAULTS_MD) { - const std::string& css = resource_id == IDR_WEBUI_CSS_TEXT_DEFAULTS ? - webui::GetWebUiCssTextDefaults() : webui::GetWebUiCssTextDefaultsMd(); - DCHECK(!css.empty()); - action->mime_type = "text/css"; - action->stream = CefStreamReader::CreateForData( - const_cast(css.c_str()), css.length()); - action->stream_size = css.length(); - } else { - action->resource_id = resource_id; - } - - return true; - } - bool OnVersion(CefRefPtr browser, Action* action) { base::StringPiece piece = CefContentClient::Get()->GetDataResource( @@ -370,6 +529,29 @@ class Delegate : public InternalHandlerDelegate { return true; } + + bool OnWebUIHosts(Action* action) { + std::string html = "\nWebUI Hosts\n" + "

WebUI Hosts

\n
    \n"; + + std::vector hosts; + GetAllowedHosts(&hosts); + std::sort(hosts.begin(), hosts.end()); + + for (size_t i = 0U; i < hosts.size(); ++i) { + html += "
  • chrome://" + + hosts[i] + "
  • \n"; + } + + html += "
\n"; + + action->mime_type = "text/html"; + action->stream = CefStreamReader::CreateForData( + const_cast(html.c_str()), html.length()); + action->stream_size = html.length(); + + return true; + } }; void DidFinishChromeVersionLoad(CefRefPtr frame) { @@ -422,14 +604,8 @@ class ChromeProtocolHandlerWrapper : net::URLRequestJob* MaybeCreateJob( net::URLRequest* request, net::NetworkDelegate* network_delegate) const override { - // Keep synchronized with the checks in - // ChromeProtocolHandler::MaybeCreateJob. - if (content::ViewHttpCacheJobFactory::IsSupportedURL(request->url()) || - (request->url().SchemeIs(content::kChromeUIScheme) && - request->url().host() == content::kChromeUIAppCacheInternalsHost) || - content::ViewBlobInternalsJobFactory::IsSupportedURL(request->url()) || - (request->url().SchemeIs(content::kChromeUIScheme) && - request->url().host() == content::kChromeUIHistogramHost)) { + // Only allow WebUI to handle chrome:// URLs whitelisted by CEF. + if (CefWebUIControllerFactory::AllowWebUIForURL(request->url())) { return chrome_protocol_handler_->MaybeCreateJob(request, network_delegate); } @@ -453,22 +629,23 @@ void RegisterChromeHandler(CefURLRequestManager* request_manager) { CreateInternalHandlerFactory(base::WrapUnique(new Delegate()))); } -bool WillHandleBrowserAboutURL(GURL* url, - content::BrowserContext* browser_context) { - std::string text = url->possibly_invalid_spec(); - if (text.find("about:") == 0 && text != "about:blank" && text.length() > 6) { - // Redirect about: URLs to chrome:// - *url = GURL(kChromeURL + text.substr(6)); - } +void RegisterWebUIControllerFactory() { + // Channel all WebUI handling through CefWebUIControllerFactory. + content::WebUIControllerFactory::UnregisterFactoryForTesting( + content::ContentWebUIControllerFactory::GetInstance()); - // Allow the redirection to proceed. - return false; + content::WebUIControllerFactory::RegisterFactory( + CefWebUIControllerFactory::GetInstance()); +} + +void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) { + CefWebUIControllerFactory::BrowserURLHandlerCreated(handler); } void DidFinishChromeLoad(CefRefPtr frame, const GURL& validated_url) { - ChromeDomain domain = GetChromeDomain(validated_url.host()); - switch (domain) { + ChromeHostId host_id = GetChromeHostId(validated_url.host()); + switch (host_id) { case CHROME_VERSION: DidFinishChromeVersionLoad(frame); default: diff --git a/libcef/browser/net/chrome_scheme_handler.h b/libcef/browser/net/chrome_scheme_handler.h index 43e4bf4ab..f2d1d9294 100644 --- a/libcef/browser/net/chrome_scheme_handler.h +++ b/libcef/browser/net/chrome_scheme_handler.h @@ -20,7 +20,7 @@ class ListValue; } namespace content { -class BrowserContext; +class BrowserURLHandler; } class CefURLRequestManager; @@ -32,9 +32,11 @@ extern const char kChromeURL[]; // Register the chrome scheme handler. void RegisterChromeHandler(CefURLRequestManager* request_manager); -// Used to redirect about: URLs to chrome: URLs. -bool WillHandleBrowserAboutURL(GURL* url, - content::BrowserContext* browser_context); +// Register the WebUI controller factory. +void RegisterWebUIControllerFactory(); + +// Register the WebUI handler. +void BrowserURLHandlerCreated(content::BrowserURLHandler* handler); // Used to fire any asynchronous content updates. void DidFinishChromeLoad(CefRefPtr frame, diff --git a/libcef/browser/net/url_request_context_getter_impl.cc b/libcef/browser/net/url_request_context_getter_impl.cc index 084d0e1a0..d0de4874c 100644 --- a/libcef/browser/net/url_request_context_getter_impl.cc +++ b/libcef/browser/net/url_request_context_getter_impl.cc @@ -25,8 +25,10 @@ #include "base/threading/thread_restrictions.h" #include "base/threading/worker_pool.h" #include "build/build_config.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/net/proxy_service_factory.h" #include "chrome/common/pref_names.h" +#include "components/net_log/chrome_net_log.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" @@ -114,12 +116,14 @@ CefURLRequestContextGetterImpl::CefURLRequestContextGetterImpl( std::unique_ptr proxy_config_service, content::URLRequestInterceptorScopedVector request_interceptors) : settings_(settings), + net_log_(g_browser_process->net_log()), io_task_runner_(std::move(io_task_runner)), file_task_runner_(std::move(file_task_runner)), proxy_config_service_(std::move(proxy_config_service)), request_interceptors_(std::move(request_interceptors)) { // Must first be created on the UI thread. CEF_REQUIRE_UIT(); + DCHECK(net_log_); std::swap(protocol_handlers_, *protocol_handlers); @@ -197,6 +201,8 @@ net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() { cache_path = base::FilePath(CefString(&settings_.cache_path)); url_request_context_.reset(new CefURLRequestContextImpl()); + url_request_context_->set_net_log(net_log_); + storage_.reset( new net::URLRequestContextStorage(url_request_context_.get())); @@ -214,7 +220,8 @@ net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() { storage_->set_http_user_agent_settings(base::WrapUnique( new CefHttpUserAgentSettings(accept_language))); - storage_->set_host_resolver(net::HostResolver::CreateDefaultResolver(NULL)); + storage_->set_host_resolver( + net::HostResolver::CreateDefaultResolver(net_log_)); storage_->set_cert_verifier(net::CertVerifier::CreateDefault()); storage_->set_transport_security_state( base::WrapUnique(new net::TransportSecurityState)); @@ -231,7 +238,7 @@ net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() { std::unique_ptr system_proxy_service = ProxyServiceFactory::CreateProxyService( - NULL, + net_log_, url_request_context_.get(), url_request_context_->network_delegate(), std::move(proxy_config_service_), @@ -299,6 +306,7 @@ net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() { url_request_context_->http_server_properties(); network_session_params.ignore_certificate_errors = settings_.ignore_certificate_errors ? true : false; + network_session_params.net_log = net_log_; storage_->set_http_network_session( base::WrapUnique(new net::HttpNetworkSession(network_session_params))); diff --git a/libcef/browser/net/url_request_context_getter_impl.h b/libcef/browser/net/url_request_context_getter_impl.h index 8a26e9a67..2cb192b9d 100644 --- a/libcef/browser/net/url_request_context_getter_impl.h +++ b/libcef/browser/net/url_request_context_getter_impl.h @@ -91,6 +91,8 @@ class CefURLRequestContextGetterImpl : public CefURLRequestContextGetter { const CefRequestContextSettings settings_; + net::NetLog* net_log_; // Guaranteed to outlive this object. + scoped_refptr io_task_runner_; scoped_refptr file_task_runner_; diff --git a/libcef/browser/prefs/browser_prefs.cc b/libcef/browser/prefs/browser_prefs.cc index 377927116..3c2e2e614 100644 --- a/libcef/browser/prefs/browser_prefs.cc +++ b/libcef/browser/prefs/browser_prefs.cc @@ -13,6 +13,7 @@ #include "base/files/file_path.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" +#include "chrome/browser/net/prediction_options.h" #include "chrome/browser/prefs/command_line_pref_store.h" #include "chrome/browser/supervised_user/supervised_user_pref_store.h" #include "chrome/browser/supervised_user/supervised_user_settings_service.h" @@ -172,6 +173,7 @@ std::unique_ptr CreatePrefService( renderer_prefs::RegisterProfilePrefs(registry.get()); update_client::RegisterPrefs(registry.get()); content_settings::CookieSettings::RegisterProfilePrefs(registry.get()); + chrome_browser_net::RegisterPredictionOptionsProfilePrefs(registry.get()); // Print preferences. registry->RegisterBooleanPref(prefs::kPrintingEnabled, true); @@ -227,6 +229,10 @@ std::unique_ptr CreatePrefService( registry->RegisterDictionaryPref(prefs::kCurrentThemeTints); registry->RegisterDictionaryPref(prefs::kCurrentThemeDisplayProperties); + // Browser UI preferences. + // Based on chrome/browser/ui/browser_ui_prefs.cc RegisterBrowserPrefs. + registry->RegisterBooleanPref(prefs::kAllowFileSelectionDialogs, true); + if (command_line->HasSwitch(switches::kEnablePreferenceTesting)) { // Preferences used with unit tests. registry->RegisterBooleanPref("test.bool", true); diff --git a/libcef/browser/resource_context.cc b/libcef/browser/resource_context.cc index 388e2f46c..247394085 100644 --- a/libcef/browser/resource_context.cc +++ b/libcef/browser/resource_context.cc @@ -8,6 +8,7 @@ #include "libcef/browser/thread_util.h" #include "base/logging.h" +#include "content/browser/resource_context_impl.h" #include "content/public/browser/browser_thread.h" #if defined(USE_NSS_CERTS) @@ -22,11 +23,24 @@ #include "net/ssl/client_cert_store_mac.h" #endif +namespace { + +bool ShouldProxyUserData(const void* key) { + // If this value is not proxied WebUI will fail to load. + if (key == content::GetURLDataManagerBackendUserDataKey()) + return true; + + return false; +} + +} // namespace + CefResourceContext::CefResourceContext( bool is_off_the_record, extensions::InfoMap* extension_info_map, CefRefPtr handler) - : is_off_the_record_(is_off_the_record), + : parent_(nullptr), + is_off_the_record_(is_off_the_record), extension_info_map_(extension_info_map), handler_(handler) { } @@ -45,6 +59,27 @@ CefResourceContext::~CefResourceContext() { } } +base::SupportsUserData::Data* CefResourceContext::GetUserData(const void* key) + const { + if (parent_ && ShouldProxyUserData(key)) + return parent_->GetUserData(key); + return content::ResourceContext::GetUserData(key); +} + +void CefResourceContext::SetUserData(const void* key, Data* data) { + if (parent_ && ShouldProxyUserData(key)) + parent_->SetUserData(key, data); + else + content::ResourceContext::SetUserData(key, data); +} + +void CefResourceContext::RemoveUserData(const void* key) { + if (parent_ && ShouldProxyUserData(key)) + parent_->RemoveUserData(key); + else + content::ResourceContext::RemoveUserData(key); +} + net::HostResolver* CefResourceContext::GetHostResolver() { CHECK(getter_.get()); return getter_->GetHostResolver(); @@ -80,6 +115,12 @@ void CefResourceContext::set_url_request_context_getter( getter_ = getter; } +void CefResourceContext::set_parent(CefResourceContext* parent) { + DCHECK(!parent_); + DCHECK(parent); + parent_ = parent; +} + void CefResourceContext::AddPluginLoadDecision( int render_process_id, const base::FilePath& plugin_path, diff --git a/libcef/browser/resource_context.h b/libcef/browser/resource_context.h index b4a7461d3..01ae1024c 100644 --- a/libcef/browser/resource_context.h +++ b/libcef/browser/resource_context.h @@ -30,6 +30,11 @@ class CefResourceContext : public content::ResourceContext { CefRefPtr handler); ~CefResourceContext() override; + // SupportsUserData implementation. + Data* GetUserData(const void* key) const override; + void SetUserData(const void* key, Data* data) override; + void RemoveUserData(const void* key) override; + // ResourceContext implementation. net::HostResolver* GetHostResolver() override; net::URLRequestContext* GetRequestContext() override; @@ -37,6 +42,7 @@ class CefResourceContext : public content::ResourceContext { std::unique_ptr CreateClientCertStore(); void set_url_request_context_getter(CefURLRequestContextGetter* getter); + void set_parent(CefResourceContext* parent); // Remember the plugin load decision for plugin status requests that arrive // via CefPluginServiceFilter::IsPluginAvailable. @@ -64,6 +70,11 @@ class CefResourceContext : public content::ResourceContext { private: scoped_refptr getter_; + // Non-NULL when this object is owned by a CefBrowserContextProxy. |parent_| + // is guaranteed to outlive this object because CefBrowserContextProxy has a + // refptr to the CefBrowserContextImpl that owns |parent_|. + CefResourceContext* parent_; + // Only accessed on the IO thread. bool is_off_the_record_; scoped_refptr extension_info_map_; diff --git a/libcef/common/content_client.cc b/libcef/common/content_client.cc index f7bbee1b9..528ad26da 100644 --- a/libcef/common/content_client.cc +++ b/libcef/common/content_client.cc @@ -286,6 +286,16 @@ base::StringPiece CefContentClient::GetDataResource( return value; } +base::RefCountedMemory* CefContentClient::GetDataResourceBytes( + int resource_id) const { + base::RefCountedMemory* value = + ResourceBundle::GetSharedInstance().LoadDataResourceBytes(resource_id); + if (!value) + LOG(ERROR) << "No data resource bytes available for id " << resource_id; + + return value; +} + gfx::Image& CefContentClient::GetNativeImageNamed(int resource_id) const { gfx::Image& value = ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); diff --git a/libcef/common/content_client.h b/libcef/common/content_client.h index 9e3fde70b..a00f5ae45 100644 --- a/libcef/common/content_client.h +++ b/libcef/common/content_client.h @@ -42,6 +42,8 @@ class CefContentClient : public content::ContentClient, base::StringPiece GetDataResource( int resource_id, ui::ScaleFactor scale_factor) const override; + base::RefCountedMemory* GetDataResourceBytes( + int resource_id) const override; gfx::Image& GetNativeImageNamed(int resource_id) const override; struct SchemeInfo { diff --git a/patch/patch.cfg b/patch/patch.cfg index a4eafd594..a84710f56 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -274,4 +274,12 @@ patches = [ 'name': 'webview_plugin_2020', 'path': '../', }, + { + # Support WebUI by: + # (a) Exposing required UserData keys; + # (b) Removing dependency on non-NULL IOThread* object. + # https://bitbucket.org/chromiumembedded/cef/issues/2037 + 'name': 'webui_2037', + 'path': '../', + }, ] diff --git a/patch/patches/chrome_profile.patch b/patch/patches/chrome_profile.patch index 51aff4904..e594a33fb 100644 --- a/patch/patches/chrome_profile.patch +++ b/patch/patches/chrome_profile.patch @@ -63,7 +63,7 @@ index 4b43013..169ca47 100644 content::BrowserContext* GetBrowserContextRedirectedInIncognito( content::BrowserContext* context); diff --git chrome/browser/profiles/profile_manager.h chrome/browser/profiles/profile_manager.h -index ba156c5..b7f41d3 100644 +index ba156c5..0ed578b 100644 --- chrome/browser/profiles/profile_manager.h +++ chrome/browser/profiles/profile_manager.h @@ -89,7 +89,7 @@ class ProfileManager : public base::NonThreadSafe, @@ -84,3 +84,12 @@ index ba156c5..b7f41d3 100644 // Returns the directory where the first created profile is stored, // relative to the user data directory currently in use. +@@ -126,7 +126,7 @@ class ProfileManager : public base::NonThreadSafe, + // Get the Profile last used (the Profile to which owns the most recently + // focused window) with this Chrome build. If no signed profile has been + // stored in Local State, hand back the Default profile. +- Profile* GetLastUsedProfile(const base::FilePath& user_data_dir); ++ virtual Profile* GetLastUsedProfile(const base::FilePath& user_data_dir); + + // Get the path of the last used profile, or if that's undefined, the default + // profile. diff --git a/patch/patches/webui_2037.patch b/patch/patches/webui_2037.patch new file mode 100644 index 000000000..553369e39 --- /dev/null +++ b/patch/patches/webui_2037.patch @@ -0,0 +1,117 @@ +diff --git chrome/browser/ui/webui/net_internals/net_internals_ui.cc chrome/browser/ui/webui/net_internals/net_internals_ui.cc +index 92fa2f1..cc3f54a 100644 +--- chrome/browser/ui/webui/net_internals/net_internals_ui.cc ++++ chrome/browser/ui/webui/net_internals/net_internals_ui.cc +@@ -689,9 +689,17 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady( + + PrePopulateEventList(); + +- // Register with network stack to observe events. +- io_thread_->net_log()->DeprecatedAddObserver( +- this, net::NetLogCaptureMode::IncludeCookiesAndCredentials()); ++ net::NetLog* net_log = nullptr; ++ if (io_thread_) ++ net_log = io_thread_->net_log(); ++ else ++ net_log = g_browser_process->net_log(); ++ ++ if (net_log) { ++ // Register with network stack to observe events. ++ net_log->DeprecatedAddObserver( ++ this, net::NetLogCaptureMode::IncludeCookiesAndCredentials()); ++ } + } + + void NetInternalsMessageHandler::IOThreadImpl::OnGetNetInfo( +@@ -869,21 +877,8 @@ void NetInternalsMessageHandler::IOThreadImpl::OnHSTSDelete( + void NetInternalsMessageHandler::IOThreadImpl::OnGetSessionNetworkStats( + const base::ListValue* list) { + DCHECK(!list); +- net::URLRequestContext* context = +- main_context_getter_->GetURLRequestContext(); +- net::HttpNetworkSession* http_network_session = +- GetHttpNetworkSession(context); + + std::unique_ptr network_info; +- if (http_network_session) { +- // TODO(mmenke): This cast is ugly. Can we get rid of it, or, better, +- // remove DRP data from net-internals entirely? +- data_reduction_proxy::DataReductionProxyNetworkDelegate* net_delegate = +- static_cast( +- context->network_delegate()); +- if (net_delegate) +- network_info = net_delegate->SessionNetworkStatsInfoToValue(); +- } + SendJavascriptCommand("receivedSessionNetworkStats", std::move(network_info)); + } + +@@ -1149,8 +1144,10 @@ void NetInternalsMessageHandler::IOThreadImpl::PrePopulateEventList() { + std::set contexts; + for (const auto& getter : context_getters_) + contexts.insert(getter->GetURLRequestContext()); +- contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get()); +- contexts.insert(io_thread_->globals()->system_request_context.get()); ++ if (io_thread_) { ++ contexts.insert(io_thread_->globals()->proxy_script_fetcher_context.get()); ++ contexts.insert(io_thread_->globals()->system_request_context.get()); ++ } + + // Add entries for ongoing network objects. + CreateNetLogEntriesForActiveObjects(contexts, this); +diff --git content/browser/resource_context_impl.cc content/browser/resource_context_impl.cc +index 22c12ee..57031f3 100644 +--- content/browser/resource_context_impl.cc ++++ content/browser/resource_context_impl.cc +@@ -84,6 +84,10 @@ URLDataManagerBackend* GetURLDataManagerForResourceContext( + context->GetUserData(kURLDataManagerBackendKeyName)); + } + ++const void* GetURLDataManagerBackendUserDataKey() { ++ return kURLDataManagerBackendKeyName; ++} ++ + void InitializeResourceContext(BrowserContext* browser_context) { + ResourceContext* resource_context = browser_context->GetResourceContext(); + +diff --git content/browser/resource_context_impl.h content/browser/resource_context_impl.h +index 903cc54..56ee4ea 100644 +--- content/browser/resource_context_impl.h ++++ content/browser/resource_context_impl.h +@@ -28,6 +28,8 @@ CONTENT_EXPORT StreamContext* GetStreamContextForResourceContext( + URLDataManagerBackend* GetURLDataManagerForResourceContext( + ResourceContext* context); + ++const void* GetURLDataManagerBackendUserDataKey(); ++ + // Initialize the above data on the ResourceContext from a given BrowserContext. + CONTENT_EXPORT void InitializeResourceContext(BrowserContext* browser_context); + +diff --git content/browser/webui/url_data_manager.cc content/browser/webui/url_data_manager.cc +index a9ec107..4a215ca 100644 +--- content/browser/webui/url_data_manager.cc ++++ content/browser/webui/url_data_manager.cc +@@ -123,6 +123,11 @@ void URLDataManager::AddWebUIDataSource(BrowserContext* browser_context, + } + + // static ++const void* URLDataManager::GetUserDataKey() { ++ return kURLDataManagerKeyName; ++} ++ ++// static + bool URLDataManager::IsScheduledForDeletion( + const URLDataSourceImpl* data_source) { + base::AutoLock lock(g_delete_lock.Get()); +diff --git content/browser/webui/url_data_manager.h content/browser/webui/url_data_manager.h +index 8eca18c..97fc80ea 100644 +--- content/browser/webui/url_data_manager.h ++++ content/browser/webui/url_data_manager.h +@@ -55,6 +55,8 @@ class CONTENT_EXPORT URLDataManager : public base::SupportsUserData::Data { + static void AddWebUIDataSource(BrowserContext* browser_context, + WebUIDataSource* source); + ++ static const void* GetUserDataKey(); ++ + private: + friend class URLDataSourceImpl; + friend struct DeleteURLDataSource; diff --git a/tests/unittests/webui_unittest.cc b/tests/unittests/webui_unittest.cc new file mode 100644 index 000000000..d118c91cf --- /dev/null +++ b/tests/unittests/webui_unittest.cc @@ -0,0 +1,212 @@ +// Copyright 2016 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 "include/base/cef_bind.h" +#include "include/cef_callback.h" +#include "include/cef_parser.h" +#include "include/wrapper/cef_closure_task.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "tests/unittests/test_handler.h" + +namespace { + +typedef std::vector UrlList; + +class WebUITestHandler : public TestHandler { + public: + explicit WebUITestHandler(const UrlList& url_list) + : url_list_(url_list), + url_index_(0U), + expected_error_code_(ERR_NONE) { + CHECK(!url_list_.empty()); + } + + void set_expected_url(const std::string& expected_url) { + expected_url_ = expected_url; + } + + void set_expected_error_code(int error_code) { + expected_error_code_ = error_code; + } + + void RunTest() override { + // Create the browser. + CreateBrowser(url_list_[0]); + + // Time out the test after a reasonable period of time. + SetTestTimeout((int(url_list_.size() / 5U) + 1) * 5000); + } + + void NextNav() { + base::Closure next_action; + + if (++url_index_ == url_list_.size()) { + next_action = base::Bind(&WebUITestHandler::DestroyTest, this); + } else { + next_action = base::Bind(&WebUITestHandler::LoadURL, this, + url_list_[url_index_]); + } + + // Wait a bit for the WebUI content to finish loading before performing the + // next action. + CefPostDelayedTask(TID_UI, next_action, 200); + } + + void LoadURL(const std::string& url) { + GetBrowser()->GetMainFrame()->LoadURL(url); + } + + void OnLoadingStateChange(CefRefPtr browser, + bool isLoading, + bool canGoBack, + bool canGoForward) override { + if (!isLoading) { + // Verify that we navigated to the expected URL. + std::string expected_url = expected_url_; + if (expected_url.empty()) + expected_url = url_list_[url_index_]; + EXPECT_STREQ(expected_url.c_str(), + browser->GetMainFrame()->GetURL().ToString().c_str()); + + NextNav(); + } + } + + void OnLoadError(CefRefPtr browser, + CefRefPtr frame, + ErrorCode errorCode, + const CefString& errorText, + const CefString& failedUrl) override { + got_load_error_.yes(); + EXPECT_EQ(expected_error_code_, errorCode) << + "failedUrl = " << failedUrl.ToString(); + } + + void DestroyTest() override { + if (expected_error_code_ == ERR_NONE) + EXPECT_FALSE(got_load_error_); + else + EXPECT_TRUE(got_load_error_); + + TestHandler::DestroyTest(); + } + + UrlList url_list_; + size_t url_index_; + + std::string expected_url_; + int expected_error_code_; + + TrackCallback got_load_error_; + + IMPLEMENT_REFCOUNTING(WebUITestHandler); +}; + +} // namespace + + +// Test hosts with special behaviors. + +// Non-existing URLs should redirect to chrome://version/. +TEST(WebUITest, doesnotexist) { + UrlList url_list; + url_list.push_back("chrome://doesnotexist/"); + CefRefPtr handler = new WebUITestHandler(url_list); + handler->set_expected_url("chrome://version/"); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +// about:* URIs should redirect to chrome://*. +TEST(WebUITest, about) { + UrlList url_list; + url_list.push_back("about:license"); + CefRefPtr handler = new WebUITestHandler(url_list); + handler->set_expected_url("chrome://license/"); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +// chrome://network-error/X should generate network error X. +TEST(WebUITest, network_error) { + UrlList url_list; + // -310 is ERR_TOO_MANY_REDIRECTS + url_list.push_back("chrome://network-error/-310"); + CefRefPtr handler = new WebUITestHandler(url_list); + handler->set_expected_url("data:text/html,chromewebdata"); + handler->set_expected_error_code(ERR_TOO_MANY_REDIRECTS); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + + +// Test hosts with a single URL. + +namespace { + +void RunWebUITest(const UrlList& url_list) { + CefRefPtr handler = new WebUITestHandler(url_list); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +void RunWebUITest(const std::string& url) { + UrlList url_list; + url_list.push_back(url); + RunWebUITest(url_list); +} + +} // namespace + +#define WEBUI_TEST(name) \ + TEST(WebUITest, name) { \ + std::string name_str = #name; \ + std::replace(name_str.begin(), name_str.end(), '_', '-'); \ + RunWebUITest("chrome://" + name_str + "/"); \ + } + +WEBUI_TEST(appcache_internals); +WEBUI_TEST(accessibility); +WEBUI_TEST(blob_internals); +WEBUI_TEST(credits); +WEBUI_TEST(gpu); +WEBUI_TEST(histograms); +WEBUI_TEST(indexeddb_internals); +WEBUI_TEST(license); +WEBUI_TEST(media_internals); +WEBUI_TEST(net_export); +WEBUI_TEST(network_errors); +WEBUI_TEST(serviceworker_internals); +WEBUI_TEST(system); +WEBUI_TEST(tracing); +WEBUI_TEST(version); +WEBUI_TEST(view_http_cache); +WEBUI_TEST(webrtc_internals); +WEBUI_TEST(webui_hosts); + + +// Test hosts with multiple URLs. + +TEST(WebUITest, net_internals) { + UrlList url_list; + url_list.push_back("chrome://net-internals/#capture"); + url_list.push_back("chrome://net-internals/#export"); + url_list.push_back("chrome://net-internals/#import"); + url_list.push_back("chrome://net-internals/#proxy"); + url_list.push_back("chrome://net-internals/#events"); + url_list.push_back("chrome://net-internals/#timeline"); + url_list.push_back("chrome://net-internals/#dns"); + url_list.push_back("chrome://net-internals/#sockets"); + url_list.push_back("chrome://net-internals/#alt-svc"); + url_list.push_back("chrome://net-internals/#http2"); + url_list.push_back("chrome://net-internals/#quic"); + url_list.push_back("chrome://net-internals/#sdch"); + url_list.push_back("chrome://net-internals/#httpCache"); + url_list.push_back("chrome://net-internals/#modules"); + url_list.push_back("chrome://net-internals/#hsts"); + url_list.push_back("chrome://net-internals/#bandwidth"); + url_list.push_back("chrome://net-internals/#prerender"); + + RunWebUITest(url_list); +}