Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / plugin_manager.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 "base/files/file_path.h"
6 #include "base/lazy_instance.h"
7 #include "base/path_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/plugin_manager.h"
11 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/chrome_paths.h"
14 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
15 #include "chrome/common/extensions/manifest_handlers/mime_types_handler.h"
16 #include "content/public/browser/plugin_service.h"
17 #include "content/public/common/pepper_plugin_info.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/common/extension.h"
20 #include "url/gurl.h"
21
22 using content::PluginService;
23
24 #if !defined(DISABLE_NACL)
25 static const char kNaClPluginMimeType[] = "application/x-nacl";
26 #endif
27
28 namespace extensions {
29
30 PluginManager::PluginManager(content::BrowserContext* context)
31     : profile_(Profile::FromBrowserContext(context)),
32       extension_registry_observer_(this) {
33   extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
34 }
35
36 PluginManager::~PluginManager() {
37 }
38
39 static base::LazyInstance<BrowserContextKeyedAPIFactory<PluginManager> >
40     g_factory = LAZY_INSTANCE_INITIALIZER;
41
42 // static
43 BrowserContextKeyedAPIFactory<PluginManager>*
44 PluginManager::GetFactoryInstance() {
45   return g_factory.Pointer();
46 }
47
48 void PluginManager::OnExtensionLoaded(content::BrowserContext* browser_context,
49                                       const Extension* extension) {
50   bool plugins_or_nacl_changed = false;
51   if (PluginInfo::HasPlugins(extension)) {
52     const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension);
53     CHECK(plugins);
54     plugins_or_nacl_changed = true;
55     for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
56          plugin != plugins->end();
57          ++plugin) {
58       PluginService::GetInstance()->RefreshPlugins();
59       PluginService::GetInstance()->AddExtraPluginPath(plugin->path);
60       ChromePluginServiceFilter* filter =
61           ChromePluginServiceFilter::GetInstance();
62       if (plugin->is_public) {
63         filter->RestrictPluginToProfileAndOrigin(
64             plugin->path, profile_, GURL());
65       } else {
66         filter->RestrictPluginToProfileAndOrigin(
67             plugin->path, profile_, extension->url());
68       }
69     }
70   }
71
72 #if !defined(DISABLE_NACL)
73   const NaClModuleInfo::List* nacl_modules =
74       NaClModuleInfo::GetNaClModules(extension);
75   if (nacl_modules) {
76     plugins_or_nacl_changed = true;
77     for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
78          module != nacl_modules->end();
79          ++module) {
80       RegisterNaClModule(*module);
81     }
82     UpdatePluginListWithNaClModules();
83   }
84 #endif
85
86   const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
87   if (handler && !handler->handler_url().empty()) {
88     plugins_or_nacl_changed = true;
89
90     content::WebPluginInfo info;
91     info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
92     info.name = base::UTF8ToUTF16(handler->extension_id());
93     info.path = base::FilePath::FromUTF8Unsafe(handler->extension_id());
94
95     for (std::set<std::string>::const_iterator mime_type =
96          handler->mime_type_set().begin();
97          mime_type != handler->mime_type_set().end(); ++mime_type) {
98       content::WebPluginMimeType mime_type_info;
99       mime_type_info.mime_type = *mime_type;
100       info.mime_types.push_back(mime_type_info);
101     }
102
103     PluginService::GetInstance()->RefreshPlugins();
104     PluginService::GetInstance()->RegisterInternalPlugin(info, true);
105   }
106
107   if (plugins_or_nacl_changed)
108     PluginService::GetInstance()->PurgePluginListCache(profile_, false);
109 }
110
111 void PluginManager::OnExtensionUnloaded(
112     content::BrowserContext* browser_context,
113     const Extension* extension,
114     UnloadedExtensionInfo::Reason reason) {
115   bool plugins_or_nacl_changed = false;
116   if (PluginInfo::HasPlugins(extension)) {
117     const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension);
118     plugins_or_nacl_changed = true;
119     for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
120          plugin != plugins->end();
121          ++plugin) {
122       PluginService::GetInstance()->ForcePluginShutdown(plugin->path);
123       PluginService::GetInstance()->RefreshPlugins();
124       PluginService::GetInstance()->RemoveExtraPluginPath(plugin->path);
125       ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin->path);
126     }
127   }
128
129 #if !defined(DISABLE_NACL)
130   const NaClModuleInfo::List* nacl_modules =
131       NaClModuleInfo::GetNaClModules(extension);
132   if (nacl_modules) {
133     plugins_or_nacl_changed = true;
134     for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
135          module != nacl_modules->end();
136          ++module) {
137       UnregisterNaClModule(*module);
138     }
139     UpdatePluginListWithNaClModules();
140   }
141 #endif
142
143   const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
144   if (handler && !handler->handler_url().empty()) {
145     plugins_or_nacl_changed = true;
146     base::FilePath path =
147         base::FilePath::FromUTF8Unsafe(handler->extension_id());
148     PluginService::GetInstance()->UnregisterInternalPlugin(path);
149     PluginService::GetInstance()->ForcePluginShutdown(path);
150     PluginService::GetInstance()->RefreshPlugins();
151   }
152
153   if (plugins_or_nacl_changed)
154     PluginService::GetInstance()->PurgePluginListCache(profile_, false);
155 }
156
157 #if !defined(DISABLE_NACL)
158
159 void PluginManager::RegisterNaClModule(const NaClModuleInfo& info) {
160   DCHECK(FindNaClModule(info.url) == nacl_module_list_.end());
161   nacl_module_list_.push_front(info);
162 }
163
164 void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) {
165   NaClModuleInfo::List::iterator iter = FindNaClModule(info.url);
166   DCHECK(iter != nacl_module_list_.end());
167   nacl_module_list_.erase(iter);
168 }
169
170 void PluginManager::UpdatePluginListWithNaClModules() {
171   // An extension has been added which has a nacl_module component, which means
172   // there is a MIME type that module wants to handle, so we need to add that
173   // MIME type to plugins which handle NaCl modules in order to allow the
174   // individual modules to handle these types.
175   base::FilePath path;
176   if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path))
177     return;
178   const content::PepperPluginInfo* pepper_info =
179       PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
180   if (!pepper_info)
181     return;
182
183   std::vector<content::WebPluginMimeType>::const_iterator mime_iter;
184   // Check each MIME type the plugins handle for the NaCl MIME type.
185   for (mime_iter = pepper_info->mime_types.begin();
186        mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
187     if (mime_iter->mime_type == kNaClPluginMimeType) {
188       // This plugin handles "application/x-nacl".
189
190       PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path);
191
192       content::WebPluginInfo info = pepper_info->ToWebPluginInfo();
193
194       for (NaClModuleInfo::List::const_iterator iter =
195                nacl_module_list_.begin();
196            iter != nacl_module_list_.end(); ++iter) {
197         // Add the MIME type specified in the extension to this NaCl plugin,
198         // With an extra "nacl" argument to specify the location of the NaCl
199         // manifest file.
200         content::WebPluginMimeType mime_type_info;
201         mime_type_info.mime_type = iter->mime_type;
202         mime_type_info.additional_param_names.push_back(
203             base::UTF8ToUTF16("nacl"));
204         mime_type_info.additional_param_values.push_back(
205             base::UTF8ToUTF16(iter->url.spec()));
206         info.mime_types.push_back(mime_type_info);
207       }
208
209       PluginService::GetInstance()->RefreshPlugins();
210       PluginService::GetInstance()->RegisterInternalPlugin(info, true);
211       // This plugin has been modified, no need to check the rest of its
212       // types, but continue checking other plugins.
213       break;
214     }
215   }
216 }
217
218 NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) {
219   for (NaClModuleInfo::List::iterator iter = nacl_module_list_.begin();
220        iter != nacl_module_list_.end(); ++iter) {
221     if (iter->url == url)
222       return iter;
223   }
224   return nacl_module_list_.end();
225 }
226
227 #endif  // !defined(DISABLE_NACL)
228
229 }  // namespace extensions