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