Home | History | Annotate | Download | only in extensions
      1 // Copyright 2013 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 "chrome/browser/extensions/extension_web_contents_observer.h"
      6 
      7 #include "chrome/browser/extensions/api/messaging/message_service.h"
      8 #include "chrome/browser/extensions/extension_service.h"
      9 #include "chrome/browser/extensions/extension_system.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/common/extensions/api/messaging/message.h"
     12 #include "chrome/common/extensions/extension_messages.h"
     13 #include "chrome/common/url_constants.h"
     14 #include "content/public/browser/child_process_security_policy.h"
     15 #include "content/public/browser/render_process_host.h"
     16 #include "content/public/browser/render_view_host.h"
     17 #include "content/public/browser/site_instance.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "extensions/browser/view_type_utils.h"
     20 #include "extensions/common/constants.h"
     21 
     22 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::ExtensionWebContentsObserver);
     23 
     24 namespace extensions {
     25 
     26 ExtensionWebContentsObserver::ExtensionWebContentsObserver(
     27     content::WebContents* web_contents)
     28     : content::WebContentsObserver(web_contents),
     29       profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())) {
     30 }
     31 
     32 ExtensionWebContentsObserver::~ExtensionWebContentsObserver() {
     33 }
     34 
     35 void ExtensionWebContentsObserver::RenderViewCreated(
     36     content::RenderViewHost* render_view_host) {
     37   render_view_host->Send(new ExtensionMsg_NotifyRenderViewType(
     38       render_view_host->GetRoutingID(),
     39       extensions::GetViewType(web_contents())));
     40 
     41   const Extension* extension = GetExtension(render_view_host);
     42   if (!extension)
     43     return;
     44 
     45   content::RenderProcessHost* process = render_view_host->GetProcess();
     46 
     47   // Some extensions use chrome:// URLs.
     48   // This is a temporary solution. Replace it with access to chrome-static://
     49   // once it is implemented. See: crbug.com/226927.
     50   Manifest::Type type = extension->GetType();
     51   if (type == Manifest::TYPE_EXTENSION ||
     52       type == Manifest::TYPE_LEGACY_PACKAGED_APP ||
     53       (type == Manifest::TYPE_PLATFORM_APP &&
     54        extension->location() == Manifest::COMPONENT)) {
     55     content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
     56         process->GetID(), chrome::kChromeUIScheme);
     57   }
     58 
     59   // Some extensions use file:// URLs.
     60   if (type == Manifest::TYPE_EXTENSION ||
     61       type == Manifest::TYPE_LEGACY_PACKAGED_APP) {
     62     if (ExtensionSystem::Get(profile_)->extension_service()->
     63             extension_prefs()->AllowFileAccess(extension->id())) {
     64       content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
     65           process->GetID(), chrome::kFileScheme);
     66     }
     67   }
     68 
     69   switch (type) {
     70     case Manifest::TYPE_EXTENSION:
     71     case Manifest::TYPE_USER_SCRIPT:
     72     case Manifest::TYPE_HOSTED_APP:
     73     case Manifest::TYPE_LEGACY_PACKAGED_APP:
     74     case Manifest::TYPE_PLATFORM_APP:
     75       // Always send a Loaded message before ActivateExtension so that
     76       // ExtensionDispatcher knows what Extension is active, not just its ID.
     77       // This is important for classifying the Extension's JavaScript context
     78       // correctly (see ExtensionDispatcher::ClassifyJavaScriptContext).
     79       render_view_host->Send(new ExtensionMsg_Loaded(
     80           std::vector<ExtensionMsg_Loaded_Params>(
     81               1, ExtensionMsg_Loaded_Params(extension))));
     82       render_view_host->Send(
     83           new ExtensionMsg_ActivateExtension(extension->id()));
     84       break;
     85 
     86     case Manifest::TYPE_UNKNOWN:
     87     case Manifest::TYPE_THEME:
     88     case Manifest::TYPE_SHARED_MODULE:
     89       break;
     90   }
     91 }
     92 
     93 bool ExtensionWebContentsObserver::OnMessageReceived(
     94     const IPC::Message& message) {
     95   bool handled = true;
     96   IPC_BEGIN_MESSAGE_MAP(ExtensionWebContentsObserver, message)
     97     IPC_MESSAGE_HANDLER(ExtensionHostMsg_PostMessage, OnPostMessage)
     98     IPC_MESSAGE_UNHANDLED(handled = false)
     99   IPC_END_MESSAGE_MAP()
    100   return handled;
    101 }
    102 
    103 void ExtensionWebContentsObserver::OnPostMessage(int port_id,
    104                                                  const Message& message) {
    105   MessageService* message_service = MessageService::Get(profile_);
    106   if (message_service) {
    107     message_service->PostMessage(port_id, message);
    108   }
    109 }
    110 
    111 const Extension* ExtensionWebContentsObserver::GetExtension(
    112     content::RenderViewHost* render_view_host) {
    113   // Note that due to ChromeContentBrowserClient::GetEffectiveURL(), hosted apps
    114   // (excluding bookmark apps) will have a chrome-extension:// URL for their
    115   // site, so we can ignore that wrinkle here.
    116   content::SiteInstance* site_instance = render_view_host->GetSiteInstance();
    117   const GURL& site = site_instance->GetSiteURL();
    118 
    119   if (!site.SchemeIs(kExtensionScheme))
    120     return NULL;
    121 
    122   ExtensionService* service = profile_->GetExtensionService();
    123   if (!service)
    124     return NULL;
    125 
    126   // Reload the extension if it has crashed.
    127   // TODO(yoz): This reload doesn't happen synchronously for unpacked
    128   //            extensions. It seems to be fast enough, but there is a race.
    129   //            We should delay loading until the extension has reloaded.
    130   if (service->GetTerminatedExtension(site.host()))
    131     service->ReloadExtension(site.host());
    132 
    133   // May be null if the extension doesn't exist, for example if somebody typos
    134   // a chrome-extension:// URL.
    135   return service->extensions()->GetByID(site.host());
    136 }
    137 
    138 }  // namespace extensions
    139