- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_web_contents_observer.cc
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