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