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 34using namespace std; 35using namespace WebCore; 36 37namespace WebKit { 38 39PluginInfoStore::PluginInfoStore() 40 : m_pluginListIsUpToDate(false) 41{ 42} 43 44void PluginInfoStore::setAdditionalPluginsDirectories(const Vector<String>& directories) 45{ 46 m_additionalPluginsDirectories = directories; 47 refresh(); 48} 49 50void PluginInfoStore::refresh() 51{ 52 m_pluginListIsUpToDate = false; 53} 54 55template <typename T, typename U, typename V, typename W> 56static 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) 63typedef HashSet<String, CaseFoldingHash> PathHashSet; 64#else 65typedef HashSet<String> PathHashSet; 66#endif 67 68void 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 96void 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 110void 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 118void 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 126const Vector<PluginInfoStore::Plugin>& PluginInfoStore::plugins() 127{ 128 loadPluginsIfNecessary(); 129 130 return m_plugins; 131} 132 133PluginInfoStore::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 150PluginInfoStore::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 173static 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) 187String PluginInfoStore::getMIMETypeForExtension(const String& extension) 188{ 189 return MIMETypeRegistry::getMIMETypeForExtension(extension); 190} 191#endif 192 193PluginInfoStore::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 225PluginInfoStore::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