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