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