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_
);
245 for (base::DictionaryValue::Iterator
plugin_it(*plugin_list
);
246 !plugin_it
.IsAtEnd(); plugin_it
.Advance()) {
247 const base::DictionaryValue
* plugin
= NULL
;
248 const std::string
& identifier
= plugin_it
.key();
249 if (plugin_list
->GetDictionaryWithoutPathExpansion(identifier
, &plugin
)) {
250 DCHECK(!identifier_plugin_
[identifier
]);
251 identifier_plugin_
[identifier
] = CreatePluginMetadata(identifier
, plugin
);
253 #if defined(ENABLE_PLUGIN_INSTALLATION)
254 if (installers_
.find(identifier
) == installers_
.end())
255 installers_
[identifier
] = new PluginInstaller();
261 base::string16
PluginFinder::FindPluginNameWithIdentifier(
262 const std::string
& identifier
) {
263 base::AutoLock
lock(mutex_
);
264 PluginMap::const_iterator it
= identifier_plugin_
.find(identifier
);
266 if (it
!= identifier_plugin_
.end())
267 name
= it
->second
->name();
269 return name
.empty() ? base::UTF8ToUTF16(identifier
) : name
;
272 scoped_ptr
<PluginMetadata
> PluginFinder::GetPluginMetadata(
273 const content::WebPluginInfo
& plugin
) {
274 base::AutoLock
lock(mutex_
);
275 for (PluginMap::const_iterator it
= identifier_plugin_
.begin();
276 it
!= identifier_plugin_
.end(); ++it
) {
277 if (!it
->second
->MatchesPlugin(plugin
))
280 return it
->second
->Clone();
283 // The plug-in metadata was not found, create a dummy one holding
284 // the name, identifier and group name only.
285 std::string identifier
= GetIdentifier(plugin
);
286 PluginMetadata
* metadata
= new PluginMetadata(identifier
,
287 GetGroupName(plugin
),
293 for (size_t i
= 0; i
< plugin
.mime_types
.size(); ++i
)
294 metadata
->AddMatchingMimeType(plugin
.mime_types
[i
].mime_type
);
296 DCHECK(metadata
->MatchesPlugin(plugin
));
297 if (identifier_plugin_
.find(identifier
) != identifier_plugin_
.end())
298 identifier
= GetLongIdentifier(plugin
);
300 DCHECK(identifier_plugin_
.find(identifier
) == identifier_plugin_
.end());
301 identifier_plugin_
[identifier
] = metadata
;
302 return metadata
->Clone();