WebUserContentControllerProxy.cpp [plain text]
#include "config.h"
#include "WebUserContentControllerProxy.h"
#include "APIArray.h"
#include "APIContentWorld.h"
#include "APISerializedScriptValue.h"
#include "APIUserScript.h"
#include "APIUserStyleSheet.h"
#include "InjectUserScriptImmediately.h"
#include "NetworkContentRuleListManagerMessages.h"
#include "NetworkProcessProxy.h"
#include "WebPageCreationParameters.h"
#include "WebProcessProxy.h"
#include "WebScriptMessageHandler.h"
#include "WebUserContentControllerDataTypes.h"
#include "WebUserContentControllerMessages.h"
#include "WebUserContentControllerProxyMessages.h"
#include <WebCore/SerializedScriptValue.h>
#if ENABLE(CONTENT_EXTENSIONS)
#include "APIContentRuleList.h"
#include "WebCompiledContentRuleList.h"
#endif
namespace WebKit {
using namespace WebCore;
static HashMap<UserContentControllerIdentifier, WebUserContentControllerProxy*>& webUserContentControllerProxies()
{
static NeverDestroyed<HashMap<UserContentControllerIdentifier, WebUserContentControllerProxy*>> proxies;
return proxies;
}
WebUserContentControllerProxy* WebUserContentControllerProxy::get(UserContentControllerIdentifier identifier)
{
return webUserContentControllerProxies().get(identifier);
}
WebUserContentControllerProxy::WebUserContentControllerProxy()
: m_identifier(UserContentControllerIdentifier::generate())
, m_userScripts(API::Array::create())
, m_userStyleSheets(API::Array::create())
{
webUserContentControllerProxies().add(m_identifier, this);
}
WebUserContentControllerProxy::~WebUserContentControllerProxy()
{
for (const auto& identifier : m_associatedContentWorlds) {
auto* world = API::ContentWorld::worldForIdentifier(identifier);
RELEASE_ASSERT(world);
world->userContentControllerProxyDestroyed(*this);
}
webUserContentControllerProxies().remove(m_identifier);
for (auto& process : m_processes) {
process.removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier());
process.didDestroyWebUserContentControllerProxy(*this);
}
#if ENABLE(CONTENT_EXTENSIONS)
for (auto& process : m_networkProcesses)
process.didDestroyWebUserContentControllerProxy(*this);
#endif
}
#if ENABLE(CONTENT_EXTENSIONS)
void WebUserContentControllerProxy::addNetworkProcess(NetworkProcessProxy& proxy)
{
m_networkProcesses.add(proxy);
}
void WebUserContentControllerProxy::removeNetworkProcess(NetworkProcessProxy& proxy)
{
m_networkProcesses.remove(proxy);
}
#endif
void WebUserContentControllerProxy::addProcess(WebProcessProxy& webProcessProxy)
{
ASSERT(!m_processes.hasNullReferences());
if (m_processes.add(webProcessProxy).isNewEntry)
webProcessProxy.addMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier(), *this);
}
UserContentControllerParameters WebUserContentControllerProxy::parameters() const
{
UserContentControllerParameters parameters;
parameters.identifier = identifier();
ASSERT(parameters.userContentWorlds.isEmpty());
for (const auto& identifier : m_associatedContentWorlds) {
auto* world = API::ContentWorld::worldForIdentifier(identifier);
RELEASE_ASSERT(world);
parameters.userContentWorlds.append(world->worldData());
}
for (auto userScript : m_userScripts->elementsOfType<API::UserScript>())
parameters.userScripts.append({ userScript->identifier(), userScript->contentWorld().identifier(), userScript->userScript() });
for (auto userStyleSheet : m_userStyleSheets->elementsOfType<API::UserStyleSheet>())
parameters.userStyleSheets.append({ userStyleSheet->identifier(), userStyleSheet->contentWorld().identifier(), userStyleSheet->userStyleSheet() });
for (auto& handler : m_scriptMessageHandlers.values())
parameters.messageHandlers.append({ handler->identifier(), handler->world().identifier(), handler->name() });
#if ENABLE(CONTENT_EXTENSIONS)
parameters.contentRuleLists = contentRuleListData();
#endif
return parameters;
}
#if ENABLE(CONTENT_EXTENSIONS)
Vector<std::pair<String, WebCompiledContentRuleListData>> WebUserContentControllerProxy::contentRuleListData() const
{
Vector<std::pair<String, WebCompiledContentRuleListData>> data;
data.reserveInitialCapacity(m_contentRuleLists.size());
for (const auto& contentRuleList : m_contentRuleLists.values())
data.uncheckedAppend(std::make_pair(contentRuleList->name(), contentRuleList->compiledRuleList().data()));
return data;
}
#endif
void WebUserContentControllerProxy::removeProcess(WebProcessProxy& webProcessProxy)
{
ASSERT(m_processes.contains(webProcessProxy));
ASSERT(!m_processes.hasNullReferences());
m_processes.remove(webProcessProxy);
webProcessProxy.removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier());
}
void WebUserContentControllerProxy::addContentWorld(API::ContentWorld& world)
{
if (world.identifier() == pageContentWorldIdentifier())
return;
auto addResult = m_associatedContentWorlds.add(world.identifier());
if (!addResult.isNewEntry)
return;
world.addAssociatedUserContentControllerProxy(*this);
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::AddContentWorlds({ world.worldData() }), identifier());
}
void WebUserContentControllerProxy::contentWorldDestroyed(API::ContentWorld& world)
{
bool result = m_associatedContentWorlds.remove(world.identifier());
ASSERT_UNUSED(result, result);
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveContentWorlds({ world.identifier() }), identifier());
}
void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript, InjectUserScriptImmediately immediately)
{
Ref<API::ContentWorld> world = userScript.contentWorld();
addContentWorld(world.get());
m_userScripts->elements().append(&userScript);
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::AddUserScripts({ { userScript.identifier(), world->identifier(), userScript.userScript() } }, immediately), identifier());
}
void WebUserContentControllerProxy::removeUserScript(API::UserScript& userScript)
{
Ref<API::ContentWorld> world = userScript.contentWorld();
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveUserScript(world->identifier(), userScript.identifier()), identifier());
m_userScripts->elements().removeAll(&userScript);
}
void WebUserContentControllerProxy::removeAllUserScripts(API::ContentWorld& world)
{
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllUserScripts({ world.identifier() }), identifier());
m_userScripts->removeAllOfTypeMatching<API::UserScript>([&](const auto& userScript) {
return &userScript->contentWorld() == &world;
});
}
void WebUserContentControllerProxy::removeAllUserScripts()
{
HashCountedSet<RefPtr<API::ContentWorld>> worlds;
for (auto userScript : m_userScripts->elementsOfType<API::UserScript>())
worlds.add(const_cast<API::ContentWorld*>(&userScript->contentWorld()));
Vector<ContentWorldIdentifier> worldIdentifiers;
worldIdentifiers.reserveInitialCapacity(worlds.size());
for (const auto& worldCountPair : worlds)
worldIdentifiers.uncheckedAppend(worldCountPair.key->identifier());
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllUserScripts(worldIdentifiers), identifier());
m_userScripts->elements().clear();
}
void WebUserContentControllerProxy::addUserStyleSheet(API::UserStyleSheet& userStyleSheet)
{
Ref<API::ContentWorld> world = userStyleSheet.contentWorld();
addContentWorld(world.get());
m_userStyleSheets->elements().append(&userStyleSheet);
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::AddUserStyleSheets({ { userStyleSheet.identifier(), world->identifier(), userStyleSheet.userStyleSheet() } }), identifier());
}
void WebUserContentControllerProxy::removeUserStyleSheet(API::UserStyleSheet& userStyleSheet)
{
Ref<API::ContentWorld> world = userStyleSheet.contentWorld();
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveUserStyleSheet(world->identifier(), userStyleSheet.identifier()), identifier());
m_userStyleSheets->elements().removeAll(&userStyleSheet);
}
void WebUserContentControllerProxy::removeAllUserStyleSheets(API::ContentWorld& world)
{
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllUserStyleSheets({ world.identifier() }), identifier());
m_userStyleSheets->removeAllOfTypeMatching<API::UserStyleSheet>([&](const auto& userStyleSheet) {
return &userStyleSheet->contentWorld() == &world;
});
}
void WebUserContentControllerProxy::removeAllUserStyleSheets()
{
HashCountedSet<RefPtr<API::ContentWorld>> worlds;
for (auto userStyleSheet : m_userStyleSheets->elementsOfType<API::UserStyleSheet>())
worlds.add(const_cast<API::ContentWorld*>(&userStyleSheet->contentWorld()));
Vector<ContentWorldIdentifier> worldIdentifiers;
worldIdentifiers.reserveInitialCapacity(worlds.size());
for (const auto& worldCountPair : worlds)
worldIdentifiers.uncheckedAppend(worldCountPair.key->identifier());
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllUserStyleSheets(worldIdentifiers), identifier());
m_userStyleSheets->elements().clear();
}
bool WebUserContentControllerProxy::addUserScriptMessageHandler(WebScriptMessageHandler& handler)
{
auto& world = handler.world();
for (auto& existingHandler : m_scriptMessageHandlers.values()) {
if (existingHandler->name() == handler.name() && existingHandler->world().identifier() == world.identifier())
return false;
}
addContentWorld(world);
m_scriptMessageHandlers.add(handler.identifier(), &handler);
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::AddUserScriptMessageHandlers({ { handler.identifier(), world.identifier(), handler.name() } }), identifier());
return true;
}
void WebUserContentControllerProxy::removeUserMessageHandlerForName(const String& name, API::ContentWorld& world)
{
for (auto it = m_scriptMessageHandlers.begin(), end = m_scriptMessageHandlers.end(); it != end; ++it) {
if (it->value->name() == name && it->value->world().identifier() == world.identifier()) {
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveUserScriptMessageHandler(world.identifier(), it->value->identifier()), identifier());
m_scriptMessageHandlers.remove(it);
return;
}
}
}
void WebUserContentControllerProxy::removeAllUserMessageHandlers(API::ContentWorld& world)
{
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllUserScriptMessageHandlersForWorlds({ world.identifier() }), identifier());
unsigned numberRemoved = 0;
m_scriptMessageHandlers.removeIf([&](auto& entry) {
if (entry.value->world().identifier() == world.identifier()) {
++numberRemoved;
return true;
}
return false;
});
}
void WebUserContentControllerProxy::removeAllUserMessageHandlers()
{
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllUserScriptMessageHandlers(), identifier());
}
void WebUserContentControllerProxy::didPostMessage(WebPageProxyIdentifier pageProxyID, FrameInfoData&& frameInfoData, uint64_t messageHandlerID, const IPC::DataReference& dataReference, Messages::WebUserContentControllerProxy::DidPostMessage::AsyncReply&& reply)
{
WebPageProxy* page = WebProcessProxy::webPage(pageProxyID);
if (!page)
return;
if (!HashMap<uint64_t, RefPtr<WebScriptMessageHandler>>::isValidKey(messageHandlerID))
return;
RefPtr<WebScriptMessageHandler> handler = m_scriptMessageHandlers.get(messageHandlerID);
if (!handler)
return;
if (!handler->client().supportsAsyncReply()) {
handler->client().didPostMessage(*page, WTFMove(frameInfoData), handler->world(), WebCore::SerializedScriptValue::adopt(dataReference.vector()));
reply({ }, { });
return;
}
handler->client().didPostMessageWithAsyncReply(*page, WTFMove(frameInfoData), handler->world(), WebCore::SerializedScriptValue::adopt(dataReference.vector()), [reply = WTFMove(reply)](API::SerializedScriptValue* value, const String& errorMessage) mutable {
if (errorMessage.isNull()) {
ASSERT(value);
reply({ value->internalRepresentation().toWireBytes() }, { });
return;
}
reply({ }, errorMessage);
});
}
#if ENABLE(CONTENT_EXTENSIONS)
void WebUserContentControllerProxy::addContentRuleList(API::ContentRuleList& contentRuleList)
{
m_contentRuleLists.set(contentRuleList.name(), &contentRuleList);
auto pair = std::make_pair(contentRuleList.name(), contentRuleList.compiledRuleList().data());
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::AddContentRuleLists({ pair }), identifier());
for (auto& process : m_networkProcesses)
process.send(Messages::NetworkContentRuleListManager::AddContentRuleLists { identifier(), { pair } }, 0);
}
void WebUserContentControllerProxy::removeContentRuleList(const String& name)
{
m_contentRuleLists.remove(name);
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveContentRuleList(name), identifier());
for (auto& process : m_networkProcesses)
process.send(Messages::NetworkContentRuleListManager::RemoveContentRuleList { identifier(), name }, 0);
}
void WebUserContentControllerProxy::removeAllContentRuleLists()
{
m_contentRuleLists.clear();
for (auto& process : m_processes)
process.send(Messages::WebUserContentController::RemoveAllContentRuleLists(), identifier());
for (auto& process : m_networkProcesses)
process.send(Messages::NetworkContentRuleListManager::RemoveAllContentRuleLists { identifier() }, 0);
}
#endif
}