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