Home | History | Annotate | Download | only in Plugins
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "PluginInfoStore.h"
     28 
     29 #include <WebCore/KURL.h>
     30 #include <WebCore/MIMETypeRegistry.h>
     31 #include <algorithm>
     32 #include <wtf/StdLibExtras.h>
     33 
     34 using namespace std;
     35 using namespace WebCore;
     36 
     37 namespace WebKit {
     38 
     39 PluginInfoStore::PluginInfoStore()
     40     : m_pluginListIsUpToDate(false)
     41 {
     42 }
     43 
     44 void PluginInfoStore::setAdditionalPluginsDirectories(const Vector<String>& directories)
     45 {
     46     m_additionalPluginsDirectories = directories;
     47     refresh();
     48 }
     49 
     50 void PluginInfoStore::refresh()
     51 {
     52     m_pluginListIsUpToDate = false;
     53 }
     54 
     55 template <typename T, typename U, typename V, typename W>
     56 static void addFromVector(HashSet<T, U, V>& hashSet, const W& vector)
     57 {
     58     for (size_t i = 0; i < vector.size(); ++i)
     59         hashSet.add(vector[i]);
     60 }
     61 
     62 #if OS(WINDOWS)
     63 typedef HashSet<String, CaseFoldingHash> PathHashSet;
     64 #else
     65 typedef HashSet<String> PathHashSet;
     66 #endif
     67 
     68 void PluginInfoStore::loadPluginsIfNecessary()
     69 {
     70     if (m_pluginListIsUpToDate)
     71         return;
     72 
     73     m_plugins.clear();
     74 
     75     PathHashSet uniquePluginPaths;
     76 
     77     // First, load plug-ins from the additional plug-ins directories specified.
     78     for (size_t i = 0; i < m_additionalPluginsDirectories.size(); ++i)
     79         addFromVector(uniquePluginPaths, pluginPathsInDirectory(m_additionalPluginsDirectories[i]));
     80 
     81     // Then load plug-ins from the standard plug-ins directories.
     82     Vector<String> directories = pluginsDirectories();
     83     for (size_t i = 0; i < directories.size(); ++i)
     84         addFromVector(uniquePluginPaths, pluginPathsInDirectory(directories[i]));
     85 
     86     // Then load plug-ins that are not in the standard plug-ins directories.
     87     addFromVector(uniquePluginPaths, individualPluginPaths());
     88 
     89     PathHashSet::const_iterator end = uniquePluginPaths.end();
     90     for (PathHashSet::const_iterator it = uniquePluginPaths.begin(); it != end; ++it)
     91         loadPlugin(*it);
     92 
     93     m_pluginListIsUpToDate = true;
     94 }
     95 
     96 void PluginInfoStore::loadPlugin(const String& pluginPath)
     97 {
     98     Plugin plugin;
     99 
    100     if (!getPluginInfo(pluginPath, plugin))
    101         return;
    102 
    103     if (!shouldUsePlugin(plugin))
    104         return;
    105 
    106     // Add the plug-in.
    107     m_plugins.append(plugin);
    108 }
    109 
    110 void PluginInfoStore::getPlugins(Vector<PluginInfo>& plugins)
    111 {
    112     loadPluginsIfNecessary();
    113 
    114     for (size_t i = 0; i < m_plugins.size(); ++i)
    115         plugins.append(m_plugins[i].info);
    116 }
    117 
    118 void PluginInfoStore::getPluginPaths(Vector<String>& pluginPaths)
    119 {
    120     loadPluginsIfNecessary();
    121 
    122     for (size_t i = 0; i < m_plugins.size(); ++i)
    123         pluginPaths.append(m_plugins[i].path);
    124 }
    125 
    126 const Vector<PluginInfoStore::Plugin>& PluginInfoStore::plugins()
    127 {
    128     loadPluginsIfNecessary();
    129 
    130     return m_plugins;
    131 }
    132 
    133 PluginInfoStore::Plugin PluginInfoStore::findPluginForMIMEType(const String& mimeType)
    134 {
    135     ASSERT(!mimeType.isNull());
    136 
    137     for (size_t i = 0; i < m_plugins.size(); ++i) {
    138         const Plugin& plugin = m_plugins[i];
    139 
    140         for (size_t j = 0; j < plugin.info.mimes.size(); ++j) {
    141             const MimeClassInfo& mimeClassInfo = plugin.info.mimes[j];
    142             if (mimeClassInfo.type == mimeType)
    143                 return plugin;
    144         }
    145     }
    146 
    147     return Plugin();
    148 }
    149 
    150 PluginInfoStore::Plugin PluginInfoStore::findPluginForExtension(const String& extension, String& mimeType)
    151 {
    152     ASSERT(!extension.isNull());
    153 
    154     for (size_t i = 0; i < m_plugins.size(); ++i) {
    155         const Plugin& plugin = m_plugins[i];
    156 
    157         for (size_t j = 0; j < plugin.info.mimes.size(); ++j) {
    158             const MimeClassInfo& mimeClassInfo = plugin.info.mimes[j];
    159 
    160             const Vector<String>& extensions = mimeClassInfo.extensions;
    161 
    162             if (find(extensions.begin(), extensions.end(), extension) != extensions.end()) {
    163                 // We found a supported extension, set the correct MIME type.
    164                 mimeType = mimeClassInfo.type;
    165                 return plugin;
    166             }
    167         }
    168     }
    169 
    170     return Plugin();
    171 }
    172 
    173 static inline String pathExtension(const KURL& url)
    174 {
    175     String extension;
    176     String filename = url.lastPathComponent();
    177     if (!filename.endsWith("/")) {
    178         int extensionPos = filename.reverseFind('.');
    179         if (extensionPos != -1)
    180             extension = filename.substring(extensionPos + 1);
    181     }
    182 
    183     return extension;
    184 }
    185 
    186 #if !PLATFORM(MAC)
    187 String PluginInfoStore::getMIMETypeForExtension(const String& extension)
    188 {
    189     return MIMETypeRegistry::getMIMETypeForExtension(extension);
    190 }
    191 #endif
    192 
    193 PluginInfoStore::Plugin PluginInfoStore::findPlugin(String& mimeType, const KURL& url)
    194 {
    195     loadPluginsIfNecessary();
    196 
    197     // First, check if we can get the plug-in based on its MIME type.
    198     if (!mimeType.isNull()) {
    199         Plugin plugin = findPluginForMIMEType(mimeType);
    200         if (!plugin.path.isNull())
    201             return plugin;
    202     }
    203 
    204     // Next, check if any plug-ins claim to support the URL extension.
    205     String extension = pathExtension(url).lower();
    206     if (!extension.isNull() && mimeType.isEmpty()) {
    207         Plugin plugin = findPluginForExtension(extension, mimeType);
    208         if (!plugin.path.isNull())
    209             return plugin;
    210 
    211         // Finally, try to get the MIME type from the extension in a platform specific manner and use that.
    212         String extensionMimeType = getMIMETypeForExtension(extension);
    213         if (!extensionMimeType.isNull()) {
    214             Plugin plugin = findPluginForMIMEType(extensionMimeType);
    215             if (!plugin.path.isNull()) {
    216                 mimeType = extensionMimeType;
    217                 return plugin;
    218             }
    219         }
    220     }
    221 
    222     return Plugin();
    223 }
    224 
    225 PluginInfoStore::Plugin PluginInfoStore::infoForPluginWithPath(const String& pluginPath)
    226 {
    227     for (size_t i = 0; i < m_plugins.size(); ++i) {
    228         if (m_plugins[i].path == pluginPath)
    229             return m_plugins[i];
    230     }
    231 
    232     ASSERT_NOT_REACHED();
    233     return Plugin();
    234 }
    235 
    236 } // namespace WebKit
    237