mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-08 05:27:14 +09:00

When we build internal pages (e.g. about:settings), there is currently quite a lot of boilerplate needed to communicate between the browser and the page. This includes creating IDL for the page and the IPC for every message sent between the processes. These internal pages are also special in that they have privileged access to and control over the browser process. The framework introduced here serves to ease the setup of new internal pages and to reduce the access that WebContent processes have to the browser process. WebUI pages can send requests to the browser process via a `ladybird.sendMessage` API. Responses from the browser are passed through a WebUIMessage event. So, for example, an internal page may: ladybird.sendMessage("getDataFor", { id: 123 }); document.addEventListener("WebUIMessage", event => { if (event.name === "gotData") { console.assert(event.data.id === 123); } }); To handle these messages, we set up a new IPC connection between the browser and WebContent processes. This connection is torn down when the user navigates away from the internal page.
75 lines
1.8 KiB
C++
75 lines
1.8 KiB
C++
/*
|
|
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibCore/Socket.h>
|
|
#include <LibCore/System.h>
|
|
#include <LibWebView/WebContentClient.h>
|
|
#include <LibWebView/WebUI.h>
|
|
|
|
namespace WebView {
|
|
|
|
template<typename WebUIType>
|
|
static ErrorOr<NonnullRefPtr<WebUIType>> create_web_ui(WebContentClient& client, String host)
|
|
{
|
|
Array<int, 2> socket_fds { 0, 0 };
|
|
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds.data()));
|
|
|
|
auto client_socket = Core::LocalSocket::adopt_fd(socket_fds[0]);
|
|
if (client_socket.is_error()) {
|
|
close(socket_fds[0]);
|
|
close(socket_fds[1]);
|
|
|
|
return client_socket.release_error();
|
|
}
|
|
|
|
auto web_ui = WebUIType::create(client, IPC::Transport { client_socket.release_value() }, move(host));
|
|
client.async_connect_to_web_ui(0, IPC::File::adopt_fd(socket_fds[1]));
|
|
|
|
return web_ui;
|
|
}
|
|
|
|
ErrorOr<RefPtr<WebUI>> WebUI::create(WebContentClient&, String)
|
|
{
|
|
RefPtr<WebUI> web_ui;
|
|
|
|
if (web_ui)
|
|
web_ui->register_interfaces();
|
|
|
|
return web_ui;
|
|
}
|
|
|
|
WebUI::WebUI(WebContentClient& client, IPC::Transport transport, String host)
|
|
: IPC::ConnectionToServer<WebUIClientEndpoint, WebUIServerEndpoint>(*this, move(transport))
|
|
, m_client(client)
|
|
, m_host(move(host))
|
|
{
|
|
}
|
|
|
|
WebUI::~WebUI() = default;
|
|
|
|
void WebUI::die()
|
|
{
|
|
m_client.web_ui_disconnected({});
|
|
}
|
|
|
|
void WebUI::register_interface(StringView name, Interface interface)
|
|
{
|
|
auto result = m_interfaces.set(name, move(interface));
|
|
VERIFY(result == HashSetResult::InsertedNewEntry);
|
|
}
|
|
|
|
void WebUI::received_message(String name, JsonValue data)
|
|
{
|
|
auto interface = m_interfaces.get(name);
|
|
if (!interface.has_value()) {
|
|
warnln("Received message from WebUI for unrecognized interface: {}", name);
|
|
return;
|
|
}
|
|
|
|
interface.value()(move(data));
|
|
}
|
|
|
|
}
|