Home | History | Annotate | Download | only in browser
      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