blob: f7643b492adb88c253aacea7afd472d24964c1c3 [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "webkit/glue/plugins/plugin_list.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
#include "net/base/mime_util.h"
#include "webkit/default_plugin/plugin_main.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/webkit_glue.h"
#include "googleurl/src/gurl.h"
namespace NPAPI {
base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED);
// static
PluginList* PluginList::Singleton() {
return g_singleton.Pointer();
}
bool PluginList::PluginsLoaded() {
AutoLock lock(lock_);
return plugins_loaded_;
}
void PluginList::ResetPluginsLoaded() {
AutoLock lock(lock_);
plugins_loaded_ = false;
}
void PluginList::AddExtraPluginPath(const FilePath& plugin_path) {
AutoLock lock(lock_);
extra_plugin_paths_.push_back(plugin_path);
}
void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
AutoLock lock(lock_);
std::vector<FilePath>::iterator it =
std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
plugin_path);
if (it != extra_plugin_paths_.end())
extra_plugin_paths_.erase(it);
}
void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) {
AutoLock lock(lock_);
extra_plugin_dirs_.push_back(plugin_dir);
}
void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) {
AutoLock lock(lock_);
internal_plugins_.push_back(info);
}
bool PluginList::ReadPluginInfo(const FilePath &filename,
WebPluginInfo* info,
const PluginEntryPoints** entry_points) {
{
AutoLock lock(lock_);
for (size_t i = 0; i < internal_plugins_.size(); ++i) {
if (filename == internal_plugins_[i].path) {
*entry_points = &internal_plugins_[i].entry_points;
return CreateWebPluginInfo(internal_plugins_[i], info);
}
}
}
// Not an internal plugin.
*entry_points = NULL;
return PluginLib::ReadWebPluginInfo(filename, info);
}
bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
WebPluginInfo* info) {
std::vector<std::string> mime_types, file_extensions;
std::vector<std::wstring> descriptions;
SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types);
SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions);
SplitString(pvi.type_descriptions, '|', &descriptions);
info->mime_types.clear();
if (mime_types.empty())
return false;
info->name = pvi.product_name;
info->desc = pvi.file_description;
info->version = pvi.file_version;
info->path = pvi.path;
for (size_t i = 0; i < mime_types.size(); ++i) {
WebPluginMimeType mime_type;
mime_type.mime_type = StringToLowerASCII(mime_types[i]);
if (file_extensions.size() > i)
SplitString(file_extensions[i], ',', &mime_type.file_extensions);
if (descriptions.size() > i) {
mime_type.description = descriptions[i];
// On Windows, the description likely has a list of file extensions
// embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension
// list from the description if it is present.
size_t ext = mime_type.description.find(L"(*");
if (ext != std::wstring::npos) {
if (ext > 1 && mime_type.description[ext -1] == ' ')
ext--;
mime_type.description.erase(ext);
}
}
info->mime_types.push_back(mime_type);
}
return true;
}
PluginList::PluginList() : plugins_loaded_(false) {
PlatformInit();
#if defined(OS_WIN)
const PluginVersionInfo default_plugin = {
FilePath(kDefaultPluginLibraryName),
L"Default Plug-in",
L"Provides functionality for installing third-party plug-ins",
L"1",
L"*",
L"",
L"",
{
default_plugin::NP_GetEntryPoints,
default_plugin::NP_Initialize,
default_plugin::NP_Shutdown
}
};
internal_plugins_.push_back(default_plugin);
#endif
}
void PluginList::LoadPlugins(bool refresh) {
// Don't want to hold the lock while loading new plugins, so we don't block
// other methods if they're called on other threads.
std::vector<FilePath> extra_plugin_paths;
std::vector<FilePath> extra_plugin_dirs;
std::vector<PluginVersionInfo> internal_plugins;
{
AutoLock lock(lock_);
if (plugins_loaded_ && !refresh)
return;
extra_plugin_paths = extra_plugin_paths_;
extra_plugin_dirs = extra_plugin_dirs_;
internal_plugins = internal_plugins_;
}
base::TimeTicks start_time = base::TimeTicks::Now();
std::vector<WebPluginInfo> new_plugins;
std::vector<FilePath> directories_to_scan;
GetPluginDirectories(&directories_to_scan);
// Load internal plugins first so that, if both an internal plugin and a
// "discovered" plugin want to handle the same type, the internal plugin
// will have precedence.
for (size_t i = 0; i < internal_plugins.size(); ++i) {
if (internal_plugins[i].path.value() == kDefaultPluginLibraryName)
continue;
LoadPlugin(internal_plugins[i].path, &new_plugins);
}
for (size_t i = 0; i < extra_plugin_paths.size(); ++i)
LoadPlugin(extra_plugin_paths[i], &new_plugins);
for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) {
LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins);
}
for (size_t i = 0; i < directories_to_scan.size(); ++i) {
LoadPluginsFromDir(directories_to_scan[i], &new_plugins);
}
// Load the default plugin last.
if (webkit_glue::IsDefaultPluginEnabled())
LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);
base::TimeTicks end_time = base::TimeTicks::Now();
base::TimeDelta elapsed = end_time - start_time;
DLOG(INFO) << "Loaded plugin list in " << elapsed.InMilliseconds() << " ms.";
AutoLock lock(lock_);
plugins_ = new_plugins;
plugins_loaded_ = true;
}
void PluginList::LoadPlugin(const FilePath &path,
std::vector<WebPluginInfo>* plugins) {
WebPluginInfo plugin_info;
const PluginEntryPoints* entry_points;
if (!ReadPluginInfo(path, &plugin_info, &entry_points))
return;
if (!ShouldLoadPlugin(plugin_info, plugins))
return;
if (path.value() != kDefaultPluginLibraryName
#if defined(OS_WIN) && !defined(NDEBUG)
&& path.BaseName().value() != L"npspy.dll" // Make an exception for NPSPY
#endif
) {
for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
// TODO: don't load global handlers for now.
// WebKit hands to the Plugin before it tries
// to handle mimeTypes on its own.
const std::string &mime_type = plugin_info.mime_types[i].mime_type;
if (mime_type == "*" )
return;
}
}
plugins->push_back(plugin_info);
}
bool PluginList::FindPlugin(const std::string& mime_type,
bool allow_wildcard,
WebPluginInfo* info) {
DCHECK(mime_type == StringToLowerASCII(mime_type));
LoadPlugins(false);
AutoLock lock(lock_);
for (size_t i = 0; i < plugins_.size(); ++i) {
if (SupportsType(plugins_[i], mime_type, allow_wildcard)) {
*info = plugins_[i];
return true;
}
}
return false;
}
bool PluginList::FindPlugin(const GURL &url,
std::string* actual_mime_type,
WebPluginInfo* info) {
LoadPlugins(false);
AutoLock lock(lock_);
std::string path = url.path();
std::string::size_type last_dot = path.rfind('.');
if (last_dot == std::string::npos)
return false;
std::string extension = StringToLowerASCII(std::string(path, last_dot+1));
for (size_t i = 0; i < plugins_.size(); ++i) {
if (SupportsExtension(plugins_[i], extension, actual_mime_type)) {
*info = plugins_[i];
return true;
}
}
return false;
}
bool PluginList::SupportsType(const WebPluginInfo& info,
const std::string &mime_type,
bool allow_wildcard) {
// Webkit will ask for a plugin to handle empty mime types.
if (mime_type.empty())
return false;
for (size_t i = 0; i < info.mime_types.size(); ++i) {
const WebPluginMimeType& mime_info = info.mime_types[i];
if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
if (!allow_wildcard && mime_info.mime_type == "*") {
continue;
}
return true;
}
}
return false;
}
bool PluginList::SupportsExtension(const WebPluginInfo& info,
const std::string &extension,
std::string* actual_mime_type) {
for (size_t i = 0; i < info.mime_types.size(); ++i) {
const WebPluginMimeType& mime_type = info.mime_types[i];
for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
if (mime_type.file_extensions[j] == extension) {
if (actual_mime_type)
*actual_mime_type = mime_type.mime_type;
return true;
}
}
}
return false;
}
void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
LoadPlugins(refresh);
AutoLock lock(lock_);
*plugins = plugins_;
}
bool PluginList::GetPluginInfo(const GURL& url,
const std::string& mime_type,
bool allow_wildcard,
WebPluginInfo* info,
std::string* actual_mime_type) {
bool found = FindPlugin(mime_type, allow_wildcard, info);
if (!found || (info->path.value() == kDefaultPluginLibraryName)) {
WebPluginInfo info2;
if (FindPlugin(url, actual_mime_type, &info2)) {
found = true;
*info = info2;
}
}
return found;
}
bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path,
WebPluginInfo* info) {
LoadPlugins(false);
AutoLock lock(lock_);
for (size_t i = 0; i < plugins_.size(); ++i) {
if (plugins_[i].path == plugin_path) {
*info = plugins_[i];
return true;
}
}
return false;
}
void PluginList::Shutdown() {
// TODO
}
} // namespace NPAPI