mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
Everywhere: Remove dynamic Mach bootstrap registration on macOS
Registering multiple Mach port names with the bootstrap server at runtime is not how macOS expects it to be used — the bootstrap server is meant for static services, and the only reason we used it originally was so child processes could reach back to the UI process. Remove bootstrap_transport_over_socket(), which had both sides register dynamic names with the bootstrap server and exchange them over a socket. Instead, WebDriver and BrowserProcess connections now go through MachPortServer instances directly. When a non-child process contacts a MachPortServer, the server creates a port pair on demand (detected via sysctl ppid check) and returns the local half immediately. This keeps bootstrap server usage limited to the one original case: child processes looking up their parent's MachPortServer. WebDriver Session now runs its own MachPortServer per session. --webdriver-content-path becomes --webdriver-mach-server-name on macOS. Spare WebContent launches are skipped when a WebDriver session is active to avoid bootstrap races.
This commit is contained in:
committed by
Alexander Kalenik
parent
4ea4d63008
commit
c6d740ea41
Notes:
github-actions[bot]
2026-03-23 17:52:42 +00:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/c6d740ea41b Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8514 Reviewed-by: https://github.com/ADKaster
@@ -122,11 +122,11 @@ void ConnectionFromClient::set_window_handle(u64 page_id, String handle)
|
||||
page->page().top_level_traversable()->set_window_handle(move(handle));
|
||||
}
|
||||
|
||||
void ConnectionFromClient::connect_to_webdriver(u64 page_id, ByteString webdriver_ipc_path)
|
||||
void ConnectionFromClient::connect_to_webdriver(u64 page_id, ByteString webdriver_endpoint)
|
||||
{
|
||||
if (auto page = this->page(page_id); page.has_value()) {
|
||||
// FIXME: Propagate this error back to the browser.
|
||||
if (auto result = page->connect_to_webdriver(webdriver_ipc_path); result.is_error())
|
||||
if (auto result = page->connect_to_webdriver(webdriver_endpoint); result.is_error())
|
||||
dbgln("Unable to connect to the WebDriver process: {}", result.error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
virtual void close_server() override;
|
||||
virtual Messages::WebContentServer::GetWindowHandleResponse get_window_handle(u64 page_id) override;
|
||||
virtual void set_window_handle(u64 page_id, String handle) override;
|
||||
virtual void connect_to_webdriver(u64 page_id, ByteString webdriver_ipc_path) override;
|
||||
virtual void connect_to_webdriver(u64 page_id, ByteString webdriver_endpoint) override;
|
||||
virtual void connect_to_web_ui(u64 page_id, IPC::TransportHandle handle) override;
|
||||
virtual void connect_to_request_server(IPC::TransportHandle handle) override;
|
||||
virtual void connect_to_image_decoder(IPC::TransportHandle handle) override;
|
||||
|
||||
@@ -790,10 +790,10 @@ void PageClient::page_did_take_screenshot(Gfx::ShareableBitmap const& screenshot
|
||||
client().async_did_take_screenshot(m_id, screenshot);
|
||||
}
|
||||
|
||||
ErrorOr<void> PageClient::connect_to_webdriver(ByteString const& webdriver_ipc_path)
|
||||
ErrorOr<void> PageClient::connect_to_webdriver(ByteString const& webdriver_endpoint)
|
||||
{
|
||||
VERIFY(!m_webdriver);
|
||||
m_webdriver = TRY(WebDriverConnection::connect(*this, webdriver_ipc_path));
|
||||
m_webdriver = TRY(WebDriverConnection::connect(*this, webdriver_endpoint));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
virtual Web::Page& page() override { return *m_page; }
|
||||
virtual Web::Page const& page() const override { return *m_page; }
|
||||
|
||||
ErrorOr<void> connect_to_webdriver(ByteString const& webdriver_ipc_path);
|
||||
ErrorOr<void> connect_to_webdriver(ByteString const& webdriver_endpoint);
|
||||
ErrorOr<void> connect_to_web_ui(IPC::TransportHandle);
|
||||
|
||||
virtual Queue<Web::QueuedInputEvent>& input_event_queue() override;
|
||||
|
||||
@@ -28,7 +28,7 @@ endpoint WebContentServer
|
||||
get_window_handle(u64 page_id) => (String handle)
|
||||
set_window_handle(u64 page_id, String handle) =|
|
||||
|
||||
connect_to_webdriver(u64 page_id, ByteString webdriver_ipc_path) =|
|
||||
connect_to_webdriver(u64 page_id, ByteString webdriver_endpoint) =|
|
||||
connect_to_web_ui(u64 page_id, IPC::TransportHandle handle) =|
|
||||
connect_to_request_server(IPC::TransportHandle handle) =|
|
||||
connect_to_image_decoder(IPC::TransportHandle handle) =|
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
#include <AK/Time.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#if !defined(AK_OS_MACOS)
|
||||
# include <LibCore/Socket.h>
|
||||
#else
|
||||
# include <LibIPC/TransportBootstrapMach.h>
|
||||
#endif
|
||||
#include <LibHTTP/Cookie/Cookie.h>
|
||||
#include <LibHTTP/Cookie/ParsedCookie.h>
|
||||
#include <LibIPC/Transport.h>
|
||||
@@ -194,16 +198,24 @@ static bool fire_an_event(FlyString const& name, Optional<Web::DOM::Element&> ta
|
||||
return target->dispatch_event(event);
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(Web::PageClient& page_client, ByteString const& webdriver_ipc_path)
|
||||
ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(Web::PageClient& page_client, ByteString const& webdriver_endpoint)
|
||||
{
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Trying to connect to {}", webdriver_ipc_path);
|
||||
auto socket = TRY(Core::LocalSocket::connect(webdriver_ipc_path));
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Trying to connect to {}", webdriver_endpoint);
|
||||
#if defined(AK_OS_MACOS)
|
||||
auto transport_ports = TRY(IPC::bootstrap_transport_from_mach_server(webdriver_endpoint));
|
||||
#else
|
||||
auto socket = TRY(Core::LocalSocket::connect(webdriver_endpoint));
|
||||
#endif
|
||||
|
||||
// Allow pop-ups, or otherwise /window/new won't be able to open a new tab.
|
||||
page_client.page().set_should_block_pop_ups(false);
|
||||
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Connected to WebDriver");
|
||||
#if defined(AK_OS_MACOS)
|
||||
auto transport = make<IPC::Transport>(move(transport_ports.receive_right), move(transport_ports.send_right));
|
||||
#else
|
||||
auto transport = TRY(IPC::Transport::from_socket(move(socket)));
|
||||
#endif
|
||||
auto connection = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(move(transport), page_client)));
|
||||
connection->async_did_set_window_handle(page_client.page().top_level_traversable()->window_handle());
|
||||
return connection;
|
||||
|
||||
@@ -34,7 +34,7 @@ class WebDriverConnection final
|
||||
C_OBJECT_ABSTRACT(WebDriverConnection)
|
||||
|
||||
public:
|
||||
static ErrorOr<NonnullRefPtr<WebDriverConnection>> connect(Web::PageClient& page_client, ByteString const& webdriver_ipc_path);
|
||||
static ErrorOr<NonnullRefPtr<WebDriverConnection>> connect(Web::PageClient& page_client, ByteString const& webdriver_endpoint);
|
||||
virtual ~WebDriverConnection() = default;
|
||||
|
||||
void visit_edges(JS::Cell::Visitor&);
|
||||
|
||||
@@ -10,9 +10,14 @@
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <LibCore/LocalServer.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#include <LibCore/StandardPaths.h>
|
||||
#if !defined(AK_OS_MACOS)
|
||||
# include <LibCore/LocalServer.h>
|
||||
# include <LibCore/Socket.h>
|
||||
# include <LibCore/StandardPaths.h>
|
||||
#else
|
||||
# include <LibIPC/TransportBootstrapMach.h>
|
||||
# include <LibWebView/Utilities.h>
|
||||
#endif
|
||||
#include <LibCore/System.h>
|
||||
#include <LibIPC/Transport.h>
|
||||
#include <LibWeb/Crypto/Crypto.h>
|
||||
@@ -123,6 +128,7 @@ Session::Session(NonnullRefPtr<Client> client, JsonObject const& capabilities, S
|
||||
, m_options(capabilities)
|
||||
, m_session_id(move(session_id))
|
||||
, m_session_flags(flags)
|
||||
, m_event_loop(Core::EventLoop::current_weak())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -192,15 +198,67 @@ void Session::close()
|
||||
if (m_browser_process.has_value())
|
||||
MUST(Core::System::kill(m_browser_process->pid(), SIGTERM));
|
||||
|
||||
if (m_web_content_socket_path.has_value()) {
|
||||
MUST(Core::System::unlink(*m_web_content_socket_path));
|
||||
m_web_content_socket_path = {};
|
||||
}
|
||||
#if defined(AK_OS_MACOS)
|
||||
m_web_content_mach_port_server = nullptr;
|
||||
#else
|
||||
if (!m_web_content_endpoint.is_empty())
|
||||
MUST(Core::System::unlink(m_web_content_endpoint));
|
||||
#endif
|
||||
m_web_content_endpoint = {};
|
||||
|
||||
// 5. If an error has occurred in any of the steps above, return the error, otherwise return success with data null.
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<ServerPromise> promise)
|
||||
ErrorOr<void> Session::accept_web_content_transport(NonnullOwnPtr<IPC::Transport> transport, NonnullRefPtr<ServerPromise> promise)
|
||||
{
|
||||
auto web_content_connection = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebContentConnection(move(transport))));
|
||||
dbgln("WebDriver is connected to WebContent");
|
||||
|
||||
auto connection_id = m_next_pending_connection_id++;
|
||||
// Publish the connection before the initial did_set_window_handle message can race in.
|
||||
m_pending_connections.set(connection_id, web_content_connection);
|
||||
|
||||
web_content_connection->on_close = [this, promise, connection_id]() {
|
||||
if (m_pending_connections.remove(connection_id)) {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Pending connection {} closed before sending its handle", connection_id);
|
||||
promise->reject(Error::from_string_literal("Window was closed before sending its handle"));
|
||||
}
|
||||
};
|
||||
|
||||
web_content_connection->on_did_set_window_handle = [this, promise, connection_id](String window_handle) {
|
||||
auto maybe_pending_connection = m_pending_connections.take(connection_id);
|
||||
if (!maybe_pending_connection.has_value())
|
||||
return;
|
||||
|
||||
auto pending_connection = maybe_pending_connection.value();
|
||||
pending_connection->on_did_set_window_handle = nullptr;
|
||||
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} registered with WebDriver.", window_handle);
|
||||
|
||||
pending_connection->on_close = [this, window_handle]() {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} was closed remotely.", window_handle);
|
||||
m_windows.remove(window_handle);
|
||||
if (m_windows.is_empty())
|
||||
close();
|
||||
};
|
||||
|
||||
pending_connection->async_set_page_load_strategy(m_page_load_strategy);
|
||||
pending_connection->async_set_strict_file_interactability(m_strict_file_interactiblity);
|
||||
pending_connection->async_set_user_prompt_handler(Web::WebDriver::user_prompt_handler());
|
||||
if (m_timeouts_configuration.has_value())
|
||||
pending_connection->async_set_timeouts(*m_timeouts_configuration);
|
||||
|
||||
m_windows.set(window_handle, Session::Window { window_handle, move(pending_connection) });
|
||||
|
||||
if (m_current_window_handle.is_empty())
|
||||
m_current_window_handle = window_handle;
|
||||
|
||||
promise->resolve({});
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> Session::create_server(NonnullRefPtr<ServerPromise> promise)
|
||||
{
|
||||
#if defined(AK_OS_WINDOWS)
|
||||
static_assert(IsSame<IPC::Transport, IPC::TransportSocketWindows>, "Need to handle other IPC transports here");
|
||||
@@ -210,12 +268,44 @@ ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<S
|
||||
static_assert(IsSame<IPC::Transport, IPC::TransportSocket>, "Need to handle other IPC transports here");
|
||||
#endif
|
||||
|
||||
dbgln("Listening for WebDriver connection on {}", *m_web_content_socket_path);
|
||||
dbgln("Listening for WebDriver connection on {}", m_web_content_endpoint);
|
||||
|
||||
(void)Core::System::unlink(*m_web_content_socket_path);
|
||||
#if defined(AK_OS_MACOS)
|
||||
m_web_content_mach_port_server = make<WebView::MachPortServer>(m_web_content_endpoint);
|
||||
if (!m_web_content_mach_port_server->is_initialized())
|
||||
return Error::from_string_literal("Failed to initialize Mach port server for WebDriver");
|
||||
|
||||
m_web_content_mach_port_server->on_receive_child_mach_port = [this, promise](auto registration) {
|
||||
auto registration_result = m_transport_bootstrap_server.register_reply_port(registration.pid, move(registration.reply_port));
|
||||
if (registration_result.is_error()) {
|
||||
auto event_loop = m_event_loop->take();
|
||||
VERIFY(event_loop);
|
||||
event_loop->deferred_invoke([promise, error = registration_result.release_error()]() mutable {
|
||||
promise->resolve(move(error));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
registration_result.release_value().visit(
|
||||
[](IPC::TransportBootstrapMachServer::WaitingForChildTransport) {
|
||||
VERIFY_NOT_REACHED();
|
||||
},
|
||||
[this, promise](IPC::TransportBootstrapMachServer::OnDemandTransport& transport) {
|
||||
auto event_loop = m_event_loop->take();
|
||||
VERIFY(event_loop);
|
||||
event_loop->deferred_invoke([this, promise, transport = move(transport.ports)]() mutable {
|
||||
if (auto result = accept_web_content_transport(make<IPC::Transport>(move(transport.receive_right), move(transport.send_right)), promise); result.is_error())
|
||||
promise->resolve(result.release_error());
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {};
|
||||
#else
|
||||
(void)Core::System::unlink(m_web_content_endpoint);
|
||||
|
||||
auto server = Core::LocalServer::construct();
|
||||
server->listen(*m_web_content_socket_path);
|
||||
server->listen(m_web_content_endpoint);
|
||||
|
||||
server->on_accept = [this, promise](auto client_socket) {
|
||||
auto maybe_transport = IPC::Transport::from_socket(move(client_socket));
|
||||
@@ -223,73 +313,31 @@ ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<S
|
||||
promise->resolve(maybe_transport.release_error());
|
||||
return;
|
||||
}
|
||||
auto maybe_connection = adopt_nonnull_ref_or_enomem(new (nothrow) WebContentConnection(maybe_transport.release_value()));
|
||||
if (maybe_connection.is_error()) {
|
||||
promise->resolve(maybe_connection.release_error());
|
||||
return;
|
||||
}
|
||||
|
||||
dbgln("WebDriver is connected to WebContent socket");
|
||||
auto web_content_connection = maybe_connection.release_value();
|
||||
|
||||
auto connection_id = m_next_pending_connection_id++;
|
||||
|
||||
web_content_connection->on_close = [this, promise, connection_id]() {
|
||||
if (m_pending_connections.remove(connection_id)) {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Pending connection {} closed before sending its handle", connection_id);
|
||||
promise->reject(Error::from_string_literal("Window was closed before sending its handle"));
|
||||
}
|
||||
};
|
||||
|
||||
web_content_connection->on_did_set_window_handle = [this, promise, connection_id](String window_handle) {
|
||||
auto maybe_pending_connection = m_pending_connections.take(connection_id);
|
||||
if (!maybe_pending_connection.has_value())
|
||||
return;
|
||||
|
||||
auto pending_connection = maybe_pending_connection.value();
|
||||
pending_connection->on_did_set_window_handle = nullptr;
|
||||
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} registered with WebDriver.", window_handle);
|
||||
|
||||
pending_connection->on_close = [this, window_handle]() {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} was closed remotely.", window_handle);
|
||||
m_windows.remove(window_handle);
|
||||
if (m_windows.is_empty())
|
||||
close();
|
||||
};
|
||||
|
||||
pending_connection->async_set_page_load_strategy(m_page_load_strategy);
|
||||
pending_connection->async_set_strict_file_interactability(m_strict_file_interactiblity);
|
||||
pending_connection->async_set_user_prompt_handler(Web::WebDriver::user_prompt_handler());
|
||||
if (m_timeouts_configuration.has_value())
|
||||
pending_connection->async_set_timeouts(*m_timeouts_configuration);
|
||||
|
||||
m_windows.set(window_handle, Session::Window { window_handle, move(pending_connection) });
|
||||
|
||||
if (m_current_window_handle.is_empty())
|
||||
m_current_window_handle = window_handle;
|
||||
|
||||
promise->resolve({});
|
||||
};
|
||||
|
||||
m_pending_connections.set(connection_id, move(web_content_connection));
|
||||
if (auto result = accept_web_content_transport(maybe_transport.release_value(), promise); result.is_error())
|
||||
promise->resolve(result.release_error());
|
||||
};
|
||||
|
||||
server->on_accept_error = [promise](auto error) {
|
||||
promise->resolve(move(error));
|
||||
};
|
||||
|
||||
return server;
|
||||
m_web_content_server = server;
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
ErrorOr<void> Session::start(LaunchBrowserCallback const& launch_browser_callback)
|
||||
{
|
||||
auto promise = ServerPromise::construct();
|
||||
|
||||
m_web_content_socket_path = ByteString::formatted("{}/webdriver/session_{}_{}", TRY(Core::StandardPaths::runtime_directory()), Core::System::getpid(), m_session_id);
|
||||
m_web_content_server = TRY(create_server(promise));
|
||||
#if defined(AK_OS_MACOS)
|
||||
m_web_content_endpoint = ByteString::formatted("{}.{}", WebView::mach_server_name_for_process("WebDriver"sv, Core::System::getpid()), m_session_id);
|
||||
#else
|
||||
m_web_content_endpoint = ByteString::formatted("{}/webdriver/session_{}_{}", TRY(Core::StandardPaths::runtime_directory()), Core::System::getpid(), m_session_id);
|
||||
#endif
|
||||
TRY(create_server(promise));
|
||||
|
||||
m_browser_process = TRY(launch_browser_callback(*m_web_content_socket_path, m_options.headless));
|
||||
m_browser_process = TRY(launch_browser_callback(m_web_content_endpoint, m_options.headless));
|
||||
|
||||
// FIXME: Allow this to be more asynchronous. For now, this at least allows us to propagate
|
||||
// errors received while accepting the Browser and WebContent sockets.
|
||||
|
||||
@@ -10,11 +10,18 @@
|
||||
|
||||
#include <AK/Error.h>
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#if !defined(AK_OS_MACOS)
|
||||
# include <LibCore/LocalServer.h>
|
||||
#else
|
||||
# include <LibIPC/TransportBootstrapMach.h>
|
||||
# include <LibWebView/MachPortServer.h>
|
||||
#endif
|
||||
#include <LibCore/Process.h>
|
||||
#include <LibCore/Promise.h>
|
||||
#include <LibWeb/WebDriver/Capabilities.h>
|
||||
@@ -85,10 +92,11 @@ public:
|
||||
private:
|
||||
Session(NonnullRefPtr<Client> client, JsonObject const& capabilities, String session_id, Web::WebDriver::SessionFlags flags);
|
||||
|
||||
ErrorOr<void> start(LaunchBrowserCallback const&);
|
||||
|
||||
using ServerPromise = Core::Promise<ErrorOr<void>>;
|
||||
ErrorOr<NonnullRefPtr<Core::LocalServer>> create_server(NonnullRefPtr<ServerPromise> promise);
|
||||
|
||||
ErrorOr<void> start(LaunchBrowserCallback const&);
|
||||
ErrorOr<void> accept_web_content_transport(NonnullOwnPtr<IPC::Transport>, NonnullRefPtr<ServerPromise> promise);
|
||||
ErrorOr<void> create_server(NonnullRefPtr<ServerPromise> promise);
|
||||
|
||||
NonnullRefPtr<Client> m_client;
|
||||
Web::WebDriver::LadybirdOptions m_options;
|
||||
@@ -102,10 +110,16 @@ private:
|
||||
HashMap<u64, NonnullRefPtr<WebContentConnection>> m_pending_connections;
|
||||
u64 m_next_pending_connection_id { 0 };
|
||||
|
||||
Optional<ByteString> m_web_content_socket_path;
|
||||
ByteString m_web_content_endpoint;
|
||||
Optional<Core::Process> m_browser_process;
|
||||
NonnullRefPtr<Core::WeakEventLoopReference> m_event_loop;
|
||||
|
||||
#if defined(AK_OS_MACOS)
|
||||
OwnPtr<WebView::MachPortServer> m_web_content_mach_port_server;
|
||||
IPC::TransportBootstrapMachServer m_transport_bootstrap_server;
|
||||
#else
|
||||
RefPtr<Core::LocalServer> m_web_content_server;
|
||||
#endif
|
||||
|
||||
Web::WebDriver::PageLoadStrategy m_page_load_strategy { Web::WebDriver::PageLoadStrategy::Normal };
|
||||
Optional<JsonValue> m_timeouts_configuration;
|
||||
|
||||
@@ -33,12 +33,15 @@ static ErrorOr<Core::Process> launch_process(StringView application, ReadonlySpa
|
||||
return result;
|
||||
}
|
||||
|
||||
static Vector<ByteString> create_arguments(ByteString const& socket_path, bool headless, bool expose_experimental_interfaces, bool force_cpu_painting, Optional<StringView> debug_process, Optional<StringView> default_time_zone)
|
||||
static Vector<ByteString> create_arguments(ByteString const& webdriver_endpoint, bool headless, bool expose_experimental_interfaces, bool force_cpu_painting, Optional<StringView> debug_process, Optional<StringView> default_time_zone)
|
||||
{
|
||||
Vector<ByteString> arguments {
|
||||
"--webdriver-content-path"sv,
|
||||
socket_path,
|
||||
};
|
||||
Vector<ByteString> arguments;
|
||||
#if defined(AK_OS_MACOS)
|
||||
arguments.append("--webdriver-mach-server-name"sv);
|
||||
#else
|
||||
arguments.append("--webdriver-content-path"sv);
|
||||
#endif
|
||||
arguments.append(webdriver_endpoint);
|
||||
|
||||
Vector<ByteString> certificate_args;
|
||||
for (auto const& certificate : certificates) {
|
||||
@@ -131,8 +134,8 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
||||
return;
|
||||
}
|
||||
|
||||
auto launch_browser_callback = [&](ByteString const& socket_path, bool headless) {
|
||||
auto arguments = create_arguments(socket_path, headless, expose_experimental_interfaces, force_cpu_painting, debug_process, default_time_zone);
|
||||
auto launch_browser_callback = [&](ByteString const& webdriver_endpoint, bool headless) {
|
||||
auto arguments = create_arguments(webdriver_endpoint, headless, expose_experimental_interfaces, force_cpu_painting, debug_process, default_time_zone);
|
||||
return launch_process("Ladybird"sv, arguments.span());
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user