shell_content_browser_client.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/shell/browser/shell_content_browser_client.h" 6 7#include "base/command_line.h" 8#include "content/public/browser/browser_thread.h" 9#include "content/public/browser/render_process_host.h" 10#include "content/public/browser/site_instance.h" 11#include "content/public/common/content_switches.h" 12#include "content/public/common/url_constants.h" 13#include "content/shell/browser/shell_browser_context.h" 14#include "extensions/browser/extension_message_filter.h" 15#include "extensions/browser/extension_protocols.h" 16#include "extensions/browser/extension_registry.h" 17#include "extensions/browser/info_map.h" 18#include "extensions/browser/process_map.h" 19#include "extensions/common/constants.h" 20#include "extensions/common/extension.h" 21#include "extensions/common/switches.h" 22#include "extensions/shell/browser/shell_browser_context.h" 23#include "extensions/shell/browser/shell_browser_main_parts.h" 24#include "extensions/shell/browser/shell_extension_system.h" 25#include "url/gurl.h" 26 27#if !defined(DISABLE_NACL) 28#include "components/nacl/browser/nacl_browser.h" 29#include "components/nacl/browser/nacl_host_message_filter.h" 30#include "components/nacl/browser/nacl_process_host.h" 31#include "components/nacl/common/nacl_process_type.h" 32#include "components/nacl/common/nacl_switches.h" 33#include "content/public/browser/browser_child_process_host.h" 34#include "content/public/browser/child_process_data.h" 35#endif 36 37using base::CommandLine; 38using content::BrowserContext; 39using content::BrowserThread; 40 41namespace extensions { 42namespace { 43 44ShellContentBrowserClient* g_instance = NULL; 45 46} // namespace 47 48ShellContentBrowserClient::ShellContentBrowserClient( 49 ShellBrowserMainDelegate* browser_main_delegate) 50 : browser_main_parts_(NULL), browser_main_delegate_(browser_main_delegate) { 51 DCHECK(!g_instance); 52 g_instance = this; 53} 54 55ShellContentBrowserClient::~ShellContentBrowserClient() { 56 g_instance = NULL; 57} 58 59// static 60ShellContentBrowserClient* ShellContentBrowserClient::Get() { 61 return g_instance; 62} 63 64content::BrowserContext* ShellContentBrowserClient::GetBrowserContext() { 65 return browser_main_parts_->browser_context(); 66} 67 68content::BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts( 69 const content::MainFunctionParams& parameters) { 70 browser_main_parts_ = 71 new ShellBrowserMainParts(parameters, browser_main_delegate_); 72 return browser_main_parts_; 73} 74 75void ShellContentBrowserClient::RenderProcessWillLaunch( 76 content::RenderProcessHost* host) { 77 int render_process_id = host->GetID(); 78 BrowserContext* browser_context = browser_main_parts_->browser_context(); 79 host->AddFilter( 80 new ExtensionMessageFilter(render_process_id, browser_context)); 81 // PluginInfoMessageFilter is not required because app_shell does not have 82 // the concept of disabled plugins. 83#if !defined(DISABLE_NACL) 84 host->AddFilter(new nacl::NaClHostMessageFilter( 85 render_process_id, 86 browser_context->IsOffTheRecord(), 87 browser_context->GetPath(), 88 browser_context->GetRequestContextForRenderProcess(render_process_id))); 89#endif 90} 91 92bool ShellContentBrowserClient::ShouldUseProcessPerSite( 93 content::BrowserContext* browser_context, 94 const GURL& effective_url) { 95 // This ensures that all render views created for a single app will use the 96 // same render process (see content::SiteInstance::GetProcess). Otherwise the 97 // default behavior of ContentBrowserClient will lead to separate render 98 // processes for the background page and each app window view. 99 return true; 100} 101 102net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext( 103 content::BrowserContext* content_browser_context, 104 content::ProtocolHandlerMap* protocol_handlers, 105 content::URLRequestInterceptorScopedVector request_interceptors) { 106 // Handle only chrome-extension:// requests. app_shell does not support 107 // chrome-extension-resource:// requests (it does not store shared extension 108 // data in its installation directory). 109 InfoMap* extension_info_map = 110 browser_main_parts_->extension_system()->info_map(); 111 (*protocol_handlers)[kExtensionScheme] = 112 linked_ptr<net::URLRequestJobFactory::ProtocolHandler>( 113 CreateExtensionProtocolHandler(false /* is_incognito */, 114 extension_info_map)); 115 // Let content::ShellBrowserContext handle the rest of the setup. 116 return browser_main_parts_->browser_context()->CreateRequestContext( 117 protocol_handlers, request_interceptors.Pass()); 118} 119 120bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { 121 if (!url.is_valid()) 122 return false; 123 // Keep in sync with ProtocolHandlers added in CreateRequestContext() and in 124 // content::ShellURLRequestContextGetter::GetURLRequestContext(). 125 static const char* const kProtocolList[] = { 126 url::kBlobScheme, 127 content::kChromeDevToolsScheme, 128 content::kChromeUIScheme, 129 url::kDataScheme, 130 url::kFileScheme, 131 url::kFileSystemScheme, 132 kExtensionScheme, 133 kExtensionResourceScheme, 134 }; 135 for (size_t i = 0; i < arraysize(kProtocolList); ++i) { 136 if (url.scheme() == kProtocolList[i]) 137 return true; 138 } 139 return false; 140} 141 142void ShellContentBrowserClient::SiteInstanceGotProcess( 143 content::SiteInstance* site_instance) { 144 // If this isn't an extension renderer there's nothing to do. 145 const Extension* extension = GetExtension(site_instance); 146 if (!extension) 147 return; 148 149 ProcessMap::Get(browser_main_parts_->browser_context()) 150 ->Insert(extension->id(), 151 site_instance->GetProcess()->GetID(), 152 site_instance->GetId()); 153 154 BrowserThread::PostTask( 155 BrowserThread::IO, 156 FROM_HERE, 157 base::Bind(&InfoMap::RegisterExtensionProcess, 158 browser_main_parts_->extension_system()->info_map(), 159 extension->id(), 160 site_instance->GetProcess()->GetID(), 161 site_instance->GetId())); 162} 163 164void ShellContentBrowserClient::SiteInstanceDeleting( 165 content::SiteInstance* site_instance) { 166 // If this isn't an extension renderer there's nothing to do. 167 const Extension* extension = GetExtension(site_instance); 168 if (!extension) 169 return; 170 171 ProcessMap::Get(browser_main_parts_->browser_context()) 172 ->Remove(extension->id(), 173 site_instance->GetProcess()->GetID(), 174 site_instance->GetId()); 175 176 BrowserThread::PostTask( 177 BrowserThread::IO, 178 FROM_HERE, 179 base::Bind(&InfoMap::UnregisterExtensionProcess, 180 browser_main_parts_->extension_system()->info_map(), 181 extension->id(), 182 site_instance->GetProcess()->GetID(), 183 site_instance->GetId())); 184} 185 186void ShellContentBrowserClient::AppendExtraCommandLineSwitches( 187 CommandLine* command_line, 188 int child_process_id) { 189 std::string process_type = 190 command_line->GetSwitchValueASCII(::switches::kProcessType); 191 if (process_type == ::switches::kRendererProcess) 192 AppendRendererSwitches(command_line); 193} 194 195content::BrowserPpapiHost* 196ShellContentBrowserClient::GetExternalBrowserPpapiHost(int plugin_process_id) { 197#if !defined(DISABLE_NACL) 198 content::BrowserChildProcessHostIterator iter(PROCESS_TYPE_NACL_LOADER); 199 while (!iter.Done()) { 200 nacl::NaClProcessHost* host = static_cast<nacl::NaClProcessHost*>( 201 iter.GetDelegate()); 202 if (host->process() && 203 host->process()->GetData().id == plugin_process_id) { 204 // Found the plugin. 205 return host->browser_ppapi_host(); 206 } 207 ++iter; 208 } 209#endif 210 return NULL; 211} 212 213void ShellContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( 214 std::vector<std::string>* additional_allowed_schemes) { 215 ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( 216 additional_allowed_schemes); 217 additional_allowed_schemes->push_back(kExtensionScheme); 218} 219 220void ShellContentBrowserClient::AppendRendererSwitches( 221 CommandLine* command_line) { 222 // TODO(jamescook): Should we check here if the process is in the extension 223 // service process map, or can we assume all renderers are extension 224 // renderers? 225 command_line->AppendSwitch(switches::kExtensionProcess); 226 227#if !defined(DISABLE_NACL) 228 // NOTE: app_shell does not support non-SFI mode, so it does not pass through 229 // SFI switches either here or for the zygote process. 230 static const char* const kSwitchNames[] = { 231 ::switches::kEnableNaClDebug, 232 }; 233 command_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), 234 kSwitchNames, 235 arraysize(kSwitchNames)); 236#endif // !defined(DISABLE_NACL) 237} 238 239const Extension* ShellContentBrowserClient::GetExtension( 240 content::SiteInstance* site_instance) { 241 ExtensionRegistry* registry = 242 ExtensionRegistry::Get(site_instance->GetBrowserContext()); 243 return registry->enabled_extensions().GetExtensionOrAppByURL( 244 site_instance->GetSiteURL()); 245} 246 247} // namespace extensions 248