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