Home | History | Annotate | Download | only in extensions
      1 // Copyright 2013 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 "base/files/file_path.h"
      6 #include "base/lazy_instance.h"
      7 #include "base/path_service.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/browser/extensions/extension_service.h"
     10 #include "chrome/browser/extensions/plugin_manager.h"
     11 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/common/chrome_paths.h"
     14 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
     15 #include "chrome/common/extensions/manifest_handlers/mime_types_handler.h"
     16 #include "content/public/browser/plugin_service.h"
     17 #include "content/public/common/pepper_plugin_info.h"
     18 #include "extensions/browser/extension_registry.h"
     19 #include "extensions/common/extension.h"
     20 #include "url/gurl.h"
     21 
     22 #if !defined(DISABLE_NACL)
     23 #include "components/nacl/common/nacl_constants.h"
     24 #endif
     25 
     26 using content::PluginService;
     27 
     28 namespace extensions {
     29 
     30 PluginManager::PluginManager(content::BrowserContext* context)
     31     : profile_(Profile::FromBrowserContext(context)),
     32       extension_registry_observer_(this) {
     33   extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
     34 }
     35 
     36 PluginManager::~PluginManager() {
     37 }
     38 
     39 static base::LazyInstance<BrowserContextKeyedAPIFactory<PluginManager> >
     40     g_factory = LAZY_INSTANCE_INITIALIZER;
     41 
     42 // static
     43 BrowserContextKeyedAPIFactory<PluginManager>*
     44 PluginManager::GetFactoryInstance() {
     45   return g_factory.Pointer();
     46 }
     47 
     48 void PluginManager::OnExtensionLoaded(content::BrowserContext* browser_context,
     49                                       const Extension* extension) {
     50   bool plugins_or_nacl_changed = false;
     51   if (PluginInfo::HasPlugins(extension)) {
     52     const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension);
     53     CHECK(plugins);
     54     plugins_or_nacl_changed = true;
     55     for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
     56          plugin != plugins->end();
     57          ++plugin) {
     58       PluginService::GetInstance()->RefreshPlugins();
     59       PluginService::GetInstance()->AddExtraPluginPath(plugin->path);
     60       ChromePluginServiceFilter* filter =
     61           ChromePluginServiceFilter::GetInstance();
     62       if (plugin->is_public) {
     63         filter->RestrictPluginToProfileAndOrigin(
     64             plugin->path, profile_, GURL());
     65       } else {
     66         filter->RestrictPluginToProfileAndOrigin(
     67             plugin->path, profile_, extension->url());
     68       }
     69     }
     70   }
     71 
     72 #if !defined(DISABLE_NACL)
     73   const NaClModuleInfo::List* nacl_modules =
     74       NaClModuleInfo::GetNaClModules(extension);
     75   if (nacl_modules) {
     76     plugins_or_nacl_changed = true;
     77     for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
     78          module != nacl_modules->end();
     79          ++module) {
     80       RegisterNaClModule(*module);
     81     }
     82     UpdatePluginListWithNaClModules();
     83   }
     84 #endif
     85 
     86   const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
     87   if (handler && !handler->handler_url().empty()) {
     88     plugins_or_nacl_changed = true;
     89 
     90     content::WebPluginInfo info;
     91     info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
     92     info.name = base::UTF8ToUTF16(handler->extension_id());
     93     info.path = base::FilePath::FromUTF8Unsafe(handler->extension_id());
     94 
     95     for (std::set<std::string>::const_iterator mime_type =
     96          handler->mime_type_set().begin();
     97          mime_type != handler->mime_type_set().end(); ++mime_type) {
     98       content::WebPluginMimeType mime_type_info;
     99       mime_type_info.mime_type = *mime_type;
    100       info.mime_types.push_back(mime_type_info);
    101     }
    102 
    103     PluginService::GetInstance()->RefreshPlugins();
    104     PluginService::GetInstance()->RegisterInternalPlugin(info, true);
    105   }
    106 
    107   if (plugins_or_nacl_changed)
    108     PluginService::GetInstance()->PurgePluginListCache(profile_, false);
    109 }
    110 
    111 void PluginManager::OnExtensionUnloaded(
    112     content::BrowserContext* browser_context,
    113     const Extension* extension,
    114     UnloadedExtensionInfo::Reason reason) {
    115   bool plugins_or_nacl_changed = false;
    116   if (PluginInfo::HasPlugins(extension)) {
    117     const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension);
    118     plugins_or_nacl_changed = true;
    119     for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
    120          plugin != plugins->end();
    121          ++plugin) {
    122       PluginService::GetInstance()->ForcePluginShutdown(plugin->path);
    123       PluginService::GetInstance()->RefreshPlugins();
    124       PluginService::GetInstance()->RemoveExtraPluginPath(plugin->path);
    125       ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin->path);
    126     }
    127   }
    128 
    129 #if !defined(DISABLE_NACL)
    130   const NaClModuleInfo::List* nacl_modules =
    131       NaClModuleInfo::GetNaClModules(extension);
    132   if (nacl_modules) {
    133     plugins_or_nacl_changed = true;
    134     for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
    135          module != nacl_modules->end();
    136          ++module) {
    137       UnregisterNaClModule(*module);
    138     }
    139     UpdatePluginListWithNaClModules();
    140   }
    141 #endif
    142 
    143   const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
    144   if (handler && !handler->handler_url().empty()) {
    145     plugins_or_nacl_changed = true;
    146     base::FilePath path =
    147         base::FilePath::FromUTF8Unsafe(handler->extension_id());
    148     PluginService::GetInstance()->UnregisterInternalPlugin(path);
    149     PluginService::GetInstance()->ForcePluginShutdown(path);
    150     PluginService::GetInstance()->RefreshPlugins();
    151   }
    152 
    153   if (plugins_or_nacl_changed)
    154     PluginService::GetInstance()->PurgePluginListCache(profile_, false);
    155 }
    156 
    157 #if !defined(DISABLE_NACL)
    158 
    159 void PluginManager::RegisterNaClModule(const NaClModuleInfo& info) {
    160   DCHECK(FindNaClModule(info.url) == nacl_module_list_.end());
    161   nacl_module_list_.push_front(info);
    162 }
    163 
    164 void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) {
    165   NaClModuleInfo::List::iterator iter = FindNaClModule(info.url);
    166   DCHECK(iter != nacl_module_list_.end());
    167   nacl_module_list_.erase(iter);
    168 }
    169 
    170 void PluginManager::UpdatePluginListWithNaClModules() {
    171   // An extension has been added which has a nacl_module component, which means
    172   // there is a MIME type that module wants to handle, so we need to add that
    173   // MIME type to plugins which handle NaCl modules in order to allow the
    174   // individual modules to handle these types.
    175   base::FilePath path;
    176   if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path))
    177     return;
    178   const content::PepperPluginInfo* pepper_info =
    179       PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
    180   if (!pepper_info)
    181     return;
    182 
    183   std::vector<content::WebPluginMimeType>::const_iterator mime_iter;
    184   // Check each MIME type the plugins handle for the NaCl MIME type.
    185   for (mime_iter = pepper_info->mime_types.begin();
    186        mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
    187     if (mime_iter->mime_type == nacl::kNaClPluginMimeType) {
    188       // This plugin handles "application/x-nacl".
    189 
    190       PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path);
    191 
    192       content::WebPluginInfo info = pepper_info->ToWebPluginInfo();
    193 
    194       for (NaClModuleInfo::List::const_iterator iter =
    195                nacl_module_list_.begin();
    196            iter != nacl_module_list_.end(); ++iter) {
    197         // Add the MIME type specified in the extension to this NaCl plugin,
    198         // With an extra "nacl" argument to specify the location of the NaCl
    199         // manifest file.
    200         content::WebPluginMimeType mime_type_info;
    201         mime_type_info.mime_type = iter->mime_type;
    202         mime_type_info.additional_param_names.push_back(
    203             base::UTF8ToUTF16("nacl"));
    204         mime_type_info.additional_param_values.push_back(
    205             base::UTF8ToUTF16(iter->url.spec()));
    206         info.mime_types.push_back(mime_type_info);
    207       }
    208 
    209       PluginService::GetInstance()->RefreshPlugins();
    210       PluginService::GetInstance()->RegisterInternalPlugin(info, true);
    211       // This plugin has been modified, no need to check the rest of its
    212       // types, but continue checking other plugins.
    213       break;
    214     }
    215   }
    216 }
    217 
    218 NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) {
    219   for (NaClModuleInfo::List::iterator iter = nacl_module_list_.begin();
    220        iter != nacl_module_list_.end(); ++iter) {
    221     if (iter->url == url)
    222       return iter;
    223   }
    224   return nacl_module_list_.end();
    225 }
    226 
    227 #endif  // !defined(DISABLE_NACL)
    228 
    229 }  // namespace extensions
    230