blob: 82ed5e514c5f6ed55329665a7a1b5cb10cd072ec [file] [log] [blame]
// Copyright (c) 2012 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 "chrome/browser/plugins/plugin_finder.h"
#include <stddef.h>
#include <string>
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/plugins/plugin_installer.h"
#include "chrome/browser/plugins/plugin_metadata.h"
#include "chrome/grit/browser_resources.h"
#include "content/public/common/webplugininfo.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/resource/resource_bundle.h"
#include "url/gurl.h"
namespace {
// Gets the full path of the plugin file as the identifier.
std::string GetLongIdentifier(const content::WebPluginInfo& plugin) {
return plugin.path.AsUTF8Unsafe();
}
// Gets the base name of the file path as the identifier.
std::string GetIdentifier(const content::WebPluginInfo& plugin) {
return plugin.path.BaseName().AsUTF8Unsafe();
}
// Gets the plugin group name as the plugin name if it is not empty or
// the filename without extension if the name is empty.
static std::u16string GetGroupName(const content::WebPluginInfo& plugin) {
if (!plugin.name.empty())
return plugin.name;
return plugin.path.BaseName().RemoveExtension().AsUTF16Unsafe();
}
void LoadMimeTypes(bool matching_mime_types,
const base::Value::Dict& plugin_dict,
PluginMetadata* plugin) {
base::StringPiece list_key =
matching_mime_types ? "matching_mime_types" : "mime_types";
const base::Value::List* mime_types = plugin_dict.FindList(list_key);
if (!mime_types)
return;
for (const auto& mime_type : *mime_types) {
const std::string* mime_type_str = mime_type.GetIfString();
if (!mime_type_str)
continue;
if (matching_mime_types)
plugin->AddMatchingMimeType(*mime_type_str);
else
plugin->AddMimeType(*mime_type_str);
}
}
std::unique_ptr<PluginMetadata> CreatePluginMetadata(
const std::string& identifier,
const base::Value::Dict& plugin_dict) {
std::string url;
if (const std::string* ptr = plugin_dict.FindString("url"))
url = *ptr;
std::string help_url;
if (const std::string* ptr = plugin_dict.FindString("help_url"))
help_url = *ptr;
std::u16string name;
bool success = true;
if (const std::string* ptr = plugin_dict.FindString("name"))
name = base::UTF8ToUTF16(*ptr);
else
success = false;
DCHECK(success);
bool display_url = plugin_dict.FindBool("displayurl").value_or(true);
std::u16string group_name_matcher;
if (const std::string* ptr = plugin_dict.FindString("group_name_matcher"))
group_name_matcher = base::UTF8ToUTF16(*ptr);
else
success = false;
DCHECK(success);
std::string language_str;
if (const std::string* ptr = plugin_dict.FindString("lang"))
language_str = *ptr;
bool plugin_is_deprecated =
plugin_dict.FindBool("plugin_is_deprecated").value_or(false);
std::unique_ptr<PluginMetadata> plugin = std::make_unique<PluginMetadata>(
identifier, name, display_url, GURL(url), GURL(help_url),
group_name_matcher, language_str, plugin_is_deprecated);
const base::Value::List* versions = plugin_dict.FindList("versions");
if (versions) {
for (const auto& entry : *versions) {
if (!entry.is_dict()) {
NOTREACHED();
continue;
}
const base::Value::Dict& version_dict = entry.GetDict();
std::string version;
success = true;
if (const std::string* ptr = version_dict.FindString("version"))
version = *ptr;
else
success = false;
DCHECK(success);
std::string status_str;
if (const std::string* ptr = version_dict.FindString("status"))
status_str = *ptr;
else
success = false;
DCHECK(success);
PluginMetadata::SecurityStatus status =
PluginMetadata::SECURITY_STATUS_UP_TO_DATE;
success = PluginMetadata::ParseSecurityStatus(status_str, &status);
DCHECK(success);
plugin->AddVersion(base::Version(version), status);
}
}
LoadMimeTypes(false, plugin_dict, plugin.get());
LoadMimeTypes(true, plugin_dict, plugin.get());
return plugin;
}
} // namespace
// static
PluginFinder* PluginFinder::GetInstance() {
static PluginFinder* instance = new PluginFinder();
return instance;
}
PluginFinder::PluginFinder() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Load the built-in plugin list.
base::StringPiece json_resource(
ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_PLUGIN_DB_JSON));
absl::optional<base::Value> value = base::JSONReader::Read(json_resource);
// Gracefully handle the case where we couldn't parse the built-in plugin list
// for some reason (https://crbug.com/388560). TODO(bauerb): Change back to a
// DCHECK once we have gathered more data about the underlying problem.
if (!value)
return;
base::AutoLock lock(mutex_);
const base::Value::Dict& plugin_list = value->GetDict();
for (const auto [identifier, plugin] : plugin_list) {
if (!plugin.is_dict())
continue;
DCHECK(identifier_plugin_.find(identifier) == identifier_plugin_.end());
identifier_plugin_[identifier] =
CreatePluginMetadata(identifier, plugin.GetDict());
if (installers_.find(identifier) == installers_.end())
installers_[identifier] = std::make_unique<PluginInstaller>();
}
}
PluginFinder::~PluginFinder() {
}
bool PluginFinder::FindPluginWithIdentifier(
const std::string& identifier,
PluginInstaller** installer,
std::unique_ptr<PluginMetadata>* plugin_metadata) {
base::AutoLock lock(mutex_);
auto metadata_it = identifier_plugin_.find(identifier);
if (metadata_it == identifier_plugin_.end())
return false;
*plugin_metadata = metadata_it->second->Clone();
if (installer) {
auto installer_it = installers_.find(identifier);
if (installer_it == installers_.end())
return false;
*installer = installer_it->second.get();
}
return true;
}
std::unique_ptr<PluginMetadata> PluginFinder::GetPluginMetadata(
const content::WebPluginInfo& plugin) {
base::AutoLock lock(mutex_);
for (const auto& plugin_pair : identifier_plugin_) {
if (!plugin_pair.second->MatchesPlugin(plugin))
continue;
return plugin_pair.second->Clone();
}
// The plugin metadata was not found, create a dummy one holding
// the name, identifier and group name only. Dummy plugin is not deprecated.
std::string identifier = GetIdentifier(plugin);
std::unique_ptr<PluginMetadata> metadata = std::make_unique<PluginMetadata>(
identifier, GetGroupName(plugin), false, GURL(), GURL(), plugin.name,
std::string(), false /* plugin_is_deprecated */);
for (size_t i = 0; i < plugin.mime_types.size(); ++i)
metadata->AddMatchingMimeType(plugin.mime_types[i].mime_type);
DCHECK(metadata->MatchesPlugin(plugin));
if (identifier_plugin_.find(identifier) != identifier_plugin_.end())
identifier = GetLongIdentifier(plugin);
DCHECK(identifier_plugin_.find(identifier) == identifier_plugin_.end());
identifier_plugin_[identifier] = std::move(metadata);
return identifier_plugin_[identifier]->Clone();
}