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