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.
5 #include "chrome/browser/plugins/plugin_finder.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"
25 #if defined(ENABLE_PLUGIN_INSTALLATION)
26 #include "chrome/browser/plugins/plugin_installer.h"
29 using base::DictionaryValue
;
30 using content::PluginService
;
34 typedef std::map
<std::string
, PluginMetadata
*> PluginMap
;
36 // Gets the full path of the plug-in file as the identifier.
37 std::string
GetLongIdentifier(const content::WebPluginInfo
& plugin
) {
38 return plugin
.path
.AsUTF8Unsafe();
41 // Gets the base name of the file path as the identifier.
42 std::string
GetIdentifier(const content::WebPluginInfo
& plugin
) {
43 return plugin
.path
.BaseName().AsUTF8Unsafe();
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.
48 static base::string16
GetGroupName(const content::WebPluginInfo
& plugin
) {
49 if (!plugin
.name
.empty())
52 return plugin
.path
.BaseName().RemoveExtension().AsUTF16Unsafe();
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
))
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
);
70 if (matching_mime_types
) {
71 plugin
->AddMatchingMimeType(mime_type_str
);
73 plugin
->AddMimeType(mime_type_str
);
78 PluginMetadata
* CreatePluginMetadata(
79 const std::string
& identifier
,
80 const base::DictionaryValue
* plugin_dict
) {
82 bool success
= plugin_dict
->GetString("url", &url
);
84 plugin_dict
->GetString("help_url", &help_url
);
86 success
= plugin_dict
->GetString("name", &name
);
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
);
93 std::string language_str
;
94 plugin_dict
->GetString("lang", &language_str
);
96 PluginMetadata
* plugin
= new PluginMetadata(identifier
,
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
)) {
113 success
= version_dict
->GetString("version", &version
);
115 std::string status_str
;
116 success
= version_dict
->GetString("status", &status_str
);
118 PluginMetadata::SecurityStatus status
=
119 PluginMetadata::SECURITY_STATUS_UP_TO_DATE
;
120 success
= PluginMetadata::ParseSecurityStatus(status_str
, &status
);
122 plugin
->AddVersion(Version(version
), status
);
126 LoadMimeTypes(false, plugin_dict
, plugin
);
127 LoadMimeTypes(true, plugin_dict
, plugin
);
134 void PluginFinder::RegisterPrefs(PrefRegistrySimple
* registry
) {
135 registry
->RegisterBooleanPref(prefs::kDisablePluginFinder
, false);
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();
145 PluginFinder::PluginFinder() : version_(-1) {
146 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
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());
155 ReinitializePlugins(plugin_list
.get());
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(
166 base::JSON_PARSE_RFC
,
170 DLOG(ERROR
) << error_str
;
173 if (value
->GetType() != base::Value::TYPE_DICTIONARY
)
175 return static_cast<base::DictionaryValue
*>(value
.release());
178 PluginFinder::~PluginFinder() {
179 #if defined(ENABLE_PLUGIN_INSTALLATION)
180 STLDeleteValues(&installers_
);
182 STLDeleteValues(&identifier_plugin_
);
185 #if defined(ENABLE_PLUGIN_INSTALLATION)
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
))
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();
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
;
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())
219 *plugin_metadata
= metadata_it
->second
->Clone();
222 std::map
<std::string
, PluginInstaller
*>::const_iterator installer_it
=
223 installers_
.find(identifier
);
224 if (installer_it
== installers_
.end())
226 *installer
= installer_it
->second
;
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_
)
243 STLDeleteValues(&identifier_plugin_
);
244 identifier_plugin_
.clear();
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
);
254 #if defined(ENABLE_PLUGIN_INSTALLATION)
255 if (installers_
.find(identifier
) == installers_
.end())
256 installers_
[identifier
] = new PluginInstaller();
262 base::string16
PluginFinder::FindPluginNameWithIdentifier(
263 const std::string
& identifier
) {
264 base::AutoLock
lock(mutex_
);
265 PluginMap::const_iterator it
= identifier_plugin_
.find(identifier
);
267 if (it
!= identifier_plugin_
.end())
268 name
= it
->second
->name();
270 return name
.empty() ? base::UTF8ToUTF16(identifier
) : name
;
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
))
281 return it
->second
->Clone();
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
),
294 for (size_t i
= 0; i
< plugin
.mime_types
.size(); ++i
)
295 metadata
->AddMatchingMimeType(plugin
.mime_types
[i
].mime_type
);
297 DCHECK(metadata
->MatchesPlugin(plugin
));
298 if (identifier_plugin_
.find(identifier
) != identifier_plugin_
.end())
299 identifier
= GetLongIdentifier(plugin
);
301 DCHECK(identifier_plugin_
.find(identifier
) == identifier_plugin_
.end());
302 identifier_plugin_
[identifier
] = metadata
;
303 return metadata
->Clone();