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