| 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 |