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