1/*
2 Copyright (C) 2000 Harri Porten (porten@kde.org)
3 Copyright (C) 2000 Daniel Molkentin (molkentin@kde.org)
4 Copyright (C) 2000 Stefan Schimanski (schimmi@kde.org)
5 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2015 Apple Inc. All Rights Reserved.
6 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23
24#include "config.h"
25#include "PluginData.h"
26
27#include "Document.h"
28#include "Frame.h"
29#include "LocalizedStrings.h"
30#include "Page.h"
31#include "PluginInfoProvider.h"
32
33namespace WebCore {
34
35PluginData::PluginData(Page& page)
36 : m_page(page)
37{
38 initPlugins();
39}
40
41const Vector<PluginInfo>& PluginData::webVisiblePlugins() const
42{
43 auto documentURL = m_page.mainFrame().document() ? m_page.mainFrame().document()->url() : URL { };
44 if (!documentURL.isNull() && !protocolHostAndPortAreEqual(m_cachedVisiblePlugins.pageURL, documentURL)) {
45 m_cachedVisiblePlugins.pageURL = WTFMove(documentURL);
46 m_cachedVisiblePlugins.pluginList = WTF::nullopt;
47 }
48
49 if (!m_cachedVisiblePlugins.pluginList)
50 m_cachedVisiblePlugins.pluginList = m_page.pluginInfoProvider().webVisiblePluginInfo(m_page, m_cachedVisiblePlugins.pageURL);
51
52 return *m_cachedVisiblePlugins.pluginList;
53}
54
55#if PLATFORM(COCOA)
56static inline bool isBuiltInPDFPlugIn(const PluginInfo& plugin)
57{
58 return equalLettersIgnoringASCIICase(plugin.bundleIdentifier, "com.apple.webkit.builtinpdfplugin");
59}
60#else
61static inline bool isBuiltInPDFPlugIn(const PluginInfo&)
62{
63 return false;
64}
65#endif
66
67static bool shouldBePubliclyVisible(const PluginInfo& plugin)
68{
69 // We can greatly reduce fingerprinting opportunities by only advertising plug-ins
70 // that are widely needed for general website compatibility. Since many users
71 // will have these plug-ins, we are not revealing much user-specific information.
72 //
73 // Web compatibility data indicate that Flash, QuickTime, Java, and PDF support
74 // are frequently accessed through the bad practice of iterating over the contents
75 // of the navigator.plugins list. Luckily, these plug-ins happen to be the least
76 // user-specific.
77 return plugin.name.containsIgnoringASCIICase("Shockwave")
78 || plugin.name.containsIgnoringASCIICase("QuickTime")
79 || plugin.name.containsIgnoringASCIICase("Java")
80 || isBuiltInPDFPlugIn(plugin);
81}
82
83Vector<PluginInfo> PluginData::publiclyVisiblePlugins() const
84{
85 auto plugins = webVisiblePlugins();
86
87 if (m_page.showAllPlugins())
88 return plugins;
89
90 plugins.removeAllMatching([](auto& plugin) {
91 return !shouldBePubliclyVisible(plugin);
92 });
93
94 std::sort(plugins.begin(), plugins.end(), [](const PluginInfo& a, const PluginInfo& b) {
95 return codePointCompareLessThan(a.name, b.name);
96 });
97 return plugins;
98}
99
100void PluginData::getWebVisibleMimesAndPluginIndices(Vector<MimeClassInfo>& mimes, Vector<size_t>& mimePluginIndices) const
101{
102 getMimesAndPluginIndiciesForPlugins(webVisiblePlugins(), mimes, mimePluginIndices);
103}
104
105void PluginData::getMimesAndPluginIndices(Vector<MimeClassInfo>& mimes, Vector<size_t>& mimePluginIndices) const
106{
107 getMimesAndPluginIndiciesForPlugins(plugins(), mimes, mimePluginIndices);
108}
109
110void PluginData::getMimesAndPluginIndiciesForPlugins(const Vector<PluginInfo>& plugins, Vector<MimeClassInfo>& mimes, Vector<size_t>& mimePluginIndices) const
111{
112 ASSERT_ARG(mimes, mimes.isEmpty());
113 ASSERT_ARG(mimePluginIndices, mimePluginIndices.isEmpty());
114
115 for (unsigned i = 0; i < plugins.size(); ++i) {
116 const PluginInfo& plugin = plugins[i];
117 for (auto& mime : plugin.mimes) {
118 mimes.append(mime);
119 mimePluginIndices.append(i);
120 }
121 }
122}
123
124bool PluginData::supportsWebVisibleMimeTypeForURL(const String& mimeType, const AllowedPluginTypes allowedPluginTypes, const URL& url) const
125{
126 if (!protocolHostAndPortAreEqual(m_cachedVisiblePlugins.pageURL, url))
127 m_cachedVisiblePlugins = { url, m_page.pluginInfoProvider().webVisiblePluginInfo(m_page, url) };
128 if (!m_cachedVisiblePlugins.pluginList)
129 return false;
130 return supportsWebVisibleMimeType(mimeType, allowedPluginTypes, *m_cachedVisiblePlugins.pluginList);
131}
132
133bool PluginData::supportsWebVisibleMimeType(const String& mimeType, const AllowedPluginTypes allowedPluginTypes) const
134{
135 return supportsWebVisibleMimeType(mimeType, allowedPluginTypes, webVisiblePlugins());
136}
137
138bool PluginData::supportsWebVisibleMimeType(const String& mimeType, const AllowedPluginTypes allowedPluginTypes, const Vector<PluginInfo>& plugins) const
139{
140 Vector<MimeClassInfo> mimes;
141 Vector<size_t> mimePluginIndices;
142 getMimesAndPluginIndiciesForPlugins(plugins, mimes, mimePluginIndices);
143
144 for (unsigned i = 0; i < mimes.size(); ++i) {
145 if (mimes[i].type == mimeType && (allowedPluginTypes == AllPlugins || plugins[mimePluginIndices[i]].isApplicationPlugin))
146 return true;
147 }
148 return false;
149}
150
151bool PluginData::getPluginInfoForWebVisibleMimeType(const String& mimeType, PluginInfo& pluginInfoRef) const
152{
153 Vector<MimeClassInfo> mimes;
154 Vector<size_t> mimePluginIndices;
155 const Vector<PluginInfo>& plugins = webVisiblePlugins();
156 getWebVisibleMimesAndPluginIndices(mimes, mimePluginIndices);
157
158 for (unsigned i = 0; i < mimes.size(); ++i) {
159 const MimeClassInfo& info = mimes[i];
160
161 if (info.type == mimeType) {
162 pluginInfoRef = plugins[mimePluginIndices[i]];
163 return true;
164 }
165 }
166
167 return false;
168}
169
170String PluginData::pluginFileForWebVisibleMimeType(const String& mimeType) const
171{
172 PluginInfo info;
173 if (getPluginInfoForWebVisibleMimeType(mimeType, info))
174 return info.file;
175 return String();
176}
177
178bool PluginData::supportsMimeType(const String& mimeType, const AllowedPluginTypes allowedPluginTypes) const
179{
180 Vector<MimeClassInfo> mimes;
181 Vector<size_t> mimePluginIndices;
182 const Vector<PluginInfo>& plugins = this->plugins();
183 getMimesAndPluginIndices(mimes, mimePluginIndices);
184
185 for (unsigned i = 0; i < mimes.size(); ++i) {
186 if (mimes[i].type == mimeType && (allowedPluginTypes == AllPlugins || plugins[mimePluginIndices[i]].isApplicationPlugin))
187 return true;
188 }
189 return false;
190}
191
192void PluginData::initPlugins()
193{
194 ASSERT(m_plugins.isEmpty());
195
196 m_plugins = m_page.pluginInfoProvider().pluginInfo(m_page, m_supportedPluginIdentifiers);
197}
198
199} // namespace WebCore
200