• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/plugins/plugin_finder.h"
6 
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/stl_util.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/plugins/plugin_metadata.h"
18 #include "chrome/common/pref_names.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/plugin_service.h"
21 #include "grit/browser_resources.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "url/gurl.h"
24 
25 #if defined(ENABLE_PLUGIN_INSTALLATION)
26 #include "chrome/browser/plugins/plugin_installer.h"
27 #endif
28 
29 using base::DictionaryValue;
30 using content::PluginService;
31 
32 namespace {
33 
34 typedef std::map<std::string, PluginMetadata*> PluginMap;
35 
36 // Gets the full path of the plug-in file as the identifier.
GetLongIdentifier(const content::WebPluginInfo & plugin)37 std::string GetLongIdentifier(const content::WebPluginInfo& plugin) {
38   return plugin.path.AsUTF8Unsafe();
39 }
40 
41 // Gets the base name of the file path as the identifier.
GetIdentifier(const content::WebPluginInfo & plugin)42 std::string GetIdentifier(const content::WebPluginInfo& plugin) {
43   return plugin.path.BaseName().AsUTF8Unsafe();
44 }
45 
46 // Gets the plug-in group name as the plug-in name if it is not empty or
47 // the filename without extension if the name is empty.
GetGroupName(const content::WebPluginInfo & plugin)48 static base::string16 GetGroupName(const content::WebPluginInfo& plugin) {
49   if (!plugin.name.empty())
50     return plugin.name;
51 
52   return plugin.path.BaseName().RemoveExtension().AsUTF16Unsafe();
53 }
54 
LoadMimeTypes(bool matching_mime_types,const base::DictionaryValue * plugin_dict,PluginMetadata * plugin)55 void LoadMimeTypes(bool matching_mime_types,
56                    const base::DictionaryValue* plugin_dict,
57                    PluginMetadata* plugin) {
58   const base::ListValue* mime_types = NULL;
59   std::string list_key =
60       matching_mime_types ? "matching_mime_types" : "mime_types";
61   if (!plugin_dict->GetList(list_key, &mime_types))
62     return;
63 
64   bool success = false;
65   for (base::ListValue::const_iterator mime_type_it = mime_types->begin();
66        mime_type_it != mime_types->end(); ++mime_type_it) {
67     std::string mime_type_str;
68     success = (*mime_type_it)->GetAsString(&mime_type_str);
69     DCHECK(success);
70     if (matching_mime_types) {
71       plugin->AddMatchingMimeType(mime_type_str);
72     } else {
73       plugin->AddMimeType(mime_type_str);
74     }
75   }
76 }
77 
CreatePluginMetadata(const std::string & identifier,const base::DictionaryValue * plugin_dict)78 PluginMetadata* CreatePluginMetadata(
79     const std::string& identifier,
80     const base::DictionaryValue* plugin_dict) {
81   std::string url;
82   bool success = plugin_dict->GetString("url", &url);
83   std::string help_url;
84   plugin_dict->GetString("help_url", &help_url);
85   base::string16 name;
86   success = plugin_dict->GetString("name", &name);
87   DCHECK(success);
88   bool display_url = false;
89   plugin_dict->GetBoolean("displayurl", &display_url);
90   base::string16 group_name_matcher;
91   success = plugin_dict->GetString("group_name_matcher", &group_name_matcher);
92   DCHECK(success);
93   std::string language_str;
94   plugin_dict->GetString("lang", &language_str);
95 
96   PluginMetadata* plugin = new PluginMetadata(identifier,
97                                               name,
98                                               display_url,
99                                               GURL(url),
100                                               GURL(help_url),
101                                               group_name_matcher,
102                                               language_str);
103   const base::ListValue* versions = NULL;
104   if (plugin_dict->GetList("versions", &versions)) {
105     for (base::ListValue::const_iterator it = versions->begin();
106          it != versions->end(); ++it) {
107       base::DictionaryValue* version_dict = NULL;
108       if (!(*it)->GetAsDictionary(&version_dict)) {
109         NOTREACHED();
110         continue;
111       }
112       std::string version;
113       success = version_dict->GetString("version", &version);
114       DCHECK(success);
115       std::string status_str;
116       success = version_dict->GetString("status", &status_str);
117       DCHECK(success);
118       PluginMetadata::SecurityStatus status =
119           PluginMetadata::SECURITY_STATUS_UP_TO_DATE;
120       success = PluginMetadata::ParseSecurityStatus(status_str, &status);
121       DCHECK(success);
122       plugin->AddVersion(Version(version), status);
123     }
124   }
125 
126   LoadMimeTypes(false, plugin_dict, plugin);
127   LoadMimeTypes(true, plugin_dict, plugin);
128   return plugin;
129 }
130 
131 }  // namespace
132 
133 // static
RegisterPrefs(PrefRegistrySimple * registry)134 void PluginFinder::RegisterPrefs(PrefRegistrySimple* registry) {
135   registry->RegisterBooleanPref(prefs::kDisablePluginFinder, false);
136 }
137 
138 // static
GetInstance()139 PluginFinder* PluginFinder::GetInstance() {
140   // PluginFinder::GetInstance() is the only method that's allowed to call
141   // Singleton<PluginFinder>::get().
142   return Singleton<PluginFinder>::get();
143 }
144 
PluginFinder()145 PluginFinder::PluginFinder() : version_(-1) {
146   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
147 }
148 
Init()149 void PluginFinder::Init() {
150   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
151   // Load the built-in plug-in list first. If we have a newer version stored
152   // locally or download one, we will replace this one with it.
153   scoped_ptr<base::DictionaryValue> plugin_list(LoadBuiltInPluginList());
154   DCHECK(plugin_list);
155   ReinitializePlugins(plugin_list.get());
156 }
157 
158 // static
LoadBuiltInPluginList()159 base::DictionaryValue* PluginFinder::LoadBuiltInPluginList() {
160   base::StringPiece json_resource(
161       ResourceBundle::GetSharedInstance().GetRawDataResource(
162           IDR_PLUGIN_DB_JSON));
163   std::string error_str;
164   scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
165       json_resource,
166       base::JSON_PARSE_RFC,
167       NULL,
168       &error_str));
169   if (!value.get()) {
170     DLOG(ERROR) << error_str;
171     return NULL;
172   }
173   if (value->GetType() != base::Value::TYPE_DICTIONARY)
174     return NULL;
175   return static_cast<base::DictionaryValue*>(value.release());
176 }
177 
~PluginFinder()178 PluginFinder::~PluginFinder() {
179 #if defined(ENABLE_PLUGIN_INSTALLATION)
180   STLDeleteValues(&installers_);
181 #endif
182   STLDeleteValues(&identifier_plugin_);
183 }
184 
185 #if defined(ENABLE_PLUGIN_INSTALLATION)
FindPlugin(const std::string & mime_type,const std::string & language,PluginInstaller ** installer,scoped_ptr<PluginMetadata> * plugin_metadata)186 bool PluginFinder::FindPlugin(
187     const std::string& mime_type,
188     const std::string& language,
189     PluginInstaller** installer,
190     scoped_ptr<PluginMetadata>* plugin_metadata) {
191   if (g_browser_process->local_state()->GetBoolean(prefs::kDisablePluginFinder))
192     return false;
193 
194   base::AutoLock lock(mutex_);
195   PluginMap::const_iterator metadata_it = identifier_plugin_.begin();
196   for (; metadata_it != identifier_plugin_.end(); ++metadata_it) {
197     if (language == metadata_it->second->language() &&
198         metadata_it->second->HasMimeType(mime_type)) {
199       *plugin_metadata = metadata_it->second->Clone();
200 
201       std::map<std::string, PluginInstaller*>::const_iterator installer_it =
202           installers_.find(metadata_it->second->identifier());
203       DCHECK(installer_it != installers_.end());
204       *installer = installer_it->second;
205       return true;
206     }
207   }
208   return false;
209 }
210 
FindPluginWithIdentifier(const std::string & identifier,PluginInstaller ** installer,scoped_ptr<PluginMetadata> * plugin_metadata)211 bool PluginFinder::FindPluginWithIdentifier(
212     const std::string& identifier,
213     PluginInstaller** installer,
214     scoped_ptr<PluginMetadata>* plugin_metadata) {
215   base::AutoLock lock(mutex_);
216   PluginMap::const_iterator metadata_it = identifier_plugin_.find(identifier);
217   if (metadata_it == identifier_plugin_.end())
218     return false;
219   *plugin_metadata = metadata_it->second->Clone();
220 
221   if (installer) {
222     std::map<std::string, PluginInstaller*>::const_iterator installer_it =
223         installers_.find(identifier);
224     if (installer_it == installers_.end())
225       return false;
226     *installer = installer_it->second;
227   }
228   return true;
229 }
230 #endif
231 
ReinitializePlugins(const base::DictionaryValue * plugin_list)232 void PluginFinder::ReinitializePlugins(
233     const base::DictionaryValue* plugin_list) {
234   base::AutoLock lock(mutex_);
235   int version = 0;  // If no version is defined, we default to 0.
236   const char kVersionKey[] = "x-version";
237   plugin_list->GetInteger(kVersionKey, &version);
238   if (version <= version_)
239     return;
240 
241   version_ = version;
242 
243   STLDeleteValues(&identifier_plugin_);
244   identifier_plugin_.clear();
245 
246   for (base::DictionaryValue::Iterator plugin_it(*plugin_list);
247       !plugin_it.IsAtEnd(); plugin_it.Advance()) {
248     const base::DictionaryValue* plugin = NULL;
249     const std::string& identifier = plugin_it.key();
250     if (plugin_list->GetDictionaryWithoutPathExpansion(identifier, &plugin)) {
251       DCHECK(!identifier_plugin_[identifier]);
252       identifier_plugin_[identifier] = CreatePluginMetadata(identifier, plugin);
253 
254 #if defined(ENABLE_PLUGIN_INSTALLATION)
255       if (installers_.find(identifier) == installers_.end())
256         installers_[identifier] = new PluginInstaller();
257 #endif
258     }
259   }
260 }
261 
FindPluginNameWithIdentifier(const std::string & identifier)262 base::string16 PluginFinder::FindPluginNameWithIdentifier(
263     const std::string& identifier) {
264   base::AutoLock lock(mutex_);
265   PluginMap::const_iterator it = identifier_plugin_.find(identifier);
266   base::string16 name;
267   if (it != identifier_plugin_.end())
268     name = it->second->name();
269 
270   return name.empty() ? base::UTF8ToUTF16(identifier) : name;
271 }
272 
GetPluginMetadata(const content::WebPluginInfo & plugin)273 scoped_ptr<PluginMetadata> PluginFinder::GetPluginMetadata(
274     const content::WebPluginInfo& plugin) {
275   base::AutoLock lock(mutex_);
276   for (PluginMap::const_iterator it = identifier_plugin_.begin();
277        it != identifier_plugin_.end(); ++it) {
278     if (!it->second->MatchesPlugin(plugin))
279       continue;
280 
281     return it->second->Clone();
282   }
283 
284   // The plug-in metadata was not found, create a dummy one holding
285   // the name, identifier and group name only.
286   std::string identifier = GetIdentifier(plugin);
287   PluginMetadata* metadata = new PluginMetadata(identifier,
288                                                 GetGroupName(plugin),
289                                                 false,
290                                                 GURL(),
291                                                 GURL(),
292                                                 plugin.name,
293                                                 std::string());
294   for (size_t i = 0; i < plugin.mime_types.size(); ++i)
295     metadata->AddMatchingMimeType(plugin.mime_types[i].mime_type);
296 
297   DCHECK(metadata->MatchesPlugin(plugin));
298   if (identifier_plugin_.find(identifier) != identifier_plugin_.end())
299     identifier = GetLongIdentifier(plugin);
300 
301   DCHECK(identifier_plugin_.find(identifier) == identifier_plugin_.end());
302   identifier_plugin_[identifier] = metadata;
303   return metadata->Clone();
304 }
305