1/*
2 * Copyright (C) 2014 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 "WebUserContentControllerProxy.h"
28
29#include "APIArray.h"
30#include "APIUserContentWorld.h"
31#include "APIUserScript.h"
32#include "APIUserStyleSheet.h"
33#include "DataReference.h"
34#include "InjectUserScriptImmediately.h"
35#include "NetworkContentRuleListManagerMessages.h"
36#include "NetworkProcessProxy.h"
37#include "WebPageCreationParameters.h"
38#include "WebProcessProxy.h"
39#include "WebScriptMessageHandler.h"
40#include "WebUserContentControllerDataTypes.h"
41#include "WebUserContentControllerMessages.h"
42#include "WebUserContentControllerProxyMessages.h"
43#include <WebCore/SerializedScriptValue.h>
44
45#if ENABLE(CONTENT_EXTENSIONS)
46#include "APIContentRuleList.h"
47#include "WebCompiledContentRuleList.h"
48#endif
49
50namespace WebKit {
51
52static HashMap<UserContentControllerIdentifier, WebUserContentControllerProxy*>& webUserContentControllerProxies()
53{
54 static NeverDestroyed<HashMap<UserContentControllerIdentifier, WebUserContentControllerProxy*>> proxies;
55 return proxies;
56}
57
58
59WebUserContentControllerProxy* WebUserContentControllerProxy::get(UserContentControllerIdentifier identifier)
60{
61 return webUserContentControllerProxies().get(identifier);
62}
63
64WebUserContentControllerProxy::WebUserContentControllerProxy()
65 : m_identifier(UserContentControllerIdentifier::generate())
66 , m_userScripts(API::Array::create())
67 , m_userStyleSheets(API::Array::create())
68{
69 webUserContentControllerProxies().add(m_identifier, this);
70}
71
72WebUserContentControllerProxy::~WebUserContentControllerProxy()
73{
74 webUserContentControllerProxies().remove(m_identifier);
75 for (auto* process : m_processes) {
76 process->removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier().toUInt64());
77 process->didDestroyWebUserContentControllerProxy(*this);
78 }
79#if ENABLE(CONTENT_EXTENSIONS)
80 for (auto* process : m_networkProcesses)
81 process->didDestroyWebUserContentControllerProxy(*this);
82#endif
83}
84
85void WebUserContentControllerProxy::addProcess(WebProcessProxy& webProcessProxy, WebPageCreationParameters& parameters)
86{
87 if (m_processes.add(&webProcessProxy).isNewEntry)
88 webProcessProxy.addMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier().toUInt64(), *this);
89
90 ASSERT(parameters.userContentWorlds.isEmpty());
91 for (const auto& world : m_userContentWorlds)
92 parameters.userContentWorlds.append(std::make_pair(world.key->identifier(), world.key->name()));
93
94 ASSERT(parameters.userScripts.isEmpty());
95 for (auto userScript : m_userScripts->elementsOfType<API::UserScript>())
96 parameters.userScripts.append({ userScript->identifier(), userScript->userContentWorld().identifier(), userScript->userScript() });
97
98 ASSERT(parameters.userStyleSheets.isEmpty());
99 for (auto userStyleSheet : m_userStyleSheets->elementsOfType<API::UserStyleSheet>())
100 parameters.userStyleSheets.append({ userStyleSheet->identifier(), userStyleSheet->userContentWorld().identifier(), userStyleSheet->userStyleSheet() });
101
102 ASSERT(parameters.messageHandlers.isEmpty());
103 for (auto& handler : m_scriptMessageHandlers.values())
104 parameters.messageHandlers.append({ handler->identifier(), handler->userContentWorld().identifier(), handler->name() });
105
106#if ENABLE(CONTENT_EXTENSIONS)
107 ASSERT(parameters.contentRuleLists.isEmpty());
108 for (const auto& contentRuleList : m_contentRuleLists.values())
109 parameters.contentRuleLists.append(std::make_pair(contentRuleList->name(), contentRuleList->compiledRuleList().data()));
110#endif
111}
112
113void WebUserContentControllerProxy::removeProcess(WebProcessProxy& webProcessProxy)
114{
115 ASSERT(m_processes.contains(&webProcessProxy));
116
117 m_processes.remove(&webProcessProxy);
118 webProcessProxy.removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier().toUInt64());
119}
120
121void WebUserContentControllerProxy::addUserContentWorldUse(API::UserContentWorld& world)
122{
123 if (&world == &API::UserContentWorld::normalWorld())
124 return;
125
126 auto addResult = m_userContentWorlds.add(&world);
127 if (addResult.isNewEntry) {
128 for (WebProcessProxy* process : m_processes)
129 process->send(Messages::WebUserContentController::AddUserContentWorlds({ std::make_pair(world.identifier(), world.name()) }), identifier().toUInt64());
130 }
131}
132
133bool WebUserContentControllerProxy::shouldSendRemoveUserContentWorldsMessage(API::UserContentWorld& world, unsigned numberOfUsesToRemove)
134{
135 if (&world == &API::UserContentWorld::normalWorld())
136 return false;
137
138 auto it = m_userContentWorlds.find(&world);
139 for (unsigned i = 0; i < numberOfUsesToRemove; ++i) {
140 if (m_userContentWorlds.remove(it)) {
141 ASSERT(i == (numberOfUsesToRemove - 1));
142 return true;
143 }
144 }
145
146 return false;
147}
148
149void WebUserContentControllerProxy::removeUserContentWorldUses(API::UserContentWorld& world, unsigned numberOfUsesToRemove)
150{
151 if (shouldSendRemoveUserContentWorldsMessage(world, numberOfUsesToRemove)) {
152 for (WebProcessProxy* process : m_processes)
153 process->send(Messages::WebUserContentController::RemoveUserContentWorlds({ world.identifier() }), identifier().toUInt64());
154 }
155}
156
157void WebUserContentControllerProxy::removeUserContentWorldUses(HashCountedSet<RefPtr<API::UserContentWorld>>& worlds)
158{
159 Vector<uint64_t> worldsToRemove;
160 for (auto& worldUsePair : worlds) {
161 if (shouldSendRemoveUserContentWorldsMessage(*worldUsePair.key.get(), worldUsePair.value))
162 worldsToRemove.append(worldUsePair.key->identifier());
163 }
164
165 for (WebProcessProxy* process : m_processes)
166 process->send(Messages::WebUserContentController::RemoveUserContentWorlds(worldsToRemove), identifier().toUInt64());
167}
168
169void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript, InjectUserScriptImmediately immediately)
170{
171 Ref<API::UserContentWorld> world = userScript.userContentWorld();
172
173 addUserContentWorldUse(world.get());
174
175 m_userScripts->elements().append(&userScript);
176
177 for (WebProcessProxy* process : m_processes)
178 process->send(Messages::WebUserContentController::AddUserScripts({ { userScript.identifier(), world->identifier(), userScript.userScript() } }, immediately), identifier().toUInt64());
179}
180
181void WebUserContentControllerProxy::removeUserScript(API::UserScript& userScript)
182{
183 Ref<API::UserContentWorld> world = userScript.userContentWorld();
184
185 for (WebProcessProxy* process : m_processes)
186 process->send(Messages::WebUserContentController::RemoveUserScript(world->identifier(), userScript.identifier()), identifier().toUInt64());
187
188 m_userScripts->elements().removeAll(&userScript);
189
190 removeUserContentWorldUses(world.get(), 1);
191}
192
193void WebUserContentControllerProxy::removeAllUserScripts(API::UserContentWorld& world)
194{
195 for (WebProcessProxy* process : m_processes)
196 process->send(Messages::WebUserContentController::RemoveAllUserScripts({ world.identifier() }), identifier().toUInt64());
197
198 unsigned userScriptsRemoved = m_userScripts->removeAllOfTypeMatching<API::UserScript>([&](const auto& userScript) {
199 return &userScript->userContentWorld() == &world;
200 });
201
202 removeUserContentWorldUses(world, userScriptsRemoved);
203}
204
205void WebUserContentControllerProxy::removeAllUserScripts()
206{
207 HashCountedSet<RefPtr<API::UserContentWorld>> worlds;
208 for (auto userScript : m_userScripts->elementsOfType<API::UserScript>())
209 worlds.add(const_cast<API::UserContentWorld*>(&userScript->userContentWorld()));
210
211 Vector<uint64_t> worldIdentifiers;
212 worldIdentifiers.reserveInitialCapacity(worlds.size());
213 for (const auto& worldCountPair : worlds)
214 worldIdentifiers.uncheckedAppend(worldCountPair.key->identifier());
215
216 for (WebProcessProxy* process : m_processes)
217 process->send(Messages::WebUserContentController::RemoveAllUserScripts(worldIdentifiers), identifier().toUInt64());
218
219 m_userScripts->elements().clear();
220
221 removeUserContentWorldUses(worlds);
222}
223
224void WebUserContentControllerProxy::addUserStyleSheet(API::UserStyleSheet& userStyleSheet)
225{
226 Ref<API::UserContentWorld> world = userStyleSheet.userContentWorld();
227
228 addUserContentWorldUse(world.get());
229
230 m_userStyleSheets->elements().append(&userStyleSheet);
231
232 for (WebProcessProxy* process : m_processes)
233 process->send(Messages::WebUserContentController::AddUserStyleSheets({ { userStyleSheet.identifier(), world->identifier(), userStyleSheet.userStyleSheet() } }), identifier().toUInt64());
234}
235
236void WebUserContentControllerProxy::removeUserStyleSheet(API::UserStyleSheet& userStyleSheet)
237{
238 Ref<API::UserContentWorld> world = userStyleSheet.userContentWorld();
239
240 for (WebProcessProxy* process : m_processes)
241 process->send(Messages::WebUserContentController::RemoveUserStyleSheet(world->identifier(), userStyleSheet.identifier()), identifier().toUInt64());
242
243 m_userStyleSheets->elements().removeAll(&userStyleSheet);
244
245 removeUserContentWorldUses(world.get(), 1);
246}
247
248void WebUserContentControllerProxy::removeAllUserStyleSheets(API::UserContentWorld& world)
249{
250 for (WebProcessProxy* process : m_processes)
251 process->send(Messages::WebUserContentController::RemoveAllUserStyleSheets({ world.identifier() }), identifier().toUInt64());
252
253 unsigned userStyleSheetsRemoved = m_userStyleSheets->removeAllOfTypeMatching<API::UserStyleSheet>([&](const auto& userStyleSheet) {
254 return &userStyleSheet->userContentWorld() == &world;
255 });
256
257 removeUserContentWorldUses(world, userStyleSheetsRemoved);
258}
259
260void WebUserContentControllerProxy::removeAllUserStyleSheets()
261{
262 HashCountedSet<RefPtr<API::UserContentWorld>> worlds;
263 for (auto userStyleSheet : m_userStyleSheets->elementsOfType<API::UserStyleSheet>())
264 worlds.add(const_cast<API::UserContentWorld*>(&userStyleSheet->userContentWorld()));
265
266 Vector<uint64_t> worldIdentifiers;
267 worldIdentifiers.reserveInitialCapacity(worlds.size());
268 for (const auto& worldCountPair : worlds)
269 worldIdentifiers.uncheckedAppend(worldCountPair.key->identifier());
270
271 for (WebProcessProxy* process : m_processes)
272 process->send(Messages::WebUserContentController::RemoveAllUserStyleSheets(worldIdentifiers), identifier().toUInt64());
273
274 m_userStyleSheets->elements().clear();
275
276 removeUserContentWorldUses(worlds);
277}
278
279bool WebUserContentControllerProxy::addUserScriptMessageHandler(WebScriptMessageHandler& handler)
280{
281 Ref<API::UserContentWorld> world = handler.userContentWorld();
282
283 for (auto& existingHandler : m_scriptMessageHandlers.values()) {
284 if (existingHandler->name() == handler.name() && &existingHandler->userContentWorld() == world.ptr())
285 return false;
286 }
287
288 addUserContentWorldUse(world.get());
289
290 m_scriptMessageHandlers.add(handler.identifier(), &handler);
291
292 for (WebProcessProxy* process : m_processes)
293 process->send(Messages::WebUserContentController::AddUserScriptMessageHandlers({ { handler.identifier(), world->identifier(), handler.name() } }), identifier().toUInt64());
294
295 return true;
296}
297
298void WebUserContentControllerProxy::removeUserMessageHandlerForName(const String& name, API::UserContentWorld& world)
299{
300 for (auto it = m_scriptMessageHandlers.begin(), end = m_scriptMessageHandlers.end(); it != end; ++it) {
301 if (it->value->name() == name && &it->value->userContentWorld() == &world) {
302 for (WebProcessProxy* process : m_processes)
303 process->send(Messages::WebUserContentController::RemoveUserScriptMessageHandler(world.identifier(), it->value->identifier()), identifier().toUInt64());
304
305 m_scriptMessageHandlers.remove(it);
306
307 removeUserContentWorldUses(world, 1);
308 return;
309 }
310 }
311}
312
313void WebUserContentControllerProxy::removeAllUserMessageHandlers(API::UserContentWorld& world)
314{
315 for (WebProcessProxy* process : m_processes)
316 process->send(Messages::WebUserContentController::RemoveAllUserScriptMessageHandlers({ world.identifier() }), identifier().toUInt64());
317
318 unsigned numberRemoved = 0;
319 m_scriptMessageHandlers.removeIf([&](auto& entry) {
320 if (&entry.value->userContentWorld() == &world) {
321 ++numberRemoved;
322 return true;
323 }
324 return false;
325 });
326
327 removeUserContentWorldUses(world, numberRemoved);
328}
329
330void WebUserContentControllerProxy::didPostMessage(IPC::Connection& connection, uint64_t pageID, const FrameInfoData& frameInfoData, uint64_t messageHandlerID, const IPC::DataReference& dataReference)
331{
332 WebPageProxy* page = WebProcessProxy::webPage(pageID);
333 if (!page)
334 return;
335
336 if (!HashMap<uint64_t, RefPtr<WebScriptMessageHandler>>::isValidKey(messageHandlerID))
337 return;
338
339 RefPtr<WebScriptMessageHandler> handler = m_scriptMessageHandlers.get(messageHandlerID);
340 if (!handler)
341 return;
342
343 handler->client().didPostMessage(*page, frameInfoData, WebCore::SerializedScriptValue::adopt(dataReference.vector()));
344}
345
346#if ENABLE(CONTENT_EXTENSIONS)
347void WebUserContentControllerProxy::addContentRuleList(API::ContentRuleList& contentRuleList)
348{
349 m_contentRuleLists.set(contentRuleList.name(), &contentRuleList);
350
351 auto pair = std::make_pair(contentRuleList.name(), contentRuleList.compiledRuleList().data());
352
353 for (auto* process : m_processes)
354 process->send(Messages::WebUserContentController::AddContentRuleLists({ pair }), identifier().toUInt64());
355
356 for (auto* process : m_networkProcesses)
357 process->send(Messages::NetworkContentRuleListManager::AddContentRuleLists { identifier(), { pair } }, 0);
358}
359
360void WebUserContentControllerProxy::removeContentRuleList(const String& name)
361{
362 m_contentRuleLists.remove(name);
363
364 for (auto* process : m_processes)
365 process->send(Messages::WebUserContentController::RemoveContentRuleList(name), identifier().toUInt64());
366
367 for (auto* process : m_networkProcesses)
368 process->send(Messages::NetworkContentRuleListManager::RemoveContentRuleList { identifier(), name }, 0);
369}
370
371void WebUserContentControllerProxy::removeAllContentRuleLists()
372{
373 m_contentRuleLists.clear();
374
375 for (auto* process : m_processes)
376 process->send(Messages::WebUserContentController::RemoveAllContentRuleLists(), identifier().toUInt64());
377
378 for (auto* process : m_networkProcesses)
379 process->send(Messages::NetworkContentRuleListManager::RemoveAllContentRuleLists { identifier() }, 0);
380}
381#endif
382
383} // namespace WebKit
384