Home | History | Annotate | Download | only in plugins
      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/plugins/plugin_finder.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/json/json_reader.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/prefs/pref_registry_simple.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/stl_util.h"
     13 #include "base/strings/sys_string_conversions.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/browser_process.h"
     17 #include "chrome/browser/plugins/plugin_metadata.h"
     18 #include "chrome/common/pref_names.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/plugin_service.h"
     21 #include "grit/browser_resources.h"
     22 #include "ui/base/resource/resource_bundle.h"
     23 #include "url/gurl.h"
     24 
     25 #if defined(ENABLE_PLUGIN_INSTALLATION)
     26 #include "chrome/browser/plugins/plugin_installer.h"
     27 #endif
     28 
     29 using base::DictionaryValue;
     30 using content::PluginService;
     31 
     32 namespace {
     33 
     34 typedef std::map<std::string, PluginMetadata*> PluginMap;
     35 
     36 // Gets the full path of the plug-in file as the identifier.
     37 std::string GetLongIdentifier(const content::WebPluginInfo& plugin) {
     38   return plugin.path.AsUTF8Unsafe();
     39 }
     40 
     41 // Gets the base name of the file path as the identifier.
     42 std::string GetIdentifier(const content::WebPluginInfo& plugin) {
     43   return plugin.path.BaseName().AsUTF8Unsafe();
     44 }
     45 
     46 // Gets the plug-in group name as the plug-in name if it is not empty or
     47 // the filename without extension if the name is empty.
     48 static base::string16 GetGroupName(const content::WebPluginInfo& plugin) {
     49   if (!plugin.name.empty())
     50     return plugin.name;
     51 
     52   return plugin.path.BaseName().RemoveExtension().AsUTF16Unsafe();
     53 }
     54 
     55 void LoadMimeTypes(bool matching_mime_types,
     56                    const base::DictionaryValue* plugin_dict,
     57                    PluginMetadata* plugin) {
     58   const base::ListValue* mime_types = NULL;
     59   std::string list_key =
     60       matching_mime_types ? "matching_mime_types" : "mime_types";
     61   if (!plugin_dict->GetList(list_key, &mime_types))
     62     return;
     63 
     64   bool success = false;
     65   for (base::ListValue::const_iterator mime_type_it = mime_types->begin();
     66        mime_type_it != mime_types->end(); ++mime_type_it) {
     67     std::string mime_type_str;
     68     success = (*mime_type_it)->GetAsString(&mime_type_str);
     69     DCHECK(success);
     70     if (matching_mime_types) {
     71       plugin->AddMatchingMimeType(mime_type_str);
     72     } else {
     73       plugin->AddMimeType(mime_type_str);
     74     }
     75   }
     76 }
     77 
     78 PluginMetadata* CreatePluginMetadata(
     79     const std::string& identifier,
     80     const base::DictionaryValue* plugin_dict) {
     81   std::string url;
     82   bool success = plugin_dict->GetString("url", &url);
     83   std::string help_url;
     84   plugin_dict->GetString("help_url", &help_url);
     85   base::string16 name;
     86   success = plugin_dict->GetString("name", &name);
     87   DCHECK(success);
     88   bool display_url = false;
     89   plugin_dict->GetBoolean("displayurl", &display_url);
     90   base::string16 group_name_matcher;
     91   success = plugin_dict->GetString("group_name_matcher", &group_name_matcher);
     92   DCHECK(success);
     93   std::string language_str;
     94   plugin_dict->GetString("lang", &language_str);
     95 
     96   PluginMetadata* plugin = new PluginMetadata(identifier,
     97                                               name,
     98                                               display_url,
     99                                               GURL(url),
    100                                               GURL(help_url),
    101                                               group_name_matcher,
    102                                               language_str);
    103   const base::ListValue* versions = NULL;
    104   if (plugin_dict->GetList("versions", &versions)) {
    105     for (base::ListValue::const_iterator it = versions->begin();
    106          it != versions->end(); ++it) {
    107       base::DictionaryValue* version_dict = NULL;
    108       if (!(*it)->GetAsDictionary(&version_dict)) {
    109         NOTREACHED();
    110         continue;
    111       }
    112       std::string version;
    113       success = version_dict->GetString("version", &version);
    114       DCHECK(success);
    115       std::string status_str;
    116       success = version_dict->GetString("status", &status_str);
    117       DCHECK(success);
    118       PluginMetadata::SecurityStatus status =
    119           PluginMetadata::SECURITY_STATUS_UP_TO_DATE;
    120       success = PluginMetadata::ParseSecurityStatus(status_str, &status);
    121       DCHECK(success);
    122       plugin->AddVersion(Version(version), status);
    123     }
    124   }
    125 
    126   LoadMimeTypes(false, plugin_dict, plugin);
    127   LoadMimeTypes(true, plugin_dict, plugin);
    128   return plugin;
    129 }
    130 
    131 }  // namespace
    132 
    133 // static
    134 void PluginFinder::RegisterPrefs(PrefRegistrySimple* registry) {
    135   registry->RegisterBooleanPref(prefs::kDisablePluginFinder, false);
    136 }
    137 
    138 // static
    139 PluginFinder* PluginFinder::GetInstance() {
    140   // PluginFinder::GetInstance() is the only method that's allowed to call
    141   // Singleton<PluginFinder>::get().
    142   return Singleton<PluginFinder>::get();
    143 }
    144 
    145 PluginFinder::PluginFinder() : version_(-1) {
    146   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    147 }
    148 
    149 void PluginFinder::Init() {
    150   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    151   // Load the built-in plug-in list first. If we have a newer version stored
    152   // locally or download one, we will replace this one with it.
    153   scoped_ptr<base::DictionaryValue> plugin_list(LoadBuiltInPluginList());
    154   DCHECK(plugin_list);
    155   ReinitializePlugins(plugin_list.get());
    156 }
    157 
    158 // static
    159 base::DictionaryValue* PluginFinder::LoadBuiltInPluginList() {
    160   base::StringPiece json_resource(
    161       ResourceBundle::GetSharedInstance().GetRawDataResource(
    162           IDR_PLUGIN_DB_JSON));
    163   std::string error_str;
    164   scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
    165       json_resource,
    166       base::JSON_PARSE_RFC,
    167       NULL,
    168       &error_str));
    169   if (!value.get()) {
    170     DLOG(ERROR) << error_str;
    171     return NULL;
    172   }
    173   if (value->GetType() != base::Value::TYPE_DICTIONARY)
    174     return NULL;
    175   return static_cast<base::DictionaryValue*>(value.release());
    176 }
    177 
    178 PluginFinder::~PluginFinder() {
    179 #if defined(ENABLE_PLUGIN_INSTALLATION)
    180   STLDeleteValues(&installers_);
    181 #endif
    182   STLDeleteValues(&identifier_plugin_);
    183 }
    184 
    185 #if defined(ENABLE_PLUGIN_INSTALLATION)
    186 bool PluginFinder::FindPlugin(
    187     const std::string& mime_type,
    188     const std::string& language,
    189     PluginInstaller** installer,
    190     scoped_ptr<PluginMetadata>* plugin_metadata) {
    191   if (g_browser_process->local_state()->GetBoolean(prefs::kDisablePluginFinder))
    192     return false;
    193 
    194   base::AutoLock lock(mutex_);
    195   PluginMap::const_iterator metadata_it = identifier_plugin_.begin();
    196   for (; metadata_it != identifier_plugin_.end(); ++metadata_it) {
    197     if (language == metadata_it->second->language() &&
    198         metadata_it->second->HasMimeType(mime_type)) {
    199       *plugin_metadata = metadata_it->second->Clone();
    200 
    201       std::map<std::string, PluginInstaller*>::const_iterator installer_it =
    202           installers_.find(metadata_it->second->identifier());
    203       DCHECK(installer_it != installers_.end());
    204       *installer = installer_it->second;
    205       return true;
    206     }
    207   }
    208   return false;
    209 }
    210 
    211 bool PluginFinder::FindPluginWithIdentifier(
    212     const std::string& identifier,
    213     PluginInstaller** installer,
    214     scoped_ptr<PluginMetadata>* plugin_metadata) {
    215   base::AutoLock lock(mutex_);
    216   PluginMap::const_iterator metadata_it = identifier_plugin_.find(identifier);
    217   if (metadata_it == identifier_plugin_.end())
    218     return false;
    219   *plugin_metadata = metadata_it->second->Clone();
    220 
    221   if (installer) {
    222     std::map<std::string, PluginInstaller*>::const_iterator installer_it =
    223         installers_.find(identifier);
    224     if (installer_it == installers_.end())
    225       return false;
    226     *installer = installer_it->second;
    227   }
    228   return true;
    229 }
    230 #endif
    231 
    232 void PluginFinder::ReinitializePlugins(
    233     const base::DictionaryValue* plugin_list) {
    234   base::AutoLock lock(mutex_);
    235   int version = 0;  // If no version is defined, we default to 0.
    236   const char kVersionKey[] = "x-version";
    237   plugin_list->GetInteger(kVersionKey, &version);
    238   if (version <= version_)
    239     return;
    240 
    241   version_ = version;
    242 
    243   STLDeleteValues(&identifier_plugin_);
    244   identifier_plugin_.clear();
    245 
    246   for (base::DictionaryValue::Iterator plugin_it(*plugin_list);
    247       !plugin_it.IsAtEnd(); plugin_it.Advance()) {
    248     const base::DictionaryValue* plugin = NULL;
    249     const std::string& identifier = plugin_it.key();
    250     if (plugin_list->GetDictionaryWithoutPathExpansion(identifier, &plugin)) {
    251       DCHECK(!identifier_plugin_[identifier]);
    252       identifier_plugin_[identifier] = CreatePluginMetadata(identifier, plugin);
    253 
    254 #if defined(ENABLE_PLUGIN_INSTALLATION)
    255       if (installers_.find(identifier) == installers_.end())
    256         installers_[identifier] = new PluginInstaller();
    257 #endif
    258     }
    259   }
    260 }
    261 
    262 base::string16 PluginFinder::FindPluginNameWithIdentifier(
    263     const std::string& identifier) {
    264   base::AutoLock lock(mutex_);
    265   PluginMap::const_iterator it = identifier_plugin_.find(identifier);
    266   base::string16 name;
    267   if (it != identifier_plugin_.end())
    268     name = it->second->name();
    269 
    270   return name.empty() ? base::UTF8ToUTF16(identifier) : name;
    271 }
    272 
    273 scoped_ptr<PluginMetadata> PluginFinder::GetPluginMetadata(
    274     const content::WebPluginInfo& plugin) {
    275   base::AutoLock lock(mutex_);
    276   for (PluginMap::const_iterator it = identifier_plugin_.begin();
    277        it != identifier_plugin_.end(); ++it) {
    278     if (!it->second->MatchesPlugin(plugin))
    279       continue;
    280 
    281     return it->second->Clone();
    282   }
    283 
    284   // The plug-in metadata was not found, create a dummy one holding
    285   // the name, identifier and group name only.
    286   std::string identifier = GetIdentifier(plugin);
    287   PluginMetadata* metadata = new PluginMetadata(identifier,
    288                                                 GetGroupName(plugin),
    289                                                 false,
    290                                                 GURL(),
    291                                                 GURL(),
    292                                                 plugin.name,
    293                                                 std::string());
    294   for (size_t i = 0; i < plugin.mime_types.size(); ++i)
    295     metadata->AddMatchingMimeType(plugin.mime_types[i].mime_type);
    296 
    297   DCHECK(metadata->MatchesPlugin(plugin));
    298   if (identifier_plugin_.find(identifier) != identifier_plugin_.end())
    299     identifier = GetLongIdentifier(plugin);
    300 
    301   DCHECK(identifier_plugin_.find(identifier) == identifier_plugin_.end());
    302   identifier_plugin_[identifier] = metadata;
    303   return metadata->Clone();
    304 }
    305