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