1/* 2 * Copyright (C) 2010, 2012 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#if ENABLE(NETSCAPE_PLUGIN_API) 30 31#include "PluginModuleInfo.h" 32#include <WebCore/KURL.h> 33#include <WebCore/MIMETypeRegistry.h> 34#include <algorithm> 35#include <wtf/ListHashSet.h> 36#include <wtf/StdLibExtras.h> 37 38using namespace WebCore; 39 40namespace WebKit { 41 42PluginInfoStore::PluginInfoStore() 43 : m_pluginListIsUpToDate(false) 44 , m_client(0) 45{ 46} 47 48void PluginInfoStore::setAdditionalPluginsDirectories(const Vector<String>& directories) 49{ 50 m_additionalPluginsDirectories = directories; 51 refresh(); 52} 53 54void PluginInfoStore::refresh() 55{ 56 m_pluginListIsUpToDate = false; 57} 58 59template <typename T, typename U> 60static void addFromVector(T& hashSet, const U& vector) 61{ 62 for (size_t i = 0; i < vector.size(); ++i) 63 hashSet.add(vector[i]); 64} 65 66// We use a ListHashSet so that plugins will be loaded from the additional plugins directories first 67// (which in turn means those plugins will be preferred if two plugins claim the same MIME type). 68#if OS(WINDOWS) 69typedef ListHashSet<String, 32, CaseFoldingHash> PathHashSet; 70#else 71typedef ListHashSet<String, 32> PathHashSet; 72#endif 73 74void PluginInfoStore::loadPluginsIfNecessary() 75{ 76 if (m_pluginListIsUpToDate) 77 return; 78 79 PathHashSet uniquePluginPaths; 80 81 // First, load plug-ins from the additional plug-ins directories specified. 82 for (size_t i = 0; i < m_additionalPluginsDirectories.size(); ++i) 83 addFromVector(uniquePluginPaths, pluginPathsInDirectory(m_additionalPluginsDirectories[i])); 84 85 // Then load plug-ins from the standard plug-ins directories. 86 Vector<String> directories = pluginsDirectories(); 87 for (size_t i = 0; i < directories.size(); ++i) 88 addFromVector(uniquePluginPaths, pluginPathsInDirectory(directories[i])); 89 90 // Then load plug-ins that are not in the standard plug-ins directories. 91 addFromVector(uniquePluginPaths, individualPluginPaths()); 92 93 m_plugins.clear(); 94 95 PathHashSet::const_iterator end = uniquePluginPaths.end(); 96 for (PathHashSet::const_iterator it = uniquePluginPaths.begin(); it != end; ++it) 97 loadPlugin(m_plugins, *it); 98 99 m_pluginListIsUpToDate = true; 100 101 if (m_client) 102 m_client->pluginInfoStoreDidLoadPlugins(this); 103} 104 105void PluginInfoStore::loadPlugin(Vector<PluginModuleInfo>& plugins, const String& pluginPath) 106{ 107 PluginModuleInfo plugin; 108 109 if (!getPluginInfo(pluginPath, plugin)) 110 return; 111 112 if (!shouldUsePlugin(plugins, plugin)) 113 return; 114 115 plugins.append(plugin); 116} 117 118Vector<PluginModuleInfo> PluginInfoStore::plugins() 119{ 120 loadPluginsIfNecessary(); 121 return m_plugins; 122} 123 124PluginModuleInfo PluginInfoStore::findPluginForMIMEType(const String& mimeType, PluginData::AllowedPluginTypes allowedPluginTypes) const 125{ 126 ASSERT(!mimeType.isNull()); 127 128 for (size_t i = 0; i < m_plugins.size(); ++i) { 129 const PluginModuleInfo& plugin = m_plugins[i]; 130 131 if (allowedPluginTypes == PluginData::OnlyApplicationPlugins && !plugin.info.isApplicationPlugin) 132 continue; 133 134 for (size_t j = 0; j < plugin.info.mimes.size(); ++j) { 135 const MimeClassInfo& mimeClassInfo = plugin.info.mimes[j]; 136 if (mimeClassInfo.type == mimeType) 137 return plugin; 138 } 139 } 140 141 return PluginModuleInfo(); 142} 143 144PluginModuleInfo PluginInfoStore::findPluginForExtension(const String& extension, String& mimeType, PluginData::AllowedPluginTypes allowedPluginTypes) const 145{ 146 ASSERT(!extension.isNull()); 147 148 for (size_t i = 0; i < m_plugins.size(); ++i) { 149 const PluginModuleInfo& plugin = m_plugins[i]; 150 151 if (allowedPluginTypes == PluginData::OnlyApplicationPlugins && !plugin.info.isApplicationPlugin) 152 continue; 153 154 for (size_t j = 0; j < plugin.info.mimes.size(); ++j) { 155 const MimeClassInfo& mimeClassInfo = plugin.info.mimes[j]; 156 157 const Vector<String>& extensions = mimeClassInfo.extensions; 158 159 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end()) { 160 // We found a supported extension, set the correct MIME type. 161 mimeType = mimeClassInfo.type; 162 return plugin; 163 } 164 } 165 } 166 167 return PluginModuleInfo(); 168} 169 170static inline String pathExtension(const KURL& url) 171{ 172 String extension; 173 String filename = url.lastPathComponent(); 174 if (!filename.endsWith('/')) { 175 int extensionPos = filename.reverseFind('.'); 176 if (extensionPos != -1) 177 extension = filename.substring(extensionPos + 1); 178 } 179 180 return extension; 181} 182 183#if !PLATFORM(MAC) 184PluginModuleLoadPolicy PluginInfoStore::defaultLoadPolicyForPlugin(const PluginModuleInfo&) 185{ 186 return PluginModuleLoadNormally; 187} 188 189String PluginInfoStore::getMIMETypeForExtension(const String& extension) 190{ 191 return MIMETypeRegistry::getMIMETypeForExtension(extension); 192} 193 194PluginModuleInfo PluginInfoStore::findPluginWithBundleIdentifier(const String&) 195{ 196 ASSERT_NOT_REACHED(); 197 return PluginModuleInfo(); 198} 199 200#endif 201 202PluginModuleInfo PluginInfoStore::findPlugin(String& mimeType, const KURL& url, PluginData::AllowedPluginTypes allowedPluginTypes) 203{ 204 loadPluginsIfNecessary(); 205 206 // First, check if we can get the plug-in based on its MIME type. 207 if (!mimeType.isNull()) { 208 PluginModuleInfo plugin = findPluginForMIMEType(mimeType, allowedPluginTypes); 209 if (!plugin.path.isNull()) 210 return plugin; 211 } 212 213 // Next, check if any plug-ins claim to support the URL extension. 214 String extension = pathExtension(url).lower(); 215 if (!extension.isNull() && mimeType.isEmpty()) { 216 PluginModuleInfo plugin = findPluginForExtension(extension, mimeType, allowedPluginTypes); 217 if (!plugin.path.isNull()) 218 return plugin; 219 220 // Finally, try to get the MIME type from the extension in a platform specific manner and use that. 221 String extensionMimeType = getMIMETypeForExtension(extension); 222 if (!extensionMimeType.isNull()) { 223 PluginModuleInfo plugin = findPluginForMIMEType(extensionMimeType, allowedPluginTypes); 224 if (!plugin.path.isNull()) { 225 mimeType = extensionMimeType; 226 return plugin; 227 } 228 } 229 } 230 231 return PluginModuleInfo(); 232} 233 234PluginModuleInfo PluginInfoStore::infoForPluginWithPath(const String& pluginPath) const 235{ 236 for (size_t i = 0; i < m_plugins.size(); ++i) { 237 if (m_plugins[i].path == pluginPath) 238 return m_plugins[i]; 239 } 240 241 ASSERT_NOT_REACHED(); 242 return PluginModuleInfo(); 243} 244 245} // namespace WebKit 246 247#endif // ENABLE(NETSCAPE_PLUGIN_API) 248