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/URL.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 66void PluginInfoStore::loadPluginsIfNecessary() 67{ 68 if (m_pluginListIsUpToDate) 69 return; 70 71 ListHashSet<String, 32> uniquePluginPaths; 72 73 // First, load plug-ins from the additional plug-ins directories specified. 74 for (size_t i = 0; i < m_additionalPluginsDirectories.size(); ++i) 75 addFromVector(uniquePluginPaths, pluginPathsInDirectory(m_additionalPluginsDirectories[i])); 76 77 // Then load plug-ins from the standard plug-ins directories. 78 Vector<String> directories = pluginsDirectories(); 79 for (size_t i = 0; i < directories.size(); ++i) 80 addFromVector(uniquePluginPaths, pluginPathsInDirectory(directories[i])); 81 82 // Then load plug-ins that are not in the standard plug-ins directories. 83 addFromVector(uniquePluginPaths, individualPluginPaths()); 84 85 m_plugins.clear(); 86 87 for (const auto& pluginPath : uniquePluginPaths) 88 loadPlugin(m_plugins, pluginPath); 89 90 m_pluginListIsUpToDate = true; 91 92 if (m_client) 93 m_client->pluginInfoStoreDidLoadPlugins(this); 94} 95 96void PluginInfoStore::loadPlugin(Vector<PluginModuleInfo>& plugins, const String& pluginPath) 97{ 98 PluginModuleInfo plugin; 99 100 if (!getPluginInfo(pluginPath, plugin)) 101 return; 102 103 if (!shouldUsePlugin(plugins, plugin)) 104 return; 105 106 plugins.append(plugin); 107} 108 109Vector<PluginModuleInfo> PluginInfoStore::plugins() 110{ 111 loadPluginsIfNecessary(); 112 return m_plugins; 113} 114 115PluginModuleInfo PluginInfoStore::findPluginForMIMEType(const String& mimeType, PluginData::AllowedPluginTypes allowedPluginTypes) const 116{ 117 ASSERT(!mimeType.isNull()); 118 119 for (const auto& plugin : m_plugins) { 120 if (allowedPluginTypes == PluginData::OnlyApplicationPlugins && !plugin.info.isApplicationPlugin) 121 continue; 122 123 for (const auto& mimeClassInfo : plugin.info.mimes) { 124 if (mimeClassInfo.type == mimeType) 125 return plugin; 126 } 127 } 128 129 return PluginModuleInfo(); 130} 131 132PluginModuleInfo PluginInfoStore::findPluginForExtension(const String& extension, String& mimeType, PluginData::AllowedPluginTypes allowedPluginTypes) const 133{ 134 ASSERT(!extension.isNull()); 135 136 for (const auto& plugin : m_plugins) { 137 if (allowedPluginTypes == PluginData::OnlyApplicationPlugins && !plugin.info.isApplicationPlugin) 138 continue; 139 140 for (const auto& mimeClassInfo : plugin.info.mimes) { 141 const Vector<String>& extensions = mimeClassInfo.extensions; 142 143 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end()) { 144 // We found a supported extension, set the correct MIME type. 145 mimeType = mimeClassInfo.type; 146 return plugin; 147 } 148 } 149 } 150 151 return PluginModuleInfo(); 152} 153 154static inline String pathExtension(const URL& url) 155{ 156 String extension; 157 String filename = url.lastPathComponent(); 158 if (!filename.endsWith('/')) { 159 int extensionPos = filename.reverseFind('.'); 160 if (extensionPos != -1) 161 extension = filename.substring(extensionPos + 1); 162 } 163 164 return extension; 165} 166 167#if !PLATFORM(COCOA) 168PluginModuleLoadPolicy PluginInfoStore::defaultLoadPolicyForPlugin(const PluginModuleInfo&) 169{ 170 return PluginModuleLoadNormally; 171} 172 173PluginModuleInfo PluginInfoStore::findPluginWithBundleIdentifier(const String&) 174{ 175 ASSERT_NOT_REACHED(); 176 return PluginModuleInfo(); 177} 178 179#endif 180 181PluginModuleInfo PluginInfoStore::findPlugin(String& mimeType, const URL& url, PluginData::AllowedPluginTypes allowedPluginTypes) 182{ 183 loadPluginsIfNecessary(); 184 185 // First, check if we can get the plug-in based on its MIME type. 186 if (!mimeType.isNull()) { 187 PluginModuleInfo plugin = findPluginForMIMEType(mimeType, allowedPluginTypes); 188 if (!plugin.path.isNull()) 189 return plugin; 190 } 191 192 // Next, check if any plug-ins claim to support the URL extension. 193 String extension = pathExtension(url).lower(); 194 if (!extension.isNull() && mimeType.isEmpty()) { 195 PluginModuleInfo plugin = findPluginForExtension(extension, mimeType, allowedPluginTypes); 196 if (!plugin.path.isNull()) 197 return plugin; 198 199 // Finally, try to get the MIME type from the extension in a platform specific manner and use that. 200 String extensionMimeType = MIMETypeRegistry::getMIMETypeForExtension(extension); 201 if (!extensionMimeType.isNull()) { 202 PluginModuleInfo plugin = findPluginForMIMEType(extensionMimeType, allowedPluginTypes); 203 if (!plugin.path.isNull()) { 204 mimeType = extensionMimeType; 205 return plugin; 206 } 207 } 208 } 209 210 return PluginModuleInfo(); 211} 212 213PluginModuleInfo PluginInfoStore::infoForPluginWithPath(const String& pluginPath) const 214{ 215 for (const auto& plugin : m_plugins) { 216 if (plugin.path == pluginPath) 217 return plugin; 218 } 219 220 ASSERT_NOT_REACHED(); 221 return PluginModuleInfo(); 222} 223 224} // namespace WebKit 225 226#endif // ENABLE(NETSCAPE_PLUGIN_API) 227