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 DictionaryValue* plugin_dict, 57 PluginMetadata* plugin) { 58 const 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 (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 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 ListValue* versions = NULL; 104 if (plugin_dict->GetList("versions", &versions)) { 105 for (ListValue::const_iterator it = versions->begin(); 106 it != versions->end(); ++it) { 107 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<DictionaryValue> plugin_list(LoadBuiltInPluginList()); 154 DCHECK(plugin_list); 155 ReinitializePlugins(plugin_list.get()); 156 } 157 158 // static 159 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 (DictionaryValue::Iterator plugin_it(*plugin_list); 247 !plugin_it.IsAtEnd(); plugin_it.Advance()) { 248 const 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() ? 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