| // Copyright (c) 2012 The Chromium 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 "chrome/browser/chrome_content_browser_client.h" |
| |
| #include <set> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/string_tokenizer.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/app/breakpad_mac.h" |
| #include "chrome/browser/browser_about_handler.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browsing_data_remover.h" |
| #include "chrome/browser/character_encoding.h" |
| #include "chrome/browser/chrome_benchmarking_message_filter.h" |
| #include "chrome/browser/chrome_quota_permission_context.h" |
| #include "chrome/browser/content_settings/content_settings_utils.h" |
| #include "chrome/browser/content_settings/cookie_settings.h" |
| #include "chrome/browser/content_settings/host_content_settings_map.h" |
| #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
| #include "chrome/browser/defaults.h" |
| #include "chrome/browser/download/download_util.h" |
| #include "chrome/browser/extensions/api/webrequest/webrequest_api.h" |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/extensions/extension_info_map.h" |
| #include "chrome/browser/extensions/extension_message_handler.h" |
| #include "chrome/browser/extensions/extension_process_manager.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_web_ui.h" |
| #include "chrome/browser/extensions/extension_webkit_preferences.h" |
| #include "chrome/browser/geolocation/chrome_access_token_store.h" |
| #include "chrome/browser/google/google_util.h" |
| #include "chrome/browser/infobars/infobar_tab_helper.h" |
| #include "chrome/browser/net/chrome_net_log.h" |
| #include "chrome/browser/notifications/desktop_notification_service.h" |
| #include "chrome/browser/notifications/desktop_notification_service_factory.h" |
| #include "chrome/browser/platform_util.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| #include "chrome/browser/prerender/prerender_manager.h" |
| #include "chrome/browser/prerender/prerender_manager_factory.h" |
| #include "chrome/browser/prerender/prerender_tracker.h" |
| #include "chrome/browser/printing/printing_message_filter.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_io_data.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
| #include "chrome/browser/renderer_host/chrome_render_view_host_observer.h" |
| #include "chrome/browser/renderer_host/plugin_info_message_filter.h" |
| #include "chrome/browser/search_engines/search_provider_install_state_message_filter.h" |
| #include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h" |
| #include "chrome/browser/spellchecker/spellcheck_message_filter.h" |
| #include "chrome/browser/ssl/ssl_add_cert_handler.h" |
| #include "chrome/browser/ssl/ssl_blocking_page.h" |
| #include "chrome/browser/tab_contents/tab_contents_ssl_helper.h" |
| #include "chrome/browser/tab_contents/tab_util.h" |
| #include "chrome/browser/ui/media_stream_infobar_delegate.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" |
| #include "chrome/browser/user_style_sheet_watcher.h" |
| #include "chrome/common/child_process_logging.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/extensions/extension.h" |
| #include "chrome/common/extensions/extension_set.h" |
| #include "chrome/common/logging_chrome.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/render_messages.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/public/browser/browser_main_parts.h" |
| #include "content/public/browser/browser_url_handler.h" |
| #include "content/public/browser/child_process_security_policy.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/resource_context.h" |
| #include "content/public/browser/site_instance.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_contents_view.h" |
| #include "grit/generated_resources.h" |
| #include "grit/ui_resources.h" |
| #include "net/base/ssl_cert_request_info.h" |
| #include "net/cookies/cookie_monster.h" |
| #include "net/cookies/cookie_options.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "webkit/glue/webpreferences.h" |
| |
| #if defined(OS_WIN) |
| #include "chrome/browser/chrome_browser_main_win.h" |
| #elif defined(OS_MACOSX) |
| #include "chrome/browser/chrome_browser_main_mac.h" |
| #include "chrome/browser/spellchecker/spellcheck_message_filter_mac.h" |
| #include "chrome/browser/tab_contents/chrome_web_contents_view_delegate_mac.h" |
| #elif defined(OS_CHROMEOS) |
| #include "chrome/browser/chromeos/chrome_browser_main_chromeos.h" |
| #include "chrome/browser/chromeos/login/user_manager.h" |
| #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| #include "chrome/browser/chrome_browser_main_linux.h" |
| #elif defined(OS_POSIX) |
| #include "chrome/browser/chrome_browser_main_posix.h" |
| #endif |
| |
| #if defined(OS_WIN) && !defined(USE_AURA) |
| #include "chrome/browser/tab_contents/chrome_web_contents_view_delegate_win.h" |
| #endif |
| |
| #if defined(TOOLKIT_USES_GTK) |
| #include "chrome/browser/chrome_browser_main_extra_parts_gtk.h" |
| #endif |
| |
| #if defined(TOOLKIT_VIEWS) |
| #include "chrome/browser/chrome_browser_main_extra_parts_views.h" |
| #include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h" |
| #endif |
| |
| #if defined(USE_AURA) |
| #include "chrome/browser/chrome_browser_main_extra_parts_aura.h" |
| #endif |
| |
| #if defined(USE_ASH) |
| #include "chrome/browser/chrome_browser_main_extra_parts_ash.h" |
| #endif |
| |
| #if defined(OS_LINUX) || defined(OS_OPENBSD) |
| #include "base/linux_util.h" |
| #include "chrome/browser/crash_handler_host_linux.h" |
| #endif |
| |
| #if defined(TOOLKIT_GTK) |
| #include "chrome/browser/tab_contents/chrome_web_contents_view_delegate_gtk.h" |
| #endif |
| #if defined(USE_NSS) |
| #include "chrome/browser/ui/crypto_module_password_dialog.h" |
| #endif |
| |
| using content::AccessTokenStore; |
| using content::BrowserThread; |
| using content::BrowserURLHandler; |
| using content::ChildProcessSecurityPolicy; |
| using content::QuotaPermissionContext; |
| using content::RenderViewHost; |
| using content::SiteInstance; |
| using content::WebContents; |
| |
| namespace { |
| |
| const char* kPredefinedAllowedSocketOrigins[] = { |
| "okddffdblfhhnmhodogpojmfkjmhinfp", // Test SSH Client |
| "pnhechapfaindjhompbnflcldabbghjo" // HTerm App (SSH Client) |
| }; |
| |
| // Handles rewriting Web UI URLs. |
| bool HandleWebUI(GURL* url, content::BrowserContext* browser_context) { |
| if (!ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL( |
| browser_context, *url)) |
| return false; |
| |
| #if defined(OS_CHROMEOS) |
| // Special case : in ChromeOS in Guest mode bookmarks and history are |
| // disabled for security reasons. New tab page explains the reasons, so |
| // we redirect user to new tab page. |
| if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) { |
| if (url->SchemeIs(chrome::kChromeUIScheme) && |
| (url->DomainIs(chrome::kChromeUIBookmarksHost) || |
| url->DomainIs(chrome::kChromeUIHistoryHost))) { |
| // Rewrite with new tab URL |
| *url = GURL(chrome::kChromeUINewTabURL); |
| } |
| } |
| #endif |
| |
| // Special case the new tab page. In older versions of Chrome, the new tab |
| // page was hosted at chrome-internal:<blah>. This might be in people's saved |
| // sessions or bookmarks, so we say any URL with that scheme triggers the new |
| // tab page. |
| if (url->SchemeIs(chrome::kChromeInternalScheme)) { |
| // Rewrite it with the proper new tab URL. |
| *url = GURL(chrome::kChromeUINewTabURL); |
| } |
| |
| return true; |
| } |
| |
| // Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions |
| // below. Extension, and isolated apps require different privileges to be |
| // granted to their RenderProcessHosts. This classification allows us to make |
| // sure URLs are served by hosts with the right set of privileges. |
| enum RenderProcessHostPrivilege { |
| PRIV_NORMAL, |
| PRIV_HOSTED, |
| PRIV_ISOLATED, |
| PRIV_EXTENSION, |
| }; |
| |
| RenderProcessHostPrivilege GetPrivilegeRequiredByUrl( |
| const GURL& url, |
| ExtensionService* service) { |
| // Default to a normal renderer cause it is lower privileged. This should only |
| // occur if the URL on a site instance is either malformed, or uninitialized. |
| // If it is malformed, then there is no need for better privileges anyways. |
| // If it is uninitialized, but eventually settles on being an a scheme other |
| // than normal webrenderer, the navigation logic will correct us out of band |
| // anyways. |
| if (!url.is_valid()) |
| return PRIV_NORMAL; |
| |
| if (url.SchemeIs(chrome::kExtensionScheme)) { |
| const Extension* extension = |
| service->extensions()->GetByID(url.host()); |
| if (extension && extension->is_storage_isolated()) |
| return PRIV_ISOLATED; |
| if (extension && extension->is_hosted_app()) |
| return PRIV_HOSTED; |
| |
| return PRIV_EXTENSION; |
| } |
| |
| return PRIV_NORMAL; |
| } |
| |
| RenderProcessHostPrivilege GetProcessPrivilege( |
| content::RenderProcessHost* process_host, |
| extensions::ProcessMap* process_map, |
| ExtensionService* service) { |
| std::set<std::string> extension_ids = |
| process_map->GetExtensionsInProcess(process_host->GetID()); |
| if (extension_ids.empty()) |
| return PRIV_NORMAL; |
| |
| for (std::set<std::string>::iterator iter = extension_ids.begin(); |
| iter != extension_ids.end(); ++iter) { |
| const Extension* extension = service->GetExtensionById(*iter, false); |
| if (extension && extension->is_storage_isolated()) |
| return PRIV_ISOLATED; |
| if (extension && extension->is_hosted_app()) |
| return PRIV_HOSTED; |
| } |
| |
| return PRIV_EXTENSION; |
| } |
| |
| bool IsIsolatedAppInProcess(const GURL& site_url, |
| content::RenderProcessHost* process_host, |
| extensions::ProcessMap* process_map, |
| ExtensionService* service) { |
| std::set<std::string> extension_ids = |
| process_map->GetExtensionsInProcess(process_host->GetID()); |
| if (extension_ids.empty()) |
| return false; |
| |
| for (std::set<std::string>::iterator iter = extension_ids.begin(); |
| iter != extension_ids.end(); ++iter) { |
| const Extension* extension = service->GetExtensionById(*iter, false); |
| if (extension && |
| extension->is_storage_isolated() && |
| extension->url() == site_url) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool CertMatchesFilter(const net::X509Certificate& cert, |
| const base::DictionaryValue& filter) { |
| // TODO(markusheintz): This is the minimal required filter implementation. |
| // Implement a better matcher. |
| |
| // An empty filter matches any client certificate since no requirements are |
| // specified at all. |
| if (filter.empty()) |
| return true; |
| |
| std::string common_name; |
| if (filter.GetString("ISSUER.CN", &common_name) && |
| (cert.issuer().common_name == common_name)) { |
| return true; |
| } |
| return false; |
| } |
| |
| // Fills |map| with the per-script font prefs under path |map_name|. |
| void FillFontFamilyMap(const PrefService* prefs, |
| const char* map_name, |
| WebPreferences::ScriptFontFamilyMap* map) { |
| for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) { |
| const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i]; |
| std::string pref_name = base::StringPrintf("%s.%s", map_name, script); |
| std::string font_family = prefs->GetString(pref_name.c_str()); |
| if (!font_family.empty()) |
| map->push_back(std::make_pair(script, UTF8ToUTF16(font_family))); |
| } |
| } |
| |
| } // namespace |
| |
| namespace chrome { |
| |
| ChromeContentBrowserClient::ChromeContentBrowserClient() { |
| for (size_t i = 0; i < arraysize(kPredefinedAllowedSocketOrigins); ++i) |
| allowed_socket_origins_.insert(kPredefinedAllowedSocketOrigins[i]); |
| } |
| |
| ChromeContentBrowserClient::~ChromeContentBrowserClient() { |
| } |
| |
| content::BrowserMainParts* ChromeContentBrowserClient::CreateBrowserMainParts( |
| const content::MainFunctionParams& parameters) { |
| ChromeBrowserMainParts* main_parts; |
| // Construct the Main browser parts based on the OS type. |
| #if defined(OS_WIN) |
| main_parts = new ChromeBrowserMainPartsWin(parameters); |
| #elif defined(OS_MACOSX) |
| main_parts = new ChromeBrowserMainPartsMac(parameters); |
| #elif defined(OS_CHROMEOS) |
| main_parts = new ChromeBrowserMainPartsChromeos(parameters); |
| #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| main_parts = new ChromeBrowserMainPartsLinux(parameters); |
| #elif defined(OS_ANDROID) |
| // Do nothing for Android. |
| // TODO(klobag): Android initialization should use the |
| // *BrowserMainParts class-hierarchy for setting up custom initialization. |
| main_parts = NULL; |
| #elif defined(OS_POSIX) |
| main_parts = new ChromeBrowserMainPartsPosix(parameters); |
| #else |
| NOTREACHED(); |
| main_parts = new ChromeBrowserMainParts(parameters); |
| #endif |
| |
| // Construct additional browser parts. Stages are called in the order in |
| // which they are added. |
| #if defined(TOOLKIT_USES_GTK) |
| main_parts->AddParts(new ChromeBrowserMainExtraPartsGtk()); |
| #endif |
| |
| #if defined(TOOLKIT_VIEWS) |
| main_parts->AddParts(new ChromeBrowserMainExtraPartsViews()); |
| #endif |
| |
| #if defined(USE_AURA) |
| main_parts->AddParts(new ChromeBrowserMainExtraPartsAura()); |
| #endif |
| |
| #if defined(USE_ASH) |
| main_parts->AddParts(new ChromeBrowserMainExtraPartsAsh()); |
| #endif |
| |
| return main_parts; |
| } |
| |
| content::WebContentsView* |
| ChromeContentBrowserClient::OverrideCreateWebContentsView( |
| WebContents* web_contents) { |
| #if defined(TOOLKIT_VIEWS) |
| return new TabContentsViewViews(web_contents); |
| #endif |
| return NULL; |
| } |
| |
| content::WebContentsViewDelegate* |
| ChromeContentBrowserClient::GetWebContentsViewDelegate( |
| content::WebContents* web_contents) { |
| #if defined(OS_WIN) && !defined(USE_AURA) |
| return new ChromeWebContentsViewDelegateWin(web_contents); |
| #elif defined(TOOLKIT_GTK) |
| return new ChromeWebContentsViewDelegateGtk(web_contents); |
| #elif defined(OS_MACOSX) |
| return |
| chrome_web_contents_view_delegate_mac::CreateWebContentsViewDelegateMac( |
| web_contents); |
| #else |
| return NULL; |
| #endif |
| } |
| |
| void ChromeContentBrowserClient::RenderViewHostCreated( |
| RenderViewHost* render_view_host) { |
| |
| SiteInstance* site_instance = render_view_host->GetSiteInstance(); |
| Profile* profile = Profile::FromBrowserContext( |
| site_instance->GetBrowserContext()); |
| |
| new ChromeRenderViewHostObserver(render_view_host, |
| profile->GetNetworkPredictor()); |
| new ExtensionMessageHandler(render_view_host); |
| } |
| |
| void ChromeContentBrowserClient::RenderProcessHostCreated( |
| content::RenderProcessHost* host) { |
| int id = host->GetID(); |
| Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); |
| host->GetChannel()->AddFilter(new ChromeRenderMessageFilter( |
| id, profile, profile->GetRequestContextForRenderProcess(id))); |
| host->GetChannel()->AddFilter(new PluginInfoMessageFilter(id, profile)); |
| #if !defined(OS_ANDROID) |
| host->GetChannel()->AddFilter(new PrintingMessageFilter()); |
| #endif |
| host->GetChannel()->AddFilter( |
| new SearchProviderInstallStateMessageFilter(id, profile)); |
| host->GetChannel()->AddFilter(new SpellCheckMessageFilter(id)); |
| #if defined(OS_MACOSX) |
| host->GetChannel()->AddFilter(new SpellCheckMessageFilterMac()); |
| #endif |
| host->GetChannel()->AddFilter(new ChromeBenchmarkingMessageFilter( |
| id, profile, profile->GetRequestContextForRenderProcess(id))); |
| |
| host->Send(new ChromeViewMsg_SetIsIncognitoProcess( |
| profile->IsOffTheRecord())); |
| |
| SendExtensionWebRequestStatusToHost(host); |
| |
| RendererContentSettingRules rules; |
| GetRendererContentSettingRules(profile->GetHostContentSettingsMap(), &rules); |
| host->Send(new ChromeViewMsg_SetContentSettingRules(rules)); |
| } |
| |
| content::WebUIControllerFactory* |
| ChromeContentBrowserClient::GetWebUIControllerFactory() { |
| return ChromeWebUIControllerFactory::GetInstance(); |
| } |
| |
| GURL ChromeContentBrowserClient::GetEffectiveURL( |
| content::BrowserContext* browser_context, const GURL& url) { |
| Profile* profile = Profile::FromBrowserContext(browser_context); |
| // Get the effective URL for the given actual URL. If the URL is part of an |
| // installed app, the effective URL is an extension URL with the ID of that |
| // extension as the host. This has the effect of grouping apps together in |
| // a common SiteInstance. |
| if (!profile || !profile->GetExtensionService()) |
| return url; |
| |
| const Extension* extension = profile->GetExtensionService()->extensions()-> |
| GetHostedAppByURL(ExtensionURLInfo(url)); |
| if (!extension) |
| return url; |
| |
| // Bookmark apps do not use the hosted app process model, and should be |
| // treated as normal URLs. |
| if (extension->from_bookmark()) |
| return url; |
| |
| // If the URL is part of an extension's web extent, convert it to an |
| // extension URL. |
| return extension->GetResourceURL(url.path()); |
| } |
| |
| bool ChromeContentBrowserClient::ShouldUseProcessPerSite( |
| content::BrowserContext* browser_context, const GURL& effective_url) { |
| // Non-extension URLs should generally use process-per-site-instance. |
| // Because we expect to use the effective URL, URLs for hosted apps (apart |
| // from bookmark apps) should have an extension scheme by now. |
| if (!effective_url.SchemeIs(chrome::kExtensionScheme)) |
| return false; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context); |
| if (!profile || !profile->GetExtensionService()) |
| return false; |
| |
| const Extension* extension = profile->GetExtensionService()->extensions()-> |
| GetExtensionOrAppByURL(ExtensionURLInfo(effective_url)); |
| if (!extension) |
| return false; |
| |
| // If the URL is part of a hosted app that does not have the background |
| // permission, or that does not allow JavaScript access to the background |
| // page, we want to give each instance its own process to improve |
| // responsiveness. |
| if (extension->GetType() == Extension::TYPE_HOSTED_APP) { |
| if (!extension->HasAPIPermission(ExtensionAPIPermission::kBackground) || |
| !extension->allow_background_js_access()) { |
| return false; |
| } |
| } |
| |
| // Hosted apps that have script access to their background page must use |
| // process per site, since all instances can make synchronous calls to the |
| // background window. Other extensions should use process per site as well. |
| return true; |
| } |
| |
| bool ChromeContentBrowserClient::IsHandledURL(const GURL& url) { |
| return ProfileIOData::IsHandledURL(url); |
| } |
| |
| bool ChromeContentBrowserClient::IsSuitableHost( |
| content::RenderProcessHost* process_host, |
| const GURL& site_url) { |
| Profile* profile = |
| Profile::FromBrowserContext(process_host->GetBrowserContext()); |
| ExtensionService* service = profile->GetExtensionService(); |
| extensions::ProcessMap* process_map = service->process_map(); |
| |
| // Don't allow the Task Manager to share a process with anything else. |
| // Otherwise it can affect the renderers it is observing. |
| // Note: we could create another RenderProcessHostPrivilege bucket for |
| // this to allow multiple chrome://tasks instances to share, but that's |
| // a very unlikely case without serious consequences. |
| if (site_url.GetOrigin() == GURL(chrome::kChromeUITaskManagerURL).GetOrigin()) |
| return false; |
| |
| // These may be NULL during tests. In that case, just assume any site can |
| // share any host. |
| if (!service || !process_map) |
| return true; |
| |
| // Experimental: |
| // If --enable-strict-site-isolation is enabled, do not allow non-WebUI pages |
| // to share a renderer process. (We could allow pages from the same site or |
| // extensions of the same type to share, if we knew what the given process |
| // was dedicated to. Allowing no sharing is simpler for now.) This may |
| // cause resource exhaustion issues if too many sites are open at once. |
| const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| if (command_line.HasSwitch(switches::kEnableStrictSiteIsolation)) |
| return false; |
| |
| // An isolated app is only allowed to share with the exact same app in order |
| // to provide complete renderer process isolation. This also works around |
| // issue http://crbug.com/85588, where different isolated apps in the same |
| // process would end up using the first app's storage contexts. |
| RenderProcessHostPrivilege privilege_required = |
| GetPrivilegeRequiredByUrl(site_url, service); |
| if (privilege_required == PRIV_ISOLATED) |
| return IsIsolatedAppInProcess(site_url, process_host, process_map, service); |
| |
| // Otherwise, just make sure the process privilege matches the privilege |
| // required by the site. |
| return GetProcessPrivilege(process_host, process_map, service) == |
| privilege_required; |
| } |
| |
| // This function is trying to limit the amount of processes used by extensions |
| // with background pages. It uses a globally set percentage of processes to |
| // run such extensions and if the limit is exceeded, it returns true, to |
| // indicate to the content module to group extensions together. |
| bool ChromeContentBrowserClient::ShouldTryToUseExistingProcessHost( |
| content::BrowserContext* browser_context, const GURL& url) { |
| // It has to be a valid URL for us to check for an extension. |
| if (!url.is_valid()) |
| return false; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context); |
| ExtensionService* service = profile->GetExtensionService(); |
| if (!service) |
| return false; |
| |
| // We have to have a valid extension with background page to proceed. |
| const Extension* extension = |
| service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(url)); |
| if (!extension) |
| return false; |
| if (!extension->has_background_page()) |
| return false; |
| |
| std::set<int> process_ids; |
| size_t max_process_count = |
| content::RenderProcessHost::GetMaxRendererProcessCount(); |
| |
| // Go through all profiles to ensure we have total count of extension |
| // processes containing background pages, otherwise one profile can |
| // starve the other. |
| std::vector<Profile*> profiles = g_browser_process->profile_manager()-> |
| GetLoadedProfiles(); |
| for (size_t i = 0; i < profiles.size(); ++i) { |
| ExtensionProcessManager* epm = profiles[i]->GetExtensionProcessManager(); |
| for (ExtensionProcessManager::const_iterator iter = epm->begin(); |
| iter != epm->end(); |
| ++iter) { |
| ExtensionHost* host = *iter; |
| if (host->extension()->has_background_page()) { |
| process_ids.insert(host->render_process_host()->GetID()); |
| } |
| } |
| } |
| |
| if (process_ids.size() > |
| (max_process_count * chrome::kMaxShareOfExtensionProcesses)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void ChromeContentBrowserClient::SiteInstanceGotProcess( |
| SiteInstance* site_instance) { |
| CHECK(site_instance->HasProcess()); |
| |
| Profile* profile = Profile::FromBrowserContext( |
| site_instance->GetBrowserContext()); |
| ExtensionService* service = profile->GetExtensionService(); |
| if (!service) |
| return; |
| |
| const Extension* extension = |
| service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo( |
| site_instance->GetSite())); |
| if (!extension) |
| return; |
| |
| service->process_map()->Insert(extension->id(), |
| site_instance->GetProcess()->GetID(), |
| site_instance->GetId()); |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| base::Bind(&ExtensionInfoMap::RegisterExtensionProcess, |
| profile->GetExtensionInfoMap(), |
| extension->id(), |
| site_instance->GetProcess()->GetID(), |
| site_instance->GetId())); |
| } |
| |
| void ChromeContentBrowserClient::SiteInstanceDeleting( |
| SiteInstance* site_instance) { |
| if (!site_instance->HasProcess()) |
| return; |
| |
| Profile* profile = Profile::FromBrowserContext( |
| site_instance->GetBrowserContext()); |
| ExtensionService* service = profile->GetExtensionService(); |
| if (!service) |
| return; |
| |
| const Extension* extension = |
| service->extensions()->GetExtensionOrAppByURL( |
| ExtensionURLInfo(site_instance->GetSite())); |
| if (!extension) |
| return; |
| |
| service->process_map()->Remove(extension->id(), |
| site_instance->GetProcess()->GetID(), |
| site_instance->GetId()); |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| base::Bind(&ExtensionInfoMap::UnregisterExtensionProcess, |
| profile->GetExtensionInfoMap(), |
| extension->id(), |
| site_instance->GetProcess()->GetID(), |
| site_instance->GetId())); |
| } |
| |
| bool ChromeContentBrowserClient::ShouldSwapProcessesForNavigation( |
| const GURL& current_url, |
| const GURL& new_url) { |
| if (current_url.is_empty()) { |
| // Always choose a new process when navigating to extension URLs. The |
| // process grouping logic will combine all of a given extension's pages |
| // into the same process. |
| if (new_url.SchemeIs(chrome::kExtensionScheme)) |
| return true; |
| |
| return false; |
| } |
| |
| // Also, we must switch if one is an extension and the other is not the exact |
| // same extension. |
| if (current_url.SchemeIs(chrome::kExtensionScheme) || |
| new_url.SchemeIs(chrome::kExtensionScheme)) { |
| if (current_url.GetOrigin() != new_url.GetOrigin()) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| std::string ChromeContentBrowserClient::GetCanonicalEncodingNameByAliasName( |
| const std::string& alias_name) { |
| return CharacterEncoding::GetCanonicalEncodingNameByAliasName(alias_name); |
| } |
| |
| void ChromeContentBrowserClient::AppendExtraCommandLineSwitches( |
| CommandLine* command_line, int child_process_id) { |
| #if defined(USE_LINUX_BREAKPAD) |
| if (IsCrashReporterEnabled()) { |
| command_line->AppendSwitchASCII(switches::kEnableCrashReporter, |
| child_process_logging::GetClientId() + "," + base::GetLinuxDistro()); |
| } |
| #elif defined(OS_MACOSX) |
| if (IsCrashReporterEnabled()) { |
| command_line->AppendSwitchASCII(switches::kEnableCrashReporter, |
| child_process_logging::GetClientId()); |
| } |
| #endif // OS_MACOSX |
| |
| if (logging::DialogsAreSuppressed()) |
| command_line->AppendSwitch(switches::kNoErrorDialogs); |
| |
| std::string process_type = |
| command_line->GetSwitchValueASCII(switches::kProcessType); |
| const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); |
| if (process_type == switches::kRendererProcess) { |
| FilePath user_data_dir = |
| browser_command_line.GetSwitchValuePath(switches::kUserDataDir); |
| if (!user_data_dir.empty()) |
| command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir); |
| #if defined(OS_CHROMEOS) |
| const std::string& login_profile = |
| browser_command_line.GetSwitchValueASCII(switches::kLoginProfile); |
| if (!login_profile.empty()) |
| command_line->AppendSwitchASCII(switches::kLoginProfile, login_profile); |
| #endif |
| |
| content::RenderProcessHost* process = |
| content::RenderProcessHost::FromID(child_process_id); |
| if (process) { |
| Profile* profile = Profile::FromBrowserContext( |
| process->GetBrowserContext()); |
| extensions::ProcessMap* process_map = |
| profile->GetExtensionService()->process_map(); |
| if (process_map && process_map->Contains(process->GetID())) |
| command_line->AppendSwitch(switches::kExtensionProcess); |
| |
| PrefService* prefs = profile->GetPrefs(); |
| // Currently this pref is only registered if applied via a policy. |
| if (prefs->HasPrefPath(prefs::kDisable3DAPIs) && |
| prefs->GetBoolean(prefs::kDisable3DAPIs)) { |
| // Turn this policy into a command line switch. |
| command_line->AppendSwitch(switches::kDisable3DAPIs); |
| } |
| |
| // Disable client-side phishing detection in the renderer if it is |
| // disabled in the Profile preferences or the browser process. |
| if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled) || |
| !g_browser_process->safe_browsing_detection_service()) { |
| command_line->AppendSwitch( |
| switches::kDisableClientSidePhishingDetection); |
| } |
| } |
| { |
| PrefService* local_state = g_browser_process->local_state(); |
| if (local_state && |
| !local_state->GetBoolean(prefs::kPrintPreviewDisabled)) { |
| command_line->AppendSwitch(switches::kRendererPrintPreview); |
| } |
| } |
| |
| // Please keep this in alphabetical order. |
| static const char* const kSwitchNames[] = { |
| switches::kAllowHTTPBackgroundPage, |
| switches::kAllowLegacyExtensionManifests, |
| switches::kAllowScriptingGallery, |
| switches::kAppsCheckoutURL, |
| switches::kAppsGalleryURL, |
| switches::kCloudPrintServiceURL, |
| switches::kDebugPrint, |
| switches::kDisableBundledPpapiFlash, |
| switches::kDumpHistogramsOnExit, |
| switches::kEnableAsynchronousSpellChecking, |
| switches::kEnableBenchmarking, |
| switches::kEnableBundledPpapiFlash, |
| switches::kEnableCrxlessWebApps, |
| switches::kEnableExperimentalExtensionApis, |
| switches::kEnableInBrowserThumbnailing, |
| switches::kEnableIPCFuzzing, |
| switches::kEnableNaCl, |
| switches::kEnablePasswordGeneration, |
| switches::kEnablePlatformApps, |
| switches::kEnableWatchdog, |
| switches::kExperimentalSpellcheckerFeatures, |
| switches::kMemoryProfiling, |
| switches::kMessageLoopHistogrammer, |
| switches::kNoRunningInsecureContent, |
| switches::kPpapiFlashArgs, |
| switches::kPpapiFlashInProcess, |
| switches::kPpapiFlashPath, |
| switches::kPpapiFlashVersion, |
| switches::kProfilingAtStart, |
| switches::kProfilingFile, |
| switches::kProfilingFlush, |
| switches::kSilentDumpOnDCHECK, |
| switches::kWhitelistedExtensionID, |
| }; |
| |
| command_line->CopySwitchesFrom(browser_command_line, kSwitchNames, |
| arraysize(kSwitchNames)); |
| } else if (process_type == switches::kUtilityProcess) { |
| static const char* const kSwitchNames[] = { |
| switches::kEnableExperimentalExtensionApis, |
| switches::kWhitelistedExtensionID, |
| }; |
| |
| command_line->CopySwitchesFrom(browser_command_line, kSwitchNames, |
| arraysize(kSwitchNames)); |
| } else if (process_type == switches::kPluginProcess) { |
| static const char* const kSwitchNames[] = { |
| #if defined(OS_CHROMEOS) |
| switches::kLoginProfile, |
| #endif |
| switches::kMemoryProfiling, |
| switches::kSilentDumpOnDCHECK, |
| switches::kUserDataDir, |
| }; |
| |
| command_line->CopySwitchesFrom(browser_command_line, kSwitchNames, |
| arraysize(kSwitchNames)); |
| } else if (process_type == switches::kZygoteProcess) { |
| static const char* const kSwitchNames[] = { |
| switches::kUserDataDir, // Make logs go to the right file. |
| // Load (in-process) Pepper plugins in-process in the zygote pre-sandbox. |
| switches::kDisableBundledPpapiFlash, |
| switches::kEnableBundledPpapiFlash, |
| switches::kPpapiFlashInProcess, |
| switches::kPpapiFlashPath, |
| switches::kPpapiFlashVersion, |
| }; |
| |
| command_line->CopySwitchesFrom(browser_command_line, kSwitchNames, |
| arraysize(kSwitchNames)); |
| } else if (process_type == switches::kGpuProcess) { |
| // If --ignore-gpu-blacklist is passed in, don't send in crash reports |
| // because GPU is expected to be unreliable. |
| if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) && |
| !command_line->HasSwitch(switches::kDisableBreakpad)) |
| command_line->AppendSwitch(switches::kDisableBreakpad); |
| } |
| |
| // The command line switch kEnableBenchmarking needs to be specified along |
| // with the kEnableStatsTable switch to ensure that the stats table global |
| // is initialized correctly. |
| if (command_line->HasSwitch(switches::kEnableBenchmarking)) |
| DCHECK(command_line->HasSwitch(switches::kEnableStatsTable)); |
| } |
| |
| std::string ChromeContentBrowserClient::GetApplicationLocale() { |
| return g_browser_process->GetApplicationLocale(); |
| } |
| |
| std::string ChromeContentBrowserClient::GetAcceptLangs( |
| content::BrowserContext* context) { |
| Profile* profile = Profile::FromBrowserContext(context); |
| return profile->GetPrefs()->GetString(prefs::kAcceptLanguages); |
| } |
| |
| SkBitmap* ChromeContentBrowserClient::GetDefaultFavicon() { |
| ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| return rb.GetBitmapNamed(IDR_DEFAULT_FAVICON); |
| } |
| |
| bool ChromeContentBrowserClient::AllowAppCache( |
| const GURL& manifest_url, |
| const GURL& first_party, |
| content::ResourceContext* context) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| return io_data->GetCookieSettings()-> |
| IsSettingCookieAllowed(manifest_url, first_party); |
| } |
| |
| bool ChromeContentBrowserClient::AllowGetCookie( |
| const GURL& url, |
| const GURL& first_party, |
| const net::CookieList& cookie_list, |
| content::ResourceContext* context, |
| int render_process_id, |
| int render_view_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| bool allow = io_data->GetCookieSettings()-> |
| IsReadingCookieAllowed(url, first_party); |
| |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&TabSpecificContentSettings::CookiesRead, render_process_id, |
| render_view_id, url, cookie_list, !allow)); |
| return allow; |
| } |
| |
| bool ChromeContentBrowserClient::AllowSetCookie( |
| const GURL& url, |
| const GURL& first_party, |
| const std::string& cookie_line, |
| content::ResourceContext* context, |
| int render_process_id, |
| int render_view_id, |
| net::CookieOptions* options) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| CookieSettings* cookie_settings = io_data->GetCookieSettings(); |
| bool allow = cookie_settings->IsSettingCookieAllowed(url, first_party); |
| |
| if (cookie_settings->IsCookieSessionOnly(url)) |
| options->set_force_session(); |
| |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&TabSpecificContentSettings::CookieChanged, render_process_id, |
| render_view_id, url, cookie_line, *options, !allow)); |
| return allow; |
| } |
| |
| bool ChromeContentBrowserClient::AllowSaveLocalState( |
| content::ResourceContext* context) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| |
| if (!io_data->clear_local_state_on_exit()->GetValue()) |
| return true; |
| |
| // Disable clearing the local state on exit if the browsing session is going |
| // to be restored on the next startup. |
| SessionStartupPref::Type startup_pref = |
| SessionStartupPref::PrefValueToType( |
| io_data->session_startup_pref()->GetValue()); |
| return (startup_pref == SessionStartupPref::LAST && |
| !CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableRestoreSessionState)); |
| } |
| |
| bool ChromeContentBrowserClient::AllowWorkerDatabase( |
| const GURL& url, |
| const string16& name, |
| const string16& display_name, |
| unsigned long estimated_size, |
| content::ResourceContext* context, |
| const std::vector<std::pair<int, int> >& render_views) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| CookieSettings* cookie_settings = io_data->GetCookieSettings(); |
| bool allow = cookie_settings->IsSettingCookieAllowed(url, url); |
| |
| // Record access to database for potential display in UI. |
| std::vector<std::pair<int, int> >::const_iterator i; |
| for (i = render_views.begin(); i != render_views.end(); ++i) { |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&TabSpecificContentSettings::WebDatabaseAccessed, |
| i->first, i->second, url, name, display_name, !allow)); |
| } |
| |
| return allow; |
| } |
| |
| bool ChromeContentBrowserClient::AllowWorkerFileSystem( |
| const GURL& url, |
| content::ResourceContext* context, |
| const std::vector<std::pair<int, int> >& render_views) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| CookieSettings* cookie_settings = io_data->GetCookieSettings(); |
| bool allow = cookie_settings->IsSettingCookieAllowed(url, url); |
| |
| // Record access to file system for potential display in UI. |
| std::vector<std::pair<int, int> >::const_iterator i; |
| for (i = render_views.begin(); i != render_views.end(); ++i) { |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&TabSpecificContentSettings::FileSystemAccessed, |
| i->first, i->second, url, !allow)); |
| } |
| |
| return allow; |
| } |
| |
| bool ChromeContentBrowserClient::AllowWorkerIndexedDB( |
| const GURL& url, |
| const string16& name, |
| content::ResourceContext* context, |
| const std::vector<std::pair<int, int> >& render_views) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| CookieSettings* cookie_settings = io_data->GetCookieSettings(); |
| bool allow = cookie_settings->IsSettingCookieAllowed(url, url); |
| |
| // Record access to IndexedDB for potential display in UI. |
| std::vector<std::pair<int, int> >::const_iterator i; |
| for (i = render_views.begin(); i != render_views.end(); ++i) { |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&TabSpecificContentSettings::IndexedDBAccessed, |
| i->first, i->second, url, name, !allow)); |
| } |
| |
| return allow; |
| } |
| |
| net::URLRequestContext* |
| ChromeContentBrowserClient::OverrideRequestContextForURL( |
| const GURL& url, content::ResourceContext* context) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| if (url.SchemeIs(chrome::kExtensionScheme)) { |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| return io_data->extensions_request_context(); |
| } |
| |
| return NULL; |
| } |
| |
| QuotaPermissionContext* |
| ChromeContentBrowserClient::CreateQuotaPermissionContext() { |
| return new ChromeQuotaPermissionContext(); |
| } |
| |
| void ChromeContentBrowserClient::OpenItem(const FilePath& path) { |
| platform_util::OpenItem(path); |
| } |
| |
| void ChromeContentBrowserClient::ShowItemInFolder(const FilePath& path) { |
| platform_util::ShowItemInFolder(path); |
| } |
| |
| void ChromeContentBrowserClient::AllowCertificateError( |
| int render_process_id, |
| int render_view_id, |
| int cert_error, |
| const net::SSLInfo& ssl_info, |
| const GURL& request_url, |
| bool overridable, |
| const base::Callback<void(bool)>& callback, |
| bool* cancel_request) { |
| // If the tab is being prerendered, cancel the prerender and the request. |
| WebContents* tab = tab_util::GetWebContentsByID( |
| render_process_id, render_view_id); |
| if (!tab) { |
| NOTREACHED(); |
| return; |
| } |
| prerender::PrerenderManager* prerender_manager = |
| prerender::PrerenderManagerFactory::GetForProfile( |
| Profile::FromBrowserContext(tab->GetBrowserContext())); |
| if (prerender_manager && prerender_manager->IsWebContentsPrerendering(tab)) { |
| if (prerender_manager->prerender_tracker()->TryCancel( |
| render_process_id, render_view_id, |
| prerender::FINAL_STATUS_SSL_ERROR)) { |
| *cancel_request = true; |
| return; |
| } |
| } |
| |
| // Otherwise, display an SSL blocking page. |
| new SSLBlockingPage( |
| tab, cert_error, ssl_info, request_url, overridable, callback); |
| } |
| |
| void ChromeContentBrowserClient::SelectClientCertificate( |
| int render_process_id, |
| int render_view_id, |
| const net::HttpNetworkSession* network_session, |
| net::SSLCertRequestInfo* cert_request_info, |
| const base::Callback<void(net::X509Certificate*)>& callback) { |
| WebContents* tab = tab_util::GetWebContentsByID( |
| render_process_id, render_view_id); |
| if (!tab) { |
| NOTREACHED(); |
| return; |
| } |
| |
| GURL requesting_url("https://" + cert_request_info->host_and_port); |
| DCHECK(requesting_url.is_valid()) << "Invalid URL string: https://" |
| << cert_request_info->host_and_port; |
| |
| Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); |
| scoped_ptr<Value> filter( |
| profile->GetHostContentSettingsMap()->GetWebsiteSetting( |
| requesting_url, |
| requesting_url, |
| CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, |
| std::string(), NULL)); |
| |
| if (filter.get()) { |
| // Try to automatically select a client certificate. |
| if (filter->IsType(Value::TYPE_DICTIONARY)) { |
| DictionaryValue* filter_dict = |
| static_cast<DictionaryValue*>(filter.get()); |
| |
| const std::vector<scoped_refptr<net::X509Certificate> >& |
| all_client_certs = cert_request_info->client_certs; |
| for (size_t i = 0; i < all_client_certs.size(); ++i) { |
| if (CertMatchesFilter(*all_client_certs[i], *filter_dict)) { |
| // Use the first certificate that is matched by the filter. |
| callback.Run(all_client_certs[i]); |
| return; |
| } |
| } |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(tab); |
| if (!wrapper) { |
| // If there is no TabContentsWrapper for the given WebContents then we can't |
| // show the user a dialog to select a client certificate. So we simply |
| // proceed with no client certificate. |
| callback.Run(NULL); |
| return; |
| } |
| wrapper->ssl_helper()->ShowClientCertificateRequestDialog( |
| network_session, cert_request_info, callback); |
| } |
| |
| void ChromeContentBrowserClient::AddNewCertificate( |
| net::URLRequest* request, |
| net::X509Certificate* cert, |
| int render_process_id, |
| int render_view_id) { |
| // The handler will run the UI and delete itself when it's finished. |
| new SSLAddCertHandler(request, cert, render_process_id, render_view_id); |
| } |
| |
| void ChromeContentBrowserClient::RequestMediaAccessPermission( |
| const content::MediaStreamRequest* request, |
| const content::MediaResponseCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| WebContents* contents = tab_util::GetWebContentsByID( |
| request->render_process_id, request->render_view_id); |
| if (!contents) { |
| // Abort, if the tab was closed after the request was made but before we |
| // got to this point. |
| callback.Run(content::MediaStreamDevices()); |
| return; |
| } |
| |
| TabContentsWrapper* tab = |
| TabContentsWrapper::GetCurrentWrapperForContents(contents); |
| DCHECK(tab); |
| |
| InfoBarTabHelper* infobar_helper = tab->infobar_tab_helper(); |
| InfoBarDelegate* old_infobar = NULL; |
| for (size_t i = 0; i < infobar_helper->infobar_count() && !old_infobar; ++i) { |
| old_infobar = |
| infobar_helper->GetInfoBarDelegateAt(i)->AsMediaStreamInfobarDelegate(); |
| } |
| |
| #if defined(TOOLKIT_VIEWS) || defined(OS_LINUX) |
| InfoBarDelegate* infobar = new MediaStreamInfoBarDelegate(infobar_helper, |
| request, |
| callback); |
| if (old_infobar) |
| infobar_helper->ReplaceInfoBar(old_infobar, infobar); |
| else |
| infobar_helper->AddInfoBar(infobar); |
| #elif defined(OS_MACOSX) |
| // TODO(macourteau): UI is not implemented yet for OS X. Fallback to |
| // the default behaviour and allow access to the first device of each |
| // requested type. |
| content::MediaStreamDevices devices; |
| for (content::MediaStreamDeviceMap::const_iterator it = |
| request->devices.begin(); it != request->devices.end(); ++it) { |
| if (!it->second.empty()) |
| devices.push_back(*it->second.begin()); |
| } |
| |
| callback.Run(devices); |
| #endif // TOOLKIT_VIEWS || OS_LINUX |
| } |
| |
| void ChromeContentBrowserClient::RequestDesktopNotificationPermission( |
| const GURL& source_origin, |
| int callback_context, |
| int render_process_id, |
| int render_view_id) { |
| #if defined(ENABLE_NOTIFICATIONS) |
| RenderViewHost* rvh = RenderViewHost::FromID( |
| render_process_id, render_view_id); |
| if (!rvh) { |
| NOTREACHED(); |
| return; |
| } |
| |
| content::RenderProcessHost* process = rvh->GetProcess(); |
| Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); |
| DesktopNotificationService* service = |
| DesktopNotificationServiceFactory::GetForProfile(profile); |
| service->RequestPermission( |
| source_origin, render_process_id, render_view_id, callback_context, |
| tab_util::GetWebContentsByID(render_process_id, render_view_id)); |
| #else |
| NOTIMPLEMENTED(); |
| #endif |
| } |
| |
| WebKit::WebNotificationPresenter::Permission |
| ChromeContentBrowserClient::CheckDesktopNotificationPermission( |
| const GURL& source_origin, |
| content::ResourceContext* context, |
| int render_process_id) { |
| #if defined(ENABLE_NOTIFICATIONS) |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| if (io_data->GetExtensionInfoMap()->SecurityOriginHasAPIPermission( |
| source_origin, render_process_id, |
| ExtensionAPIPermission::kNotification)) |
| return WebKit::WebNotificationPresenter::PermissionAllowed; |
| |
| // Fall back to the regular notification preferences, which works on an |
| // origin basis. |
| return io_data->GetNotificationService() ? |
| io_data->GetNotificationService()->HasPermission(source_origin) : |
| WebKit::WebNotificationPresenter::PermissionNotAllowed; |
| #else |
| return WebKit::WebNotificationPresenter::PermissionAllowed; |
| #endif |
| } |
| |
| void ChromeContentBrowserClient::ShowDesktopNotification( |
| const content::ShowDesktopNotificationHostMsgParams& params, |
| int render_process_id, |
| int render_view_id, |
| bool worker) { |
| #if defined(ENABLE_NOTIFICATIONS) |
| RenderViewHost* rvh = RenderViewHost::FromID( |
| render_process_id, render_view_id); |
| if (!rvh) { |
| NOTREACHED(); |
| return; |
| } |
| |
| content::RenderProcessHost* process = rvh->GetProcess(); |
| Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); |
| DesktopNotificationService* service = |
| DesktopNotificationServiceFactory::GetForProfile(profile); |
| service->ShowDesktopNotification( |
| params, render_process_id, render_view_id, |
| worker ? DesktopNotificationService::WorkerNotification : |
| DesktopNotificationService::PageNotification); |
| #else |
| NOTIMPLEMENTED(); |
| #endif |
| } |
| |
| void ChromeContentBrowserClient::CancelDesktopNotification( |
| int render_process_id, |
| int render_view_id, |
| int notification_id) { |
| #if defined(ENABLE_NOTIFICATIONS) |
| RenderViewHost* rvh = RenderViewHost::FromID( |
| render_process_id, render_view_id); |
| if (!rvh) { |
| NOTREACHED(); |
| return; |
| } |
| |
| content::RenderProcessHost* process = rvh->GetProcess(); |
| Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); |
| DesktopNotificationService* service = |
| DesktopNotificationServiceFactory::GetForProfile(profile); |
| service->CancelDesktopNotification( |
| render_process_id, render_view_id, notification_id); |
| #else |
| NOTIMPLEMENTED(); |
| #endif |
| } |
| |
| bool ChromeContentBrowserClient::CanCreateWindow( |
| const GURL& opener_url, |
| const GURL& source_origin, |
| WindowContainerType container_type, |
| content::ResourceContext* context, |
| int render_process_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| // If the opener is trying to create a background window but doesn't have |
| // the appropriate permission, fail the attempt. |
| if (container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) { |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| ExtensionInfoMap* map = io_data->GetExtensionInfoMap(); |
| |
| // If the opener is not allowed to script its background window, then return |
| // false so that the window.open call returns null. In this case, only |
| // the manifest is permitted to create a background window. |
| // Note: this use of GetExtensionOrAppByURL is safe but imperfect. It may |
| // return a recently installed Extension even if this CanCreateWindow call |
| // was made by an old copy of the page in a normal web process. That's ok, |
| // because the permission check below will still fail. We must use the |
| // full URL to find hosted apps, though, and not just the origin. |
| const Extension* extension = map->extensions().GetExtensionOrAppByURL( |
| ExtensionURLInfo(opener_url)); |
| if (extension && !extension->allow_background_js_access()) |
| return false; |
| |
| return map->SecurityOriginHasAPIPermission( |
| source_origin, render_process_id, ExtensionAPIPermission::kBackground); |
| } |
| return true; |
| } |
| |
| std::string ChromeContentBrowserClient::GetWorkerProcessTitle( |
| const GURL& url, content::ResourceContext* context) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| // Check if it's an extension-created worker, in which case we want to use |
| // the name of the extension. |
| ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); |
| const Extension* extension = |
| io_data->GetExtensionInfoMap()->extensions().GetByID(url.host()); |
| return extension ? extension->name() : std::string(); |
| } |
| |
| void ChromeContentBrowserClient::ResourceDispatcherHostCreated() { |
| return g_browser_process->ResourceDispatcherHostCreated(); |
| } |
| |
| content::SpeechRecognitionManagerDelegate* |
| ChromeContentBrowserClient::GetSpeechRecognitionManagerDelegate() { |
| #if defined(ENABLE_INPUT_SPEECH) |
| return new speech::ChromeSpeechRecognitionManagerDelegate(); |
| #else |
| return NULL; |
| #endif |
| } |
| |
| ui::Clipboard* ChromeContentBrowserClient::GetClipboard() { |
| return g_browser_process->clipboard(); |
| } |
| |
| net::NetLog* ChromeContentBrowserClient::GetNetLog() { |
| return g_browser_process->net_log(); |
| } |
| |
| AccessTokenStore* ChromeContentBrowserClient::CreateAccessTokenStore() { |
| return new ChromeAccessTokenStore(); |
| } |
| |
| bool ChromeContentBrowserClient::IsFastShutdownPossible() { |
| const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); |
| return !browser_command_line.HasSwitch(switches::kChromeFrame); |
| } |
| |
| void ChromeContentBrowserClient::OverrideWebkitPrefs( |
| RenderViewHost* rvh, const GURL& url, WebPreferences* web_prefs) { |
| Profile* profile = Profile::FromBrowserContext( |
| rvh->GetProcess()->GetBrowserContext()); |
| PrefService* prefs = profile->GetPrefs(); |
| |
| web_prefs->standard_font_family = |
| UTF8ToUTF16(prefs->GetString(prefs::kWebKitGlobalStandardFontFamily)); |
| web_prefs->fixed_font_family = |
| UTF8ToUTF16(prefs->GetString(prefs::kWebKitGlobalFixedFontFamily)); |
| web_prefs->serif_font_family = |
| UTF8ToUTF16(prefs->GetString(prefs::kWebKitGlobalSerifFontFamily)); |
| web_prefs->sans_serif_font_family = |
| UTF8ToUTF16(prefs->GetString(prefs::kWebKitGlobalSansSerifFontFamily)); |
| web_prefs->cursive_font_family = |
| UTF8ToUTF16(prefs->GetString(prefs::kWebKitGlobalCursiveFontFamily)); |
| web_prefs->fantasy_font_family = |
| UTF8ToUTF16(prefs->GetString(prefs::kWebKitGlobalFantasyFontFamily)); |
| |
| FillFontFamilyMap(prefs, prefs::kWebKitStandardFontFamilyMap, |
| &web_prefs->standard_font_family_map); |
| FillFontFamilyMap(prefs, prefs::kWebKitFixedFontFamilyMap, |
| &web_prefs->fixed_font_family_map); |
| FillFontFamilyMap(prefs, prefs::kWebKitSerifFontFamilyMap, |
| &web_prefs->serif_font_family_map); |
| FillFontFamilyMap(prefs, prefs::kWebKitSansSerifFontFamilyMap, |
| &web_prefs->sans_serif_font_family_map); |
| FillFontFamilyMap(prefs, prefs::kWebKitCursiveFontFamilyMap, |
| &web_prefs->cursive_font_family_map); |
| FillFontFamilyMap(prefs, prefs::kWebKitFantasyFontFamilyMap, |
| &web_prefs->fantasy_font_family_map); |
| |
| web_prefs->default_font_size = |
| prefs->GetInteger(prefs::kWebKitGlobalDefaultFontSize); |
| web_prefs->default_fixed_font_size = |
| prefs->GetInteger(prefs::kWebKitGlobalDefaultFixedFontSize); |
| web_prefs->minimum_font_size = |
| prefs->GetInteger(prefs::kWebKitGlobalMinimumFontSize); |
| web_prefs->minimum_logical_font_size = |
| prefs->GetInteger(prefs::kWebKitGlobalMinimumLogicalFontSize); |
| |
| web_prefs->default_encoding = prefs->GetString(prefs::kGlobalDefaultCharset); |
| |
| web_prefs->javascript_can_open_windows_automatically = |
| prefs->GetBoolean( |
| prefs::kWebKitGlobalJavascriptCanOpenWindowsAutomatically); |
| web_prefs->dom_paste_enabled = |
| prefs->GetBoolean(prefs::kWebKitDomPasteEnabled); |
| web_prefs->shrinks_standalone_images_to_fit = |
| prefs->GetBoolean(prefs::kWebKitShrinksStandaloneImagesToFit); |
| const DictionaryValue* inspector_settings = |
| prefs->GetDictionary(prefs::kWebKitInspectorSettings); |
| if (inspector_settings) { |
| for (DictionaryValue::key_iterator iter(inspector_settings->begin_keys()); |
| iter != inspector_settings->end_keys(); ++iter) { |
| std::string value; |
| if (inspector_settings->GetStringWithoutPathExpansion(*iter, &value)) |
| web_prefs->inspector_settings.push_back( |
| std::make_pair(*iter, value)); |
| } |
| } |
| web_prefs->tabs_to_links = prefs->GetBoolean(prefs::kWebkitTabsToLinks); |
| |
| if (!prefs->GetBoolean(prefs::kWebKitGlobalJavascriptEnabled)) |
| web_prefs->javascript_enabled = false; |
| if (!prefs->GetBoolean(prefs::kWebKitWebSecurityEnabled)) |
| web_prefs->web_security_enabled = false; |
| if (!prefs->GetBoolean(prefs::kWebKitGlobalPluginsEnabled)) |
| web_prefs->plugins_enabled = false; |
| if (!prefs->GetBoolean(prefs::kWebKitJavaEnabled)) |
| web_prefs->java_enabled = false; |
| web_prefs->loads_images_automatically = |
| prefs->GetBoolean(prefs::kWebKitGlobalLoadsImagesAutomatically); |
| |
| if (prefs->GetBoolean(prefs::kDisable3DAPIs)) |
| web_prefs->experimental_webgl_enabled = false; |
| |
| web_prefs->memory_info_enabled = |
| prefs->GetBoolean(prefs::kEnableMemoryInfo); |
| web_prefs->allow_displaying_insecure_content = |
| prefs->GetBoolean(prefs::kWebKitAllowDisplayingInsecureContent); |
| web_prefs->allow_running_insecure_content = |
| prefs->GetBoolean(prefs::kWebKitAllowRunningInsecureContent); |
| web_prefs->password_echo_enabled = browser_defaults::kPasswordEchoEnabled; |
| |
| // The user stylesheet watcher may not exist in a testing profile. |
| if (profile->GetUserStyleSheetWatcher()) { |
| web_prefs->user_style_sheet_enabled = true; |
| web_prefs->user_style_sheet_location = |
| profile->GetUserStyleSheetWatcher()->user_style_sheet(); |
| } else { |
| web_prefs->user_style_sheet_enabled = false; |
| } |
| |
| web_prefs->asynchronous_spell_checking_enabled = |
| CommandLine::ForCurrentProcess()-> |
| HasSwitch(switches::kEnableAsynchronousSpellChecking); |
| web_prefs->unified_textchecker_enabled = |
| web_prefs->asynchronous_spell_checking_enabled || |
| CommandLine::ForCurrentProcess()-> |
| HasSwitch(switches::kExperimentalSpellcheckerFeatures); |
| |
| web_prefs->uses_universal_detector = |
| prefs->GetBoolean(prefs::kWebKitUsesUniversalDetector); |
| web_prefs->text_areas_are_resizable = |
| prefs->GetBoolean(prefs::kWebKitTextAreasAreResizable); |
| web_prefs->hyperlink_auditing_enabled = |
| prefs->GetBoolean(prefs::kEnableHyperlinkAuditing); |
| |
| // Make sure we will set the default_encoding with canonical encoding name. |
| web_prefs->default_encoding = |
| CharacterEncoding::GetCanonicalEncodingNameByAliasName( |
| web_prefs->default_encoding); |
| if (web_prefs->default_encoding.empty()) { |
| prefs->ClearPref(prefs::kGlobalDefaultCharset); |
| web_prefs->default_encoding = |
| prefs->GetString(prefs::kGlobalDefaultCharset); |
| } |
| DCHECK(!web_prefs->default_encoding.empty()); |
| |
| ExtensionService* service = profile->GetExtensionService(); |
| if (service) { |
| const Extension* extension = service->extensions()->GetByID( |
| rvh->GetSiteInstance()->GetSite().host()); |
| extension_webkit_preferences::SetPreferences( |
| extension, rvh->GetDelegate()->GetRenderViewType(), web_prefs); |
| } |
| |
| if (rvh->GetDelegate()->GetRenderViewType() == |
| chrome::VIEW_TYPE_NOTIFICATION) { |
| web_prefs->allow_scripts_to_close_windows = true; |
| } else if (rvh->GetDelegate()->GetRenderViewType() == |
| chrome::VIEW_TYPE_BACKGROUND_CONTENTS) { |
| // Disable all kinds of acceleration for background pages. |
| // See http://crbug.com/96005 and http://crbug.com/96006 |
| web_prefs->force_compositing_mode = false; |
| web_prefs->accelerated_compositing_enabled = false; |
| web_prefs->accelerated_2d_canvas_enabled = false; |
| web_prefs->accelerated_video_enabled = false; |
| web_prefs->accelerated_painting_enabled = false; |
| web_prefs->accelerated_plugins_enabled = false; |
| } |
| |
| #if defined(FILE_MANAGER_EXTENSION) |
| // Override the default of suppressing HW compositing for WebUI pages for the |
| // file manager, which is implemented using WebUI but wants HW acceleration |
| // for video decode & render. |
| if (url.spec() == chrome::kChromeUIFileManagerURL) { |
| web_prefs->accelerated_compositing_enabled = true; |
| web_prefs->accelerated_2d_canvas_enabled = true; |
| } |
| #endif |
| } |
| |
| void ChromeContentBrowserClient::UpdateInspectorSetting( |
| RenderViewHost* rvh, const std::string& key, const std::string& value) { |
| content::BrowserContext* browser_context = |
| rvh->GetProcess()->GetBrowserContext(); |
| DictionaryPrefUpdate update( |
| Profile::FromBrowserContext(browser_context)->GetPrefs(), |
| prefs::kWebKitInspectorSettings); |
| DictionaryValue* inspector_settings = update.Get(); |
| inspector_settings->SetWithoutPathExpansion(key, |
| Value::CreateStringValue(value)); |
| } |
| |
| void ChromeContentBrowserClient::ClearInspectorSettings(RenderViewHost* rvh) { |
| content::BrowserContext* browser_context = |
| rvh->GetProcess()->GetBrowserContext(); |
| Profile::FromBrowserContext(browser_context)->GetPrefs()-> |
| ClearPref(prefs::kWebKitInspectorSettings); |
| } |
| |
| void ChromeContentBrowserClient::BrowserURLHandlerCreated( |
| BrowserURLHandler* handler) { |
| // Add the default URL handlers. |
| handler->AddHandlerPair(&ExtensionWebUI::HandleChromeURLOverride, |
| BrowserURLHandler::null_handler()); |
| handler->AddHandlerPair(BrowserURLHandler::null_handler(), |
| &ExtensionWebUI::HandleChromeURLOverrideReverse); |
| |
| // about: handler. Must come before chrome: handler, since it will |
| // rewrite about: urls to chrome: URLs and then expect chrome: to |
| // actually handle them. |
| handler->AddHandlerPair(&WillHandleBrowserAboutURL, |
| BrowserURLHandler::null_handler()); |
| // chrome: & friends. |
| handler->AddHandlerPair(&HandleWebUI, |
| BrowserURLHandler::null_handler()); |
| } |
| |
| void ChromeContentBrowserClient::ClearCache(RenderViewHost* rvh) { |
| Profile* profile = Profile::FromBrowserContext( |
| rvh->GetSiteInstance()->GetProcess()->GetBrowserContext()); |
| BrowsingDataRemover* remover = new BrowsingDataRemover(profile, |
| BrowsingDataRemover::EVERYTHING, |
| base::Time()); |
| remover->Remove(BrowsingDataRemover::REMOVE_CACHE); |
| // BrowsingDataRemover takes care of deleting itself when done. |
| } |
| |
| void ChromeContentBrowserClient::ClearCookies(RenderViewHost* rvh) { |
| Profile* profile = Profile::FromBrowserContext( |
| rvh->GetSiteInstance()->GetProcess()->GetBrowserContext()); |
| BrowsingDataRemover* remover = new BrowsingDataRemover(profile, |
| BrowsingDataRemover::EVERYTHING, |
| base::Time()); |
| int remove_mask = BrowsingDataRemover::REMOVE_SITE_DATA; |
| remover->Remove(remove_mask); |
| // BrowsingDataRemover takes care of deleting itself when done. |
| } |
| |
| FilePath ChromeContentBrowserClient::GetDefaultDownloadDirectory() { |
| return download_util::GetDefaultDownloadDirectory(); |
| } |
| |
| std::string ChromeContentBrowserClient::GetDefaultDownloadName() { |
| return l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME); |
| } |
| |
| bool ChromeContentBrowserClient::AllowSocketAPI( |
| content::BrowserContext* browser_context, const GURL& url) { |
| if (!url.is_valid()) |
| return false; |
| |
| std::string host = url.host(); |
| if (allowed_socket_origins_.count(host)) |
| return true; |
| |
| // Need to check this now and not on construction because otherwise it won't |
| // work with browser_tests. |
| const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| std::string allowed_list = |
| command_line.GetSwitchValueASCII(switches::kAllowNaClSocketAPI); |
| if (!allowed_list.empty()) { |
| StringTokenizer t(allowed_list, ","); |
| while (t.GetNext()) { |
| if (t.token() == host) |
| return true; |
| } |
| } |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context); |
| if (!profile || !profile->GetExtensionService()) |
| return false; |
| |
| const Extension* extension = profile->GetExtensionService()->extensions()-> |
| GetExtensionOrAppByURL(ExtensionURLInfo(url)); |
| if (!extension) |
| return false; |
| |
| if (extension->HasAPIPermission(ExtensionAPIPermission::kSocket)) |
| return true; |
| |
| return false; |
| } |
| |
| #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| int ChromeContentBrowserClient::GetCrashSignalFD( |
| const CommandLine& command_line) { |
| #if defined(OS_ANDROID) |
| // TODO(carlosvaldivia): Upstream breakpad code for Android and remove this |
| // fork. http://crbug.com/113560 |
| NOTIMPLEMENTED(); |
| #else |
| if (command_line.HasSwitch(switches::kExtensionProcess)) { |
| ExtensionCrashHandlerHostLinux* crash_handler = |
| ExtensionCrashHandlerHostLinux::GetInstance(); |
| return crash_handler->GetDeathSignalSocket(); |
| } |
| |
| std::string process_type = |
| command_line.GetSwitchValueASCII(switches::kProcessType); |
| |
| if (process_type == switches::kRendererProcess) |
| return RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); |
| |
| if (process_type == switches::kPluginProcess) |
| return PluginCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); |
| |
| if (process_type == switches::kPpapiPluginProcess) |
| return PpapiCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); |
| |
| if (process_type == switches::kGpuProcess) |
| return GpuCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); |
| #endif // defined(OS_ANDROID) |
| |
| return -1; |
| } |
| #endif // defined(OS_POSIX) && !defined(OS_MACOSX) |
| |
| #if defined(OS_WIN) |
| const wchar_t* ChromeContentBrowserClient::GetResourceDllName() { |
| return chrome::kBrowserResourcesDll; |
| } |
| #endif |
| |
| #if defined(USE_NSS) |
| crypto::CryptoModuleBlockingPasswordDelegate* |
| ChromeContentBrowserClient::GetCryptoPasswordDelegate( |
| const GURL& url) { |
| return browser::NewCryptoModuleBlockingDialogDelegate( |
| browser::kCryptoModulePasswordKeygen, url.host()); |
| } |
| #endif |
| |
| } // namespace chrome |