ladybird/Services/WebWorker/ConnectionFromClient.cpp
Aliaksandr Kalenik 1b5bdb2b41 LibWeb+LibWebView+WebWorker: Initialize transport peer pid on Windows
WebWorker control connections can transfer handles from the browser
process to the worker process, including RequestServer and ImageDecoder
transport handles sent during worker startup. On Windows, serializing
those attachments needs the destination process id so DuplicateHandle
and WSADuplicateSocketW can target the peer process. WebWorker was
excluded from the generic helper-process InitTransport handshake,
leaving the transport without a peer pid before any attachment-bearing
message was sent.

Add InitTransport to the WebWorker server endpoint, implement the
server-side peer pid exchange, expose the message type through
WebWorkerClient, and let the shared helper launcher perform the
handshake for workers as it does for other Windows IPC clients.
2026-06-18 04:06:30 +02:00

136 lines
4.5 KiB
C++

/*
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/Process.h>
#include <LibCore/System.h>
#include <LibWeb/HTML/BroadcastChannel.h>
#include <LibWeb/HTML/WorkerAgentParent.h>
#include <WebWorker/ConnectionFromClient.h>
#include <WebWorker/PageHost.h>
#include <WebWorker/WorkerHost.h>
namespace WebWorker {
Messages::WebWorkerServer::InitTransportResponse ConnectionFromClient::init_transport([[maybe_unused]] int peer_pid)
{
#ifdef AK_OS_WINDOWS
m_transport->set_peer_pid(peer_pid);
return Core::System::getpid();
#endif
VERIFY_NOT_REACHED();
}
void ConnectionFromClient::connect_to_request_server(IPC::TransportHandle handle)
{
if (on_request_server_connection)
on_request_server_connection(handle);
}
void ConnectionFromClient::connect_to_image_decoder(IPC::TransportHandle handle)
{
if (on_image_decoder_connection)
on_image_decoder_connection(handle);
}
void ConnectionFromClient::close_worker()
{
async_did_close_worker();
// FIXME: Invoke a worker shutdown operation that implements the spec
m_worker_host = nullptr;
die();
}
void ConnectionFromClient::die()
{
// FIXME: When handling multiple workers in the same process,
// this logic needs to be smarter (only when all workers are dead, etc).
Core::Process::terminate_immediately(0);
}
void ConnectionFromClient::request_file(Web::FileRequest request)
{
auto request_id = ++last_id;
auto path = request.path();
m_requested_files.set(request_id, move(request));
async_did_request_file(path, request_id);
}
ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<IPC::Transport> transport)
: IPC::ConnectionFromClient<WebWorkerClientEndpoint, WebWorkerServerEndpoint>(*this, move(transport), 1)
, m_page_host(PageHost::create(Web::Bindings::main_thread_vm(), *this))
{
}
ConnectionFromClient::~ConnectionFromClient() = default;
Web::Page& ConnectionFromClient::page()
{
return m_page_host->page();
}
Web::Page const& ConnectionFromClient::page() const
{
return m_page_host->page();
}
void ConnectionFromClient::start_worker(URL::URL url, Web::Bindings::WorkerType type, Web::Bindings::RequestCredentials credentials, String name, Web::HTML::TransferDataEncoder implicit_port, Web::HTML::SerializedEnvironmentSettingsObject outside_settings, Web::Bindings::AgentType agent_type)
{
m_worker_host = make_ref_counted<WorkerHost>(move(url), type, move(name));
bool const is_shared = agent_type == Web::Bindings::AgentType::SharedWorker;
VERIFY(is_shared || agent_type == Web::Bindings::AgentType::DedicatedWorker);
// FIXME: Add an assertion that the agent_type passed here is the same that was passed at process creation to initialize_main_thread_vm()
m_worker_host->run(page(), move(implicit_port), outside_settings, credentials, is_shared);
}
void ConnectionFromClient::connect_shared_worker(Web::HTML::TransferDataEncoder message_port, Web::HTML::SerializedEnvironmentSettingsObject outside_settings)
{
if (!m_worker_host)
return;
m_worker_host->connect_shared_worker(move(message_port), move(outside_settings));
}
void ConnectionFromClient::handle_file_return(i32 error, Optional<IPC::File> file, i32 request_id)
{
auto file_request = m_requested_files.take(request_id);
VERIFY(file_request.has_value());
VERIFY(file_request.value().on_file_request_finish);
file_request.value().on_file_request_finish(error != 0 ? Error::from_errno(error) : ErrorOr<i32> { file->take_fd() });
}
void ConnectionFromClient::did_worker_agent_finish_loading_script(Web::HTML::WorkerAgentOwnerToken owner_token)
{
Web::HTML::WorkerAgentParent::did_finish_loading_worker_script(owner_token);
}
void ConnectionFromClient::did_worker_agent_fail_loading_script(Web::HTML::WorkerAgentOwnerToken owner_token)
{
Web::HTML::WorkerAgentParent::did_fail_loading_worker_script(owner_token);
}
void ConnectionFromClient::did_worker_agent_report_exception(Web::HTML::WorkerAgentOwnerToken owner_token, String message, String filename, u32 lineno, u32 colno)
{
Web::HTML::WorkerAgentParent::did_report_worker_exception(owner_token, move(message), move(filename), lineno, colno);
}
void ConnectionFromClient::did_worker_agent_close(Web::HTML::WorkerAgentOwnerToken owner_token)
{
Web::HTML::WorkerAgentParent::did_close_worker(owner_token);
}
void ConnectionFromClient::broadcast_channel_message(Web::HTML::BroadcastChannelMessage message)
{
Web::HTML::BroadcastChannel::deliver_message_locally(message);
}
}