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