OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "webkit/glue/plugins/plugin_list.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "base/logging.h" | |
12 #include "base/string_split.h" | |
13 #include "base/string_util.h" | |
14 #include "base/sys_string_conversions.h" | |
15 #include "base/utf_string_conversions.h" | |
16 #include "googleurl/src/gurl.h" | |
17 #include "net/base/mime_util.h" | |
18 #include "webkit/glue/plugins/plugin_constants_win.h" | |
19 #include "webkit/glue/plugins/plugin_lib.h" | |
20 #include "webkit/glue/webkit_glue.h" | |
21 #include "webkit/plugins/plugin_switches.h" | |
22 | |
23 #if defined(OS_POSIX) | |
24 #include "base/stl_util-inl.h" | |
25 #include "base/third_party/valgrind/valgrind.h" | |
26 #endif // defined(OS_POSIX) | |
27 | |
28 namespace NPAPI { | |
29 | |
30 #if defined(OS_MACOSX) | |
31 // Plugin Groups for Mac. | |
32 // Plugins are listed here as soon as vulnerabilities and solutions | |
33 // (new versions) are published. | |
34 // TODO(panayiotis): Get the Real Player version on Mac, somehow. | |
35 static const VersionRangeDefinition kQuicktimeVersionRange[] = { | |
36 { "", "", "7.6.6" } | |
37 }; | |
38 static const VersionRangeDefinition kJavaVersionRange[] = { | |
39 { "", "", "" } | |
40 }; | |
41 static const VersionRangeDefinition kFlashVersionRange[] = { | |
42 { "", "", "10.1.102" } | |
43 }; | |
44 static const VersionRangeDefinition kSilverlightVersionRange[] = { | |
45 { "0", "4", "3.0.50106.0" }, | |
46 { "4", "5", "" } | |
47 }; | |
48 static const VersionRangeDefinition kFlip4MacVersionRange[] = { | |
49 { "", "", "2.2.1" } | |
50 }; | |
51 static const VersionRangeDefinition kShockwaveVersionRange[] = { | |
52 { "", "", "11.5.9.615" } | |
53 }; | |
54 static const PluginGroupDefinition kGroupDefinitions[] = { | |
55 { "apple-quicktime", "Quicktime", "QuickTime Plug-in", kQuicktimeVersionRange, | |
56 arraysize(kQuicktimeVersionRange), | |
57 "http://www.apple.com/quicktime/download/" }, | |
58 { "java-runtime-environment", "Java", "Java", kJavaVersionRange, | |
59 arraysize(kJavaVersionRange), "http://support.apple.com/kb/HT1338" }, | |
60 { "adobe-flash-player", "Flash", "Shockwave Flash", kFlashVersionRange, | |
61 arraysize(kFlashVersionRange), "http://get.adobe.com/flashplayer/" }, | |
62 { "silverlight", "Silverlight", "Silverlight", kSilverlightVersionRange, | |
63 arraysize(kSilverlightVersionRange), | |
64 "http://www.microsoft.com/getsilverlight/" }, | |
65 { "flip4mac", "Flip4Mac", "Flip4Mac", kFlip4MacVersionRange, | |
66 arraysize(kFlip4MacVersionRange), | |
67 "http://www.telestream.net/flip4mac-wmv/overview.htm" }, | |
68 { "shockwave", "Shockwave", "Shockwave for Director", kShockwaveVersionRange, | |
69 arraysize(kShockwaveVersionRange), | |
70 "http://www.adobe.com/shockwave/download/" } | |
71 }; | |
72 | |
73 #elif defined(OS_WIN) | |
74 // TODO(panayiotis): We should group "RealJukebox NS Plugin" with the rest of | |
75 // the RealPlayer files. | |
76 static const VersionRangeDefinition kQuicktimeVersionRange[] = { | |
77 { "", "", "7.6.8" } | |
78 }; | |
79 static const VersionRangeDefinition kJavaVersionRange[] = { | |
80 { "0", "7", "6.0.220" } // "220" is not a typo. | |
81 }; | |
82 static const VersionRangeDefinition kAdobeReaderVersionRange[] = { | |
83 { "10", "11", "" }, | |
84 { "9", "10", "9.4.1" }, | |
85 { "0", "9", "8.2.5" } | |
86 }; | |
87 static const VersionRangeDefinition kFlashVersionRange[] = { | |
88 { "", "", "10.1.102" } | |
89 }; | |
90 static const VersionRangeDefinition kSilverlightVersionRange[] = { | |
91 { "0", "4", "3.0.50106.0" }, | |
92 { "4", "5", "" } | |
93 }; | |
94 static const VersionRangeDefinition kShockwaveVersionRange[] = { | |
95 { "", "", "11.5.9.615" } | |
96 }; | |
97 static const VersionRangeDefinition kDivXVersionRange[] = { | |
98 { "", "", "1.4.3.4" } | |
99 }; | |
100 static const PluginGroupDefinition kGroupDefinitions[] = { | |
101 { "apple-quicktime", "Quicktime", "QuickTime Plug-in", kQuicktimeVersionRange, | |
102 arraysize(kQuicktimeVersionRange), | |
103 "http://www.apple.com/quicktime/download/" }, | |
104 { "java-runtime-environment", "Java 6", "Java", kJavaVersionRange, | |
105 arraysize(kJavaVersionRange), "http://www.java.com/" }, | |
106 { "adobe-reader", PluginGroup::kAdobeReaderGroupName, "Adobe Acrobat", | |
107 kAdobeReaderVersionRange, arraysize(kAdobeReaderVersionRange), | |
108 "http://get.adobe.com/reader/" }, | |
109 { "adobe-flash-player", "Flash", "Shockwave Flash", kFlashVersionRange, | |
110 arraysize(kFlashVersionRange), "http://get.adobe.com/flashplayer/" }, | |
111 { "silverlight", "Silverlight", "Silverlight", kSilverlightVersionRange, | |
112 arraysize(kSilverlightVersionRange), | |
113 "http://www.microsoft.com/getsilverlight/" }, | |
114 { "shockwave", "Shockwave", "Shockwave for Director", kShockwaveVersionRange, | |
115 arraysize(kShockwaveVersionRange), | |
116 "http://www.adobe.com/shockwave/download/" }, | |
117 { "divx-player", "DivX Player", "DivX Web Player", kDivXVersionRange, | |
118 arraysize(kDivXVersionRange), | |
119 "http://download.divx.com/divx/autoupdate/player/" | |
120 "DivXWebPlayerInstaller.exe" }, | |
121 // These are here for grouping, no vulnerabilities known. | |
122 { "windows-media-player", "Windows Media Player", "Windows Media Player", | |
123 NULL, 0, "" }, | |
124 { "microsoft-office", "Microsoft Office", "Microsoft Office", | |
125 NULL, 0, "" }, | |
126 // TODO(panayiotis): The vulnerable versions are | |
127 // (v >= 6.0.12.1040 && v <= 6.0.12.1663) | |
128 // || v == 6.0.12.1698 || v == 6.0.12.1741 | |
129 { "realplayer", "RealPlayer", "RealPlayer", NULL, 0, | |
130 "www.real.com/realplayer/downloads" }, | |
131 }; | |
132 | |
133 #else | |
134 static const PluginGroupDefinition kGroupDefinitions[] = {}; | |
135 #endif | |
136 | |
137 // static | |
138 const PluginGroupDefinition* PluginList::GetPluginGroupDefinitions() { | |
139 return kGroupDefinitions; | |
140 } | |
141 | |
142 // static | |
143 size_t PluginList::GetPluginGroupDefinitionsSize() { | |
144 // TODO(viettrungluu): |arraysize()| doesn't work with zero-size arrays. | |
145 return ARRAYSIZE_UNSAFE(kGroupDefinitions); | |
146 } | |
147 | |
148 base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED); | |
149 | |
150 // static | |
151 PluginList* PluginList::Singleton() { | |
152 return g_singleton.Pointer(); | |
153 } | |
154 | |
155 // static | |
156 bool PluginList::DebugPluginLoading() { | |
157 return CommandLine::ForCurrentProcess()->HasSwitch( | |
158 switches::kDebugPluginLoading); | |
159 } | |
160 | |
161 bool PluginList::PluginsLoaded() { | |
162 AutoLock lock(lock_); | |
163 return plugins_loaded_; | |
164 } | |
165 | |
166 void PluginList::RefreshPlugins() { | |
167 AutoLock lock(lock_); | |
168 plugins_need_refresh_ = true; | |
169 } | |
170 | |
171 void PluginList::AddExtraPluginPath(const FilePath& plugin_path) { | |
172 // Chrome OS only loads plugins from /opt/google/chrome/plugins. | |
173 #if !defined(OS_CHROMEOS) | |
174 AutoLock lock(lock_); | |
175 extra_plugin_paths_.push_back(plugin_path); | |
176 #endif | |
177 } | |
178 | |
179 void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) { | |
180 AutoLock lock(lock_); | |
181 std::vector<FilePath>::iterator it = | |
182 std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(), | |
183 plugin_path); | |
184 if (it != extra_plugin_paths_.end()) | |
185 extra_plugin_paths_.erase(it); | |
186 } | |
187 | |
188 void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) { | |
189 // Chrome OS only loads plugins from /opt/google/chrome/plugins. | |
190 #if !defined(OS_CHROMEOS) | |
191 AutoLock lock(lock_); | |
192 extra_plugin_dirs_.push_back(plugin_dir); | |
193 #endif | |
194 } | |
195 | |
196 void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) { | |
197 AutoLock lock(lock_); | |
198 internal_plugins_.push_back(info); | |
199 } | |
200 | |
201 void PluginList::UnregisterInternalPlugin(const FilePath& path) { | |
202 AutoLock lock(lock_); | |
203 for (size_t i = 0; i < internal_plugins_.size(); i++) { | |
204 if (internal_plugins_[i].path == path) { | |
205 internal_plugins_.erase(internal_plugins_.begin() + i); | |
206 return; | |
207 } | |
208 } | |
209 NOTREACHED(); | |
210 } | |
211 | |
212 bool PluginList::ReadPluginInfo(const FilePath& filename, | |
213 WebPluginInfo* info, | |
214 const PluginEntryPoints** entry_points) { | |
215 { | |
216 AutoLock lock(lock_); | |
217 for (size_t i = 0; i < internal_plugins_.size(); ++i) { | |
218 if (filename == internal_plugins_[i].path) { | |
219 *entry_points = &internal_plugins_[i].entry_points; | |
220 return CreateWebPluginInfo(internal_plugins_[i], info); | |
221 } | |
222 } | |
223 } | |
224 | |
225 // Not an internal plugin. | |
226 *entry_points = NULL; | |
227 | |
228 return PluginLib::ReadWebPluginInfo(filename, info); | |
229 } | |
230 | |
231 bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi, | |
232 WebPluginInfo* info) { | |
233 std::vector<std::string> mime_types, file_extensions; | |
234 std::vector<string16> descriptions; | |
235 base::SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types); | |
236 base::SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions); | |
237 base::SplitString(WideToUTF16(pvi.type_descriptions), '|', &descriptions); | |
238 | |
239 info->mime_types.clear(); | |
240 | |
241 if (mime_types.empty()) { | |
242 LOG_IF(ERROR, PluginList::DebugPluginLoading()) | |
243 << "Plugin " << pvi.product_name << " has no MIME types, skipping"; | |
244 return false; | |
245 } | |
246 | |
247 info->name = WideToUTF16(pvi.product_name); | |
248 info->desc = WideToUTF16(pvi.file_description); | |
249 info->version = WideToUTF16(pvi.file_version); | |
250 info->path = pvi.path; | |
251 info->enabled = true; | |
252 | |
253 for (size_t i = 0; i < mime_types.size(); ++i) { | |
254 WebPluginMimeType mime_type; | |
255 mime_type.mime_type = StringToLowerASCII(mime_types[i]); | |
256 if (file_extensions.size() > i) | |
257 base::SplitString(file_extensions[i], ',', &mime_type.file_extensions); | |
258 | |
259 if (descriptions.size() > i) { | |
260 mime_type.description = descriptions[i]; | |
261 | |
262 // On Windows, the description likely has a list of file extensions | |
263 // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension | |
264 // list from the description if it is present. | |
265 size_t ext = mime_type.description.find(ASCIIToUTF16("(*")); | |
266 if (ext != string16::npos) { | |
267 if (ext > 1 && mime_type.description[ext -1] == ' ') | |
268 ext--; | |
269 | |
270 mime_type.description.erase(ext); | |
271 } | |
272 } | |
273 | |
274 info->mime_types.push_back(mime_type); | |
275 } | |
276 | |
277 return true; | |
278 } | |
279 | |
280 PluginList::PluginList() | |
281 : plugins_loaded_(false), | |
282 plugins_need_refresh_(false), | |
283 disable_outdated_plugins_(false), | |
284 next_priority_(0) { | |
285 PlatformInit(); | |
286 AddHardcodedPluginGroups(); | |
287 } | |
288 | |
289 bool PluginList::ShouldDisableGroup(const string16& group_name) { | |
290 AutoLock lock(lock_); | |
291 if (PluginGroup::IsPluginNameDisabledByPolicy(group_name)) { | |
292 disabled_groups_.insert(group_name); | |
293 return true; | |
294 } | |
295 return disabled_groups_.count(group_name) > 0; | |
296 } | |
297 | |
298 void PluginList::LoadPlugins(bool refresh) { | |
299 // Don't want to hold the lock while loading new plugins, so we don't block | |
300 // other methods if they're called on other threads. | |
301 std::vector<FilePath> extra_plugin_paths; | |
302 std::vector<FilePath> extra_plugin_dirs; | |
303 std::vector<PluginVersionInfo> internal_plugins; | |
304 { | |
305 AutoLock lock(lock_); | |
306 if (plugins_loaded_ && !refresh && !plugins_need_refresh_) | |
307 return; | |
308 | |
309 // Clear the refresh bit now, because it might get set again before we | |
310 // reach the end of the method. | |
311 plugins_need_refresh_ = false; | |
312 extra_plugin_paths = extra_plugin_paths_; | |
313 extra_plugin_dirs = extra_plugin_dirs_; | |
314 internal_plugins = internal_plugins_; | |
315 } | |
316 | |
317 std::vector<WebPluginInfo> new_plugins; | |
318 std::set<FilePath> visited_plugins; | |
319 | |
320 std::vector<FilePath> directories_to_scan; | |
321 GetPluginDirectories(&directories_to_scan); | |
322 | |
323 // Load internal plugins first so that, if both an internal plugin and a | |
324 // "discovered" plugin want to handle the same type, the internal plugin | |
325 // will have precedence. | |
326 for (size_t i = 0; i < internal_plugins.size(); ++i) { | |
327 if (internal_plugins[i].path.value() == kDefaultPluginLibraryName) | |
328 continue; | |
329 LoadPlugin(internal_plugins[i].path, &new_plugins); | |
330 } | |
331 | |
332 for (size_t i = 0; i < extra_plugin_paths.size(); ++i) { | |
333 const FilePath& path = extra_plugin_paths[i]; | |
334 if (visited_plugins.find(path) != visited_plugins.end()) | |
335 continue; | |
336 LoadPlugin(path, &new_plugins); | |
337 visited_plugins.insert(path); | |
338 } | |
339 | |
340 for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) { | |
341 LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins, &visited_plugins); | |
342 } | |
343 | |
344 for (size_t i = 0; i < directories_to_scan.size(); ++i) { | |
345 LoadPluginsFromDir(directories_to_scan[i], &new_plugins, &visited_plugins); | |
346 } | |
347 | |
348 #if defined(OS_WIN) | |
349 LoadPluginsFromRegistry(&new_plugins, &visited_plugins); | |
350 #endif | |
351 | |
352 // Load the default plugin last. | |
353 if (webkit_glue::IsDefaultPluginEnabled()) | |
354 LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins); | |
355 | |
356 // Disable all of the plugins and plugin groups that are disabled by policy. | |
357 // There's currenly a bug that makes it impossible to correctly re-enable | |
358 // plugins or plugin-groups to their original, "pre-policy" state, so | |
359 // plugins and groups are only changed to a more "safe" state after a policy | |
360 // change, i.e. from enabled to disabled. See bug 54681. | |
361 for (PluginGroup::PluginMap::iterator it = plugin_groups_.begin(); | |
362 it != plugin_groups_.end(); ++it) { | |
363 PluginGroup* group = it->second; | |
364 string16 group_name = group->GetGroupName(); | |
365 if (ShouldDisableGroup(group_name)) { | |
366 group->Enable(false); | |
367 } | |
368 | |
369 if (disable_outdated_plugins_) { | |
370 group->DisableOutdatedPlugins(); | |
371 } | |
372 if (!group->Enabled()) { | |
373 AutoLock lock(lock_); | |
374 disabled_groups_.insert(group_name); | |
375 } | |
376 } | |
377 | |
378 // Only update the data now since loading plugins can take a while. | |
379 AutoLock lock(lock_); | |
380 | |
381 plugins_ = new_plugins; | |
382 plugins_loaded_ = true; | |
383 } | |
384 | |
385 void PluginList::LoadPlugin(const FilePath& path, | |
386 std::vector<WebPluginInfo>* plugins) { | |
387 LOG_IF(ERROR, PluginList::DebugPluginLoading()) | |
388 << "Loading plugin " << path.value(); | |
389 | |
390 WebPluginInfo plugin_info; | |
391 const PluginEntryPoints* entry_points; | |
392 | |
393 if (!ReadPluginInfo(path, &plugin_info, &entry_points)) | |
394 return; | |
395 | |
396 if (!ShouldLoadPlugin(plugin_info, plugins)) | |
397 return; | |
398 | |
399 if (path.value() != kDefaultPluginLibraryName | |
400 #if defined(OS_WIN) && !defined(NDEBUG) | |
401 && path.BaseName().value() != L"npspy.dll" // Make an exception for NPSPY | |
402 #endif | |
403 ) { | |
404 for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) { | |
405 // TODO: don't load global handlers for now. | |
406 // WebKit hands to the Plugin before it tries | |
407 // to handle mimeTypes on its own. | |
408 const std::string &mime_type = plugin_info.mime_types[i].mime_type; | |
409 if (mime_type == "*" ) | |
410 return; | |
411 } | |
412 } | |
413 | |
414 // Mark disabled plugins as such. (This has to happen before calling | |
415 // |AddToPluginGroups(plugin_info)|.) | |
416 if (disabled_plugins_.count(plugin_info.path)) { | |
417 plugin_info.enabled = false; | |
418 } else { | |
419 plugin_info.enabled = true; | |
420 } | |
421 | |
422 AutoLock lock(lock_); | |
423 plugins->push_back(plugin_info); | |
424 AddToPluginGroups(plugin_info); | |
425 } | |
426 | |
427 bool PluginList::SupportsType(const WebPluginInfo& info, | |
428 const std::string &mime_type, | |
429 bool allow_wildcard) { | |
430 // Webkit will ask for a plugin to handle empty mime types. | |
431 if (mime_type.empty()) | |
432 return false; | |
433 | |
434 for (size_t i = 0; i < info.mime_types.size(); ++i) { | |
435 const WebPluginMimeType& mime_info = info.mime_types[i]; | |
436 if (net::MatchesMimeType(mime_info.mime_type, mime_type)) { | |
437 if (!allow_wildcard && mime_info.mime_type == "*") { | |
438 continue; | |
439 } | |
440 return true; | |
441 } | |
442 } | |
443 return false; | |
444 } | |
445 | |
446 bool PluginList::SupportsExtension(const WebPluginInfo& info, | |
447 const std::string &extension, | |
448 std::string* actual_mime_type) { | |
449 for (size_t i = 0; i < info.mime_types.size(); ++i) { | |
450 const WebPluginMimeType& mime_type = info.mime_types[i]; | |
451 for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) { | |
452 if (mime_type.file_extensions[j] == extension) { | |
453 if (actual_mime_type) | |
454 *actual_mime_type = mime_type.mime_type; | |
455 return true; | |
456 } | |
457 } | |
458 } | |
459 | |
460 return false; | |
461 } | |
462 | |
463 | |
464 void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) { | |
465 LoadPlugins(refresh); | |
466 | |
467 AutoLock lock(lock_); | |
468 *plugins = plugins_; | |
469 } | |
470 | |
471 void PluginList::GetEnabledPlugins(bool refresh, | |
472 std::vector<WebPluginInfo>* plugins) { | |
473 LoadPlugins(refresh); | |
474 | |
475 plugins->clear(); | |
476 AutoLock lock(lock_); | |
477 for (std::vector<WebPluginInfo>::const_iterator it = plugins_.begin(); | |
478 it != plugins_.end(); | |
479 ++it) { | |
480 if (it->enabled) | |
481 plugins->push_back(*it); | |
482 } | |
483 } | |
484 | |
485 void PluginList::GetPluginInfoArray( | |
486 const GURL& url, | |
487 const std::string& mime_type, | |
488 bool allow_wildcard, | |
489 std::vector<WebPluginInfo>* info, | |
490 std::vector<std::string>* actual_mime_types) { | |
491 DCHECK(mime_type == StringToLowerASCII(mime_type)); | |
492 DCHECK(info); | |
493 | |
494 LoadPlugins(false); | |
495 AutoLock lock(lock_); | |
496 info->clear(); | |
497 if (actual_mime_types) | |
498 actual_mime_types->clear(); | |
499 | |
500 std::set<FilePath> visited_plugins; | |
501 | |
502 // Add in enabled plugins by mime type. | |
503 WebPluginInfo default_plugin; | |
504 for (size_t i = 0; i < plugins_.size(); ++i) { | |
505 if (plugins_[i].enabled && | |
506 SupportsType(plugins_[i], mime_type, allow_wildcard)) { | |
507 FilePath path = plugins_[i].path; | |
508 if (path.value() != kDefaultPluginLibraryName && | |
509 visited_plugins.insert(path).second) { | |
510 info->push_back(plugins_[i]); | |
511 if (actual_mime_types) | |
512 actual_mime_types->push_back(mime_type); | |
513 } | |
514 } | |
515 } | |
516 | |
517 // Add in enabled plugins by url. | |
518 std::string path = url.path(); | |
519 std::string::size_type last_dot = path.rfind('.'); | |
520 if (last_dot != std::string::npos) { | |
521 std::string extension = StringToLowerASCII(std::string(path, last_dot+1)); | |
522 std::string actual_mime_type; | |
523 for (size_t i = 0; i < plugins_.size(); ++i) { | |
524 if (plugins_[i].enabled && | |
525 SupportsExtension(plugins_[i], extension, &actual_mime_type)) { | |
526 FilePath path = plugins_[i].path; | |
527 if (path.value() != kDefaultPluginLibraryName && | |
528 visited_plugins.insert(path).second) { | |
529 info->push_back(plugins_[i]); | |
530 if (actual_mime_types) | |
531 actual_mime_types->push_back(actual_mime_type); | |
532 } | |
533 } | |
534 } | |
535 } | |
536 | |
537 // Add in disabled plugins by mime type. | |
538 for (size_t i = 0; i < plugins_.size(); ++i) { | |
539 if (!plugins_[i].enabled && | |
540 SupportsType(plugins_[i], mime_type, allow_wildcard)) { | |
541 FilePath path = plugins_[i].path; | |
542 if (path.value() != kDefaultPluginLibraryName && | |
543 visited_plugins.insert(path).second) { | |
544 info->push_back(plugins_[i]); | |
545 if (actual_mime_types) | |
546 actual_mime_types->push_back(mime_type); | |
547 } | |
548 } | |
549 } | |
550 | |
551 // Add the default plugin at the end if it supports the mime type given, | |
552 // and the default plugin is enabled. | |
553 if (!plugins_.empty() && webkit_glue::IsDefaultPluginEnabled()) { | |
554 const WebPluginInfo& default_info = plugins_.back(); | |
555 if (SupportsType(default_info, mime_type, allow_wildcard)) { | |
556 info->push_back(default_info); | |
557 if (actual_mime_types) | |
558 actual_mime_types->push_back(mime_type); | |
559 } | |
560 } | |
561 } | |
562 | |
563 bool PluginList::GetPluginInfo(const GURL& url, | |
564 const std::string& mime_type, | |
565 bool allow_wildcard, | |
566 WebPluginInfo* info, | |
567 std::string* actual_mime_type) { | |
568 DCHECK(info); | |
569 std::vector<WebPluginInfo> info_list; | |
570 | |
571 // GetPluginInfoArray has slightly less work to do if we can pass | |
572 // NULL for the mime type list... | |
573 if (actual_mime_type) { | |
574 std::vector<std::string> mime_type_list; | |
575 GetPluginInfoArray( | |
576 url, mime_type, allow_wildcard, &info_list, &mime_type_list); | |
577 if (!info_list.empty()) { | |
578 *info = info_list[0]; | |
579 *actual_mime_type = mime_type_list[0]; | |
580 return true; | |
581 } | |
582 } else { | |
583 GetPluginInfoArray(url, mime_type, allow_wildcard, &info_list, NULL); | |
584 if (!info_list.empty()) { | |
585 *info = info_list[0]; | |
586 return true; | |
587 } | |
588 } | |
589 return false; | |
590 } | |
591 | |
592 bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path, | |
593 WebPluginInfo* info) { | |
594 LoadPlugins(false); | |
595 AutoLock lock(lock_); | |
596 for (size_t i = 0; i < plugins_.size(); ++i) { | |
597 if (plugins_[i].path == plugin_path) { | |
598 *info = plugins_[i]; | |
599 return true; | |
600 } | |
601 } | |
602 | |
603 return false; | |
604 } | |
605 | |
606 void PluginList::GetPluginGroups( | |
607 bool load_if_necessary, | |
608 std::vector<PluginGroup>* plugin_groups) { | |
609 if (load_if_necessary) | |
610 LoadPlugins(false); | |
611 plugin_groups->clear(); | |
612 for (PluginGroup::PluginMap::const_iterator it = plugin_groups_.begin(); | |
613 it != plugin_groups_.end(); ++it) { | |
614 plugin_groups->push_back(*it->second); | |
615 } | |
616 } | |
617 | |
618 const PluginGroup* PluginList::GetPluginGroup( | |
619 const WebPluginInfo& web_plugin_info) { | |
620 AutoLock lock(lock_); | |
621 return AddToPluginGroups(web_plugin_info); | |
622 } | |
623 | |
624 string16 PluginList::GetPluginGroupName(std::string identifier) { | |
625 PluginGroup::PluginMap::iterator it = plugin_groups_.find(identifier); | |
626 if (it == plugin_groups_.end()) { | |
627 return string16(); | |
628 } | |
629 return it->second->GetGroupName(); | |
630 } | |
631 | |
632 std::string PluginList::GetPluginGroupIdentifier( | |
633 const WebPluginInfo& web_plugin_info) { | |
634 AutoLock lock(lock_); | |
635 PluginGroup* group = AddToPluginGroups(web_plugin_info); | |
636 return group->identifier(); | |
637 } | |
638 | |
639 void PluginList::AddHardcodedPluginGroups() { | |
640 AutoLock lock(lock_); | |
641 const PluginGroupDefinition* definitions = GetPluginGroupDefinitions(); | |
642 for (size_t i = 0; i < GetPluginGroupDefinitionsSize(); ++i) { | |
643 PluginGroup* definition_group = PluginGroup::FromPluginGroupDefinition( | |
644 definitions[i]); | |
645 std::string identifier = definition_group->identifier(); | |
646 DCHECK(plugin_groups_.find(identifier) == plugin_groups_.end()); | |
647 plugin_groups_.insert(std::make_pair(identifier, definition_group)); | |
648 } | |
649 } | |
650 | |
651 PluginGroup* PluginList::AddToPluginGroups( | |
652 const WebPluginInfo& web_plugin_info) { | |
653 PluginGroup* group = NULL; | |
654 for (PluginGroup::PluginMap::iterator it = plugin_groups_.begin(); | |
655 it != plugin_groups_.end(); ++it) { | |
656 if (it->second->Match(web_plugin_info)) | |
657 group = it->second; | |
658 } | |
659 if (!group) { | |
660 group = PluginGroup::FromWebPluginInfo(web_plugin_info); | |
661 std::string identifier = group->identifier(); | |
662 // If the identifier is not unique, use the full path. This means that we | |
663 // probably won't be able to search for this group by identifier, but at | |
664 // least it's going to be in the set of plugin groups, and if there | |
665 // is already a plug-in with the same filename, it's probably going to | |
666 // handle the same MIME types (and it has a higher priority), so this one | |
667 // is not going to run anyway. | |
668 if (plugin_groups_.find(identifier) != plugin_groups_.end()) | |
669 identifier = PluginGroup::GetLongIdentifier(web_plugin_info); | |
670 DCHECK(plugin_groups_.find(identifier) == plugin_groups_.end()); | |
671 plugin_groups_.insert(std::make_pair(identifier, group)); | |
672 } | |
673 group->AddPlugin(web_plugin_info, next_priority_++); | |
674 return group; | |
675 } | |
676 | |
677 bool PluginList::EnablePlugin(const FilePath& filename) { | |
678 AutoLock lock(lock_); | |
679 | |
680 bool did_enable = false; | |
681 | |
682 std::set<FilePath>::iterator entry = disabled_plugins_.find(filename); | |
683 if (entry == disabled_plugins_.end()) | |
684 return did_enable; // Early exit if plugin not in disabled list. | |
685 | |
686 disabled_plugins_.erase(entry); // Remove from disabled list. | |
687 | |
688 // Set enabled flags if necessary. | |
689 for (std::vector<WebPluginInfo>::iterator it = plugins_.begin(); | |
690 it != plugins_.end(); | |
691 ++it) { | |
692 if (it->path == filename) { | |
693 DCHECK(!it->enabled); // Should have been disabled. | |
694 it->enabled = true; | |
695 did_enable = true; | |
696 } | |
697 } | |
698 | |
699 return did_enable; | |
700 } | |
701 | |
702 bool PluginList::DisablePlugin(const FilePath& filename) { | |
703 AutoLock lock(lock_); | |
704 | |
705 bool did_disable = false; | |
706 | |
707 if (disabled_plugins_.find(filename) != disabled_plugins_.end()) | |
708 return did_disable; // Early exit if plugin already in disabled list. | |
709 | |
710 disabled_plugins_.insert(filename); // Add to disabled list. | |
711 | |
712 // Unset enabled flags if necessary. | |
713 for (std::vector<WebPluginInfo>::iterator it = plugins_.begin(); | |
714 it != plugins_.end(); | |
715 ++it) { | |
716 if (it->path == filename) { | |
717 DCHECK(it->enabled); // Should have been enabled. | |
718 it->enabled = false; | |
719 did_disable = true; | |
720 } | |
721 } | |
722 | |
723 return did_disable; | |
724 } | |
725 | |
726 bool PluginList::EnableGroup(bool enable, const string16& group_name) { | |
727 bool did_change = false; | |
728 { | |
729 AutoLock lock(lock_); | |
730 | |
731 std::set<string16>::iterator entry = disabled_groups_.find(group_name); | |
732 if (enable) { | |
733 if (entry == disabled_groups_.end()) | |
734 return did_change; // Early exit if group not in disabled list. | |
735 disabled_groups_.erase(entry); // Remove from disabled list. | |
736 } else { | |
737 if (entry != disabled_groups_.end()) | |
738 return did_change; // Early exit if group already in disabled list. | |
739 disabled_groups_.insert(group_name); | |
740 } | |
741 } | |
742 | |
743 for (PluginGroup::PluginMap::iterator it = plugin_groups_.begin(); | |
744 it != plugin_groups_.end(); ++it) { | |
745 if (it->second->GetGroupName() == group_name) { | |
746 if (it->second->Enabled() != enable) { | |
747 it->second->Enable(enable); | |
748 did_change = true; | |
749 break; | |
750 } | |
751 } | |
752 } | |
753 | |
754 return did_change; | |
755 } | |
756 | |
757 void PluginList::DisableOutdatedPluginGroups() { | |
758 disable_outdated_plugins_ = true; | |
759 } | |
760 | |
761 PluginList::~PluginList() { | |
762 Shutdown(); | |
763 } | |
764 | |
765 void PluginList::Shutdown() { | |
766 // TODO | |
767 // Note: plugin_groups_ contains simple pointers of type PluginGroup*, but | |
768 // since this singleton lives until the process is destroyed, no explicit | |
769 // cleanup is necessary. | |
770 // However, when running on Valgrind, we need to do the cleanup to keep the | |
771 // memory tree green. | |
772 #if defined(OS_POSIX) | |
773 if (RUNNING_ON_VALGRIND) { | |
774 STLDeleteContainerPairSecondPointers(plugin_groups_.begin(), | |
775 plugin_groups_.end()); | |
776 } | |
777 #endif | |
778 } | |
779 | |
780 } // namespace NPAPI | |
OLD | NEW |