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