OLD | NEW |
| (Empty) |
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/plugin_finder.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/json/json_reader.h" | |
9 #include "base/message_loop.h" | |
10 #include "base/stl_util.h" | |
11 #include "base/sys_string_conversions.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/browser_process.h" | |
15 #include "chrome/browser/plugin_installer.h" | |
16 #include "chrome/browser/prefs/pref_service.h" | |
17 #include "chrome/common/pref_names.h" | |
18 #include "content/public/browser/browser_thread.h" | |
19 #include "content/public/browser/plugin_service.h" | |
20 #include "googleurl/src/gurl.h" | |
21 #include "grit/browser_resources.h" | |
22 #include "ui/base/layout.h" | |
23 #include "ui/base/resource/resource_bundle.h" | |
24 | |
25 using base::DictionaryValue; | |
26 using content::PluginService; | |
27 | |
28 namespace { | |
29 | |
30 // Gets the base name of the file path as the identifier. | |
31 static std::string GetIdentifier(const webkit::WebPluginInfo& plugin) { | |
32 #if defined(OS_POSIX) | |
33 return plugin.path.BaseName().value(); | |
34 #elif defined(OS_WIN) | |
35 return base::SysWideToUTF8(plugin.path.BaseName().value()); | |
36 #endif | |
37 } | |
38 | |
39 // Gets the plug-in group name as the plug-in name if it is not empty or | |
40 // the filename without extension if the name is empty. | |
41 static string16 GetGroupName(const webkit::WebPluginInfo& plugin) { | |
42 if (!plugin.name.empty()) | |
43 return plugin.name; | |
44 | |
45 FilePath::StringType path = plugin.path.BaseName().RemoveExtension().value(); | |
46 #if defined(OS_POSIX) | |
47 return UTF8ToUTF16(path); | |
48 #elif defined(OS_WIN) | |
49 return WideToUTF16(path); | |
50 #endif | |
51 } | |
52 | |
53 // A callback barrier used to enforce the execution of a callback function | |
54 // only when two different asynchronous callbacks are done execution. | |
55 // The first asynchronous callback gets a PluginFinder instance and the | |
56 // second asynchronous callback gets a list of plugins. | |
57 class PluginFinderCallbackBarrier | |
58 : public base::RefCountedThreadSafe<PluginFinderCallbackBarrier> { | |
59 public: | |
60 typedef base::Callback<void(const PluginFinder::PluginVector&)> | |
61 PluginsCallback; | |
62 | |
63 explicit PluginFinderCallbackBarrier( | |
64 const PluginFinder::CombinedCallback& callback) | |
65 : callback_(callback), | |
66 finder_(NULL) { | |
67 DCHECK(!callback_.is_null()); | |
68 } | |
69 | |
70 base::Callback<void(PluginFinder*)> CreatePluginFinderCallback() { | |
71 return base::Bind(&PluginFinderCallbackBarrier::GotPluginFinder, this); | |
72 } | |
73 | |
74 PluginsCallback CreatePluginsCallback() { | |
75 return base::Bind(&PluginFinderCallbackBarrier::GotPlugins, this); | |
76 } | |
77 | |
78 private: | |
79 friend class base::RefCountedThreadSafe<PluginFinderCallbackBarrier>; | |
80 | |
81 ~PluginFinderCallbackBarrier() { | |
82 DCHECK(callback_.is_null()); | |
83 } | |
84 | |
85 void GotPlugins(const PluginFinder::PluginVector& plugins) { | |
86 plugins_.reset(new PluginFinder::PluginVector(plugins)); | |
87 MaybeRunCallback(); | |
88 } | |
89 | |
90 void GotPluginFinder(PluginFinder* finder) { | |
91 finder_ = finder; | |
92 MaybeRunCallback(); | |
93 } | |
94 | |
95 // Executes the callback only when both asynchronous methods have finished | |
96 // their executions. This is identified by having non-null values in both | |
97 // |finder_| and |plugins_|. | |
98 void MaybeRunCallback() { | |
99 if (!finder_ || !plugins_.get()) | |
100 return; | |
101 | |
102 callback_.Run(*plugins_, finder_); | |
103 callback_.Reset(); | |
104 } | |
105 | |
106 PluginFinder::CombinedCallback callback_; | |
107 PluginFinder* finder_; | |
108 scoped_ptr<PluginFinder::PluginVector> plugins_; | |
109 }; | |
110 | |
111 } // namespace | |
112 | |
113 // static | |
114 void PluginFinder::GetPluginsAndPluginFinder( | |
115 const PluginFinder::CombinedCallback& cb) { | |
116 scoped_refptr<PluginFinderCallbackBarrier> barrier = | |
117 new PluginFinderCallbackBarrier(cb); | |
118 | |
119 PluginFinder::Get(barrier->CreatePluginFinderCallback()); | |
120 PluginService::GetInstance()->GetPlugins(barrier->CreatePluginsCallback()); | |
121 } | |
122 | |
123 // static | |
124 void PluginFinder::Get(const base::Callback<void(PluginFinder*)>& cb) { | |
125 // At a later point we might want to do intialization here that needs to be | |
126 // done asynchronously, like loading the plug-in list from disk or from a URL. | |
127 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(cb, GetInstance())); | |
128 } | |
129 | |
130 // static | |
131 PluginFinder* PluginFinder::GetInstance() { | |
132 // PluginFinder::GetInstance() is the only method that's allowed to call | |
133 // Singleton<PluginFinder>::get(). | |
134 return Singleton<PluginFinder>::get(); | |
135 } | |
136 | |
137 PluginFinder::PluginFinder() : plugin_list_(LoadPluginList()) { | |
138 if (!plugin_list_.get()) | |
139 plugin_list_.reset(new DictionaryValue()); | |
140 } | |
141 | |
142 // static | |
143 DictionaryValue* PluginFinder::LoadPluginList() { | |
144 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) | |
145 base::StringPiece json_resource( | |
146 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
147 IDR_PLUGIN_DB_JSON, ui::SCALE_FACTOR_NONE)); | |
148 std::string error_str; | |
149 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( | |
150 json_resource, | |
151 base::JSON_PARSE_RFC, | |
152 NULL, | |
153 &error_str)); | |
154 if (!value.get()) { | |
155 DLOG(ERROR) << error_str; | |
156 return NULL; | |
157 } | |
158 if (value->GetType() != base::Value::TYPE_DICTIONARY) | |
159 return NULL; | |
160 return static_cast<base::DictionaryValue*>(value.release()); | |
161 #else | |
162 return new DictionaryValue(); | |
163 #endif | |
164 } | |
165 | |
166 PluginFinder::~PluginFinder() { | |
167 STLDeleteValues(&installers_); | |
168 } | |
169 | |
170 PluginInstaller* PluginFinder::FindPlugin(const std::string& mime_type, | |
171 const std::string& language) { | |
172 if (g_browser_process->local_state()->GetBoolean(prefs::kDisablePluginFinder)) | |
173 return NULL; | |
174 for (DictionaryValue::Iterator plugin_it(*plugin_list_); | |
175 plugin_it.HasNext(); plugin_it.Advance()) { | |
176 const DictionaryValue* plugin = NULL; | |
177 if (!plugin_it.value().GetAsDictionary(&plugin)) { | |
178 NOTREACHED(); | |
179 continue; | |
180 } | |
181 std::string language_str; | |
182 bool success = plugin->GetString("lang", &language_str); | |
183 if (language_str != language) | |
184 continue; | |
185 const ListValue* mime_types = NULL; | |
186 plugin->GetList("mime_types", &mime_types); | |
187 DCHECK(success); | |
188 for (ListValue::const_iterator mime_type_it = mime_types->begin(); | |
189 mime_type_it != mime_types->end(); ++mime_type_it) { | |
190 std::string mime_type_str; | |
191 success = (*mime_type_it)->GetAsString(&mime_type_str); | |
192 DCHECK(success); | |
193 if (mime_type_str == mime_type) { | |
194 std::string identifier = plugin_it.key(); | |
195 std::map<std::string, PluginInstaller*>::const_iterator installer = | |
196 installers_.find(identifier); | |
197 if (installer != installers_.end()) | |
198 return installer->second; | |
199 return CreateInstaller(identifier, plugin); | |
200 } | |
201 } | |
202 } | |
203 return NULL; | |
204 } | |
205 | |
206 PluginInstaller* PluginFinder::FindPluginWithIdentifier( | |
207 const std::string& identifier) { | |
208 std::map<std::string, PluginInstaller*>::const_iterator it = | |
209 installers_.find(identifier); | |
210 if (it != installers_.end()) | |
211 return it->second; | |
212 DictionaryValue* plugin = NULL; | |
213 if (plugin_list_->GetDictionaryWithoutPathExpansion(identifier, &plugin)) | |
214 return CreateInstaller(identifier, plugin); | |
215 return NULL; | |
216 } | |
217 | |
218 PluginInstaller* PluginFinder::CreateInstaller( | |
219 const std::string& identifier, | |
220 const DictionaryValue* plugin_dict) { | |
221 DCHECK(!installers_[identifier]); | |
222 std::string url; | |
223 bool success = plugin_dict->GetString("url", &url); | |
224 std::string help_url; | |
225 plugin_dict->GetString("help_url", &help_url); | |
226 string16 name; | |
227 success = plugin_dict->GetString("name", &name); | |
228 DCHECK(success); | |
229 bool display_url = false; | |
230 plugin_dict->GetBoolean("displayurl", &display_url); | |
231 string16 group_name_matcher; | |
232 success = plugin_dict->GetString("group_name_matcher", &group_name_matcher); | |
233 DCHECK(success); | |
234 | |
235 PluginInstaller* installer = new PluginInstaller(identifier, | |
236 name, | |
237 display_url, | |
238 GURL(url), | |
239 GURL(help_url), | |
240 group_name_matcher); | |
241 const ListValue* versions = NULL; | |
242 if (plugin_dict->GetList("versions", &versions)) { | |
243 for (ListValue::const_iterator it = versions->begin(); | |
244 it != versions->end(); ++it) { | |
245 DictionaryValue* version_dict = NULL; | |
246 if (!(*it)->GetAsDictionary(&version_dict)) { | |
247 NOTREACHED(); | |
248 continue; | |
249 } | |
250 std::string version; | |
251 success = version_dict->GetString("version", &version); | |
252 DCHECK(success); | |
253 std::string status_str; | |
254 success = version_dict->GetString("status", &status_str); | |
255 DCHECK(success); | |
256 PluginInstaller::SecurityStatus status = | |
257 PluginInstaller::SECURITY_STATUS_UP_TO_DATE; | |
258 success = PluginInstaller::ParseSecurityStatus(status_str, &status); | |
259 DCHECK(success); | |
260 installer->AddVersion(Version(version), status); | |
261 } | |
262 } | |
263 | |
264 installers_[identifier] = installer; | |
265 return installer; | |
266 } | |
267 | |
268 PluginInstaller* PluginFinder::GetPluginInstaller( | |
269 const webkit::WebPluginInfo& plugin) { | |
270 if (name_installers_.find(plugin.name) != name_installers_.end()) | |
271 return name_installers_[plugin.name]; | |
272 | |
273 for (DictionaryValue::Iterator plugin_it(*plugin_list_); | |
274 plugin_it.HasNext(); plugin_it.Advance()) { | |
275 // This method triggers the lazy initialization for all PluginInstallers. | |
276 FindPluginWithIdentifier(plugin_it.key()); | |
277 } | |
278 | |
279 // Use the group name matcher to find the plug-in installer we want. | |
280 for (std::map<std::string, PluginInstaller*>::const_iterator it = | |
281 installers_.begin(); it != installers_.end(); ++it) { | |
282 if (!it->second->MatchesPlugin(plugin)) | |
283 continue; | |
284 | |
285 name_installers_[plugin.name] = it->second; | |
286 return it->second; | |
287 } | |
288 | |
289 // The plug-in installer was not found, create a dummy one holding | |
290 // the name, identifier and group name only. | |
291 std::string identifier = GetIdentifier(plugin); | |
292 PluginInstaller* installer = new PluginInstaller(identifier, | |
293 GetGroupName(plugin), | |
294 false, GURL(), GURL(), | |
295 GetGroupName(plugin)); | |
296 installers_[identifier] = installer; | |
297 name_installers_[plugin.name] = installer; | |
298 return installer; | |
299 } | |
OLD | NEW |