[GTK] Epiphany searching for plugins even if plugins are disabled
[WebKit-https.git] / Source / WebKit / WebProcess / Plugins / WebPluginInfoProvider.cpp
1 /*
2  * Copyright (C) 2016 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 "WebPluginInfoProvider.h"
28
29 #include "HangDetectionDisabler.h"
30 #include "WebCoreArgumentCoders.h"
31 #include "WebProcess.h"
32 #include "WebProcessProxyMessages.h"
33 #include <WebCore/Document.h>
34 #include <WebCore/DocumentLoader.h>
35 #include <WebCore/Frame.h>
36 #include <WebCore/FrameLoader.h>
37 #include <WebCore/Page.h>
38 #include <WebCore/SchemeRegistry.h>
39 #include <WebCore/Settings.h>
40 #include <WebCore/SubframeLoader.h>
41 #include <wtf/text/StringHash.h>
42
43 #if PLATFORM(MAC)
44 #include <WebCore/StringUtilities.h>
45 #endif
46
47 namespace WebKit {
48 using namespace WebCore;
49
50 WebPluginInfoProvider& WebPluginInfoProvider::singleton()
51 {
52     static WebPluginInfoProvider& pluginInfoProvider = adoptRef(*new WebPluginInfoProvider).leakRef();
53
54     return pluginInfoProvider;
55 }
56
57 WebPluginInfoProvider::WebPluginInfoProvider()
58 {
59 }
60
61 WebPluginInfoProvider::~WebPluginInfoProvider()
62 {
63 }
64
65 #if PLATFORM(MAC)
66 void WebPluginInfoProvider::setPluginLoadClientPolicy(WebCore::PluginLoadClientPolicy clientPolicy, const String& host, const String& bundleIdentifier, const String& versionString)
67 {
68     String hostToSet = host.isNull() || !host.length() ? "*" : host;
69     String bundleIdentifierToSet = bundleIdentifier.isNull() || !bundleIdentifier.length() ? "*" : bundleIdentifier;
70     String versionStringToSet = versionString.isNull() || !versionString.length() ? "*" : versionString;
71
72     PluginPolicyMapsByIdentifier policiesByIdentifier;
73     if (m_hostsToPluginIdentifierData.contains(hostToSet))
74         policiesByIdentifier = m_hostsToPluginIdentifierData.get(hostToSet);
75
76     PluginLoadClientPoliciesByBundleVersion versionsToPolicies;
77     if (policiesByIdentifier.contains(bundleIdentifierToSet))
78         versionsToPolicies = policiesByIdentifier.get(bundleIdentifierToSet);
79
80     versionsToPolicies.set(versionStringToSet, clientPolicy);
81     policiesByIdentifier.set(bundleIdentifierToSet, versionsToPolicies);
82     m_hostsToPluginIdentifierData.set(hostToSet, policiesByIdentifier);
83
84     clearPagesPluginData();
85 }
86
87 void WebPluginInfoProvider::clearPluginClientPolicies()
88 {
89     m_hostsToPluginIdentifierData.clear();
90     clearPagesPluginData();
91 }
92 #endif
93
94 void WebPluginInfoProvider::refreshPlugins()
95 {
96 #if ENABLE(NETSCAPE_PLUGIN_API)
97     m_cachedPlugins.clear();
98     m_pluginCacheIsPopulated = false;
99     m_shouldRefreshPlugins = true;
100 #endif
101 }
102
103 Vector<PluginInfo> WebPluginInfoProvider::pluginInfo(Page& page, Optional<Vector<SupportedPluginIdentifier>>& supportedPluginIdentifiers)
104 {
105 #if ENABLE(NETSCAPE_PLUGIN_API)
106     populatePluginCache(page);
107
108     if (m_cachedSupportedPluginIdentifiers)
109         supportedPluginIdentifiers = *m_cachedSupportedPluginIdentifiers;
110
111     return page.mainFrame().loader().subframeLoader().allowPlugins() ? m_cachedPlugins : m_cachedApplicationPlugins;
112 #else
113     UNUSED_PARAM(page);
114     UNUSED_PARAM(supportedPluginIdentifiers);
115     return { };
116 #endif // ENABLE(NETSCAPE_PLUGIN_API)
117 }
118
119 Vector<WebCore::PluginInfo> WebPluginInfoProvider::webVisiblePluginInfo(Page& page, const URL& url)
120 {
121     Optional<Vector<WebCore::SupportedPluginIdentifier>> supportedPluginIdentifiers;
122     auto plugins = pluginInfo(page, supportedPluginIdentifiers);
123
124     plugins.removeAllMatching([&] (auto& plugin) {
125         return supportedPluginIdentifiers && !isSupportedPlugin(*supportedPluginIdentifiers, url, plugin.bundleIdentifier);
126     });
127
128 #if PLATFORM(MAC)
129     if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol().toString()))
130         return plugins;
131
132     for (int32_t i = plugins.size() - 1; i >= 0; --i) {
133         auto& info = plugins.at(i);
134
135         // Allow built-in plugins. Also tentatively allow plugins that the client might later selectively permit.
136         if (info.isApplicationPlugin || info.clientLoadPolicy == WebCore::PluginLoadClientPolicyAsk)
137             continue;
138
139         if (info.clientLoadPolicy == WebCore::PluginLoadClientPolicyBlock)
140             plugins.remove(i);
141     }
142 #endif
143     return plugins;
144 }
145
146 #if ENABLE(NETSCAPE_PLUGIN_API)
147 void WebPluginInfoProvider::populatePluginCache(const WebCore::Page& page)
148 {
149     if (!m_pluginCacheIsPopulated) {
150         if (page.settings().arePluginsEnabled()) {
151             HangDetectionDisabler hangDetectionDisabler;
152             if (!WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetPlugins(m_shouldRefreshPlugins),
153                 Messages::WebProcessProxy::GetPlugins::Reply(m_cachedPlugins, m_cachedApplicationPlugins, m_cachedSupportedPluginIdentifiers), 0))
154                 return;
155         }
156
157         m_shouldRefreshPlugins = false;
158         m_pluginCacheIsPopulated = true;
159     }
160
161 #if PLATFORM(MAC)
162     String pageHost = page.mainFrame().loader().documentLoader()->responseURL().host().toString();
163     if (pageHost.isNull())
164         return;
165     for (auto& info : m_cachedPlugins) {
166         if (auto clientPolicy = pluginLoadClientPolicyForHost(pageHost, info))
167             info.clientLoadPolicy = *clientPolicy;
168     }
169 #else
170     UNUSED_PARAM(page);
171 #endif // not PLATFORM(MAC)
172 }
173 #endif
174
175 #if PLATFORM(MAC)
176 Optional<WebCore::PluginLoadClientPolicy> WebPluginInfoProvider::pluginLoadClientPolicyForHost(const String& host, const WebCore::PluginInfo& info) const
177 {
178     String hostToLookUp = host;
179     String identifier = info.bundleIdentifier;
180
181     auto policiesByIdentifierIterator = m_hostsToPluginIdentifierData.find(hostToLookUp);
182
183     if (!identifier.isNull() && policiesByIdentifierIterator == m_hostsToPluginIdentifierData.end()) {
184         if (!replaceHostWithMatchedWildcardHost(hostToLookUp, identifier))
185             hostToLookUp = "*";
186         policiesByIdentifierIterator = m_hostsToPluginIdentifierData.find(hostToLookUp);
187         if (hostToLookUp != "*" && policiesByIdentifierIterator == m_hostsToPluginIdentifierData.end()) {
188             hostToLookUp = "*";
189             policiesByIdentifierIterator = m_hostsToPluginIdentifierData.find(hostToLookUp);
190         }
191     }
192     if (policiesByIdentifierIterator == m_hostsToPluginIdentifierData.end())
193         return WTF::nullopt;
194
195     auto& policiesByIdentifier = policiesByIdentifierIterator->value;
196
197     if (!identifier)
198         identifier = "*";
199
200     auto identifierPolicyIterator = policiesByIdentifier.find(identifier);
201     if (identifier != "*" && identifierPolicyIterator == policiesByIdentifier.end()) {
202         identifier = "*";
203         identifierPolicyIterator = policiesByIdentifier.find(identifier);
204     }
205
206     if (identifierPolicyIterator == policiesByIdentifier.end())
207         return WTF::nullopt;
208
209     auto& versionsToPolicies = identifierPolicyIterator->value;
210
211     String version = info.versionString;
212     if (!version)
213         version = "*";
214     auto policyIterator = versionsToPolicies.find(version);
215     if (version != "*" && policyIterator == versionsToPolicies.end()) {
216         version = "*";
217         policyIterator = versionsToPolicies.find(version);
218     }
219
220     if (policyIterator == versionsToPolicies.end())
221         return WTF::nullopt;
222
223     return policyIterator->value;
224 }
225
226 String WebPluginInfoProvider::longestMatchedWildcardHostForHost(const String& host) const
227 {
228     String longestMatchedHost;
229
230     for (auto& key : m_hostsToPluginIdentifierData.keys()) {
231         if (key.contains('*') && key != "*" && stringMatchesWildcardString(host, key)) {
232             if (key.length() > longestMatchedHost.length())
233                 longestMatchedHost = key;
234             else if (key.length() == longestMatchedHost.length() && codePointCompareLessThan(key, longestMatchedHost))
235                 longestMatchedHost = key;
236         }
237     }
238
239     return longestMatchedHost;
240 }
241
242 bool WebPluginInfoProvider::replaceHostWithMatchedWildcardHost(String& host, const String& identifier) const
243 {
244     String matchedWildcardHost = longestMatchedWildcardHostForHost(host);
245
246     if (matchedWildcardHost.isNull())
247         return false;
248
249     auto plugInIdentifierData = m_hostsToPluginIdentifierData.find(matchedWildcardHost);
250     if (plugInIdentifierData == m_hostsToPluginIdentifierData.end() || !plugInIdentifierData->value.contains(identifier))
251         return false;
252
253     host = matchedWildcardHost;
254     return true;
255 }
256 #endif
257
258 }