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