diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index 829c1cc8f5..85bcd53aa9 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -20,14 +20,18 @@ namespace WebDriver { Atomic Client::s_next_session_id; NonnullOwnPtrVector Client::s_sessions; -ErrorOr> Client::try_create(NonnullOwnPtr socket, Core::Object* parent) +ErrorOr> Client::try_create(NonnullOwnPtr socket, LaunchBrowserCallbacks callbacks, Core::Object* parent) { + if (!callbacks.launch_browser || !callbacks.launch_headless_browser) + return Error::from_string_view("All callbacks to launch a browser must be provided"sv); + TRY(socket->set_blocking(true)); - return adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), parent)); + return adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), move(callbacks), parent)); } -Client::Client(NonnullOwnPtr socket, Core::Object* parent) +Client::Client(NonnullOwnPtr socket, LaunchBrowserCallbacks callbacks, Core::Object* parent) : Web::WebDriver::Client(move(socket), parent) + , m_callbacks(move(callbacks)) { } @@ -154,7 +158,7 @@ Web::WebDriver::Response Client::new_session(Web::WebDriver::Parameters, JsonVal Web::WebDriver::LadybirdOptions options { capabilities.as_object() }; auto session = make(session_id, *this, move(options)); - if (auto start_result = session->start(); start_result.is_error()) + if (auto start_result = session->start(m_callbacks); start_result.is_error()) return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::SessionNotCreated, DeprecatedString::formatted("Failed to start session: {}", start_result.error().string_literal())); auto& web_content_connection = session->web_content_connection(); diff --git a/Userland/Services/WebDriver/Client.h b/Userland/Services/WebDriver/Client.h index d590ba87ff..bfc1728c42 100644 --- a/Userland/Services/WebDriver/Client.h +++ b/Userland/Services/WebDriver/Client.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -18,17 +19,22 @@ namespace WebDriver { +struct LaunchBrowserCallbacks { + Function(DeprecatedString const&)> launch_browser; + Function(DeprecatedString const&)> launch_headless_browser; +}; + class Client final : public Web::WebDriver::Client { C_OBJECT_ABSTRACT(Client); public: - static ErrorOr> try_create(NonnullOwnPtr, Core::Object* parent); + static ErrorOr> try_create(NonnullOwnPtr, LaunchBrowserCallbacks, Core::Object* parent); virtual ~Client() override; void close_session(unsigned session_id); private: - Client(NonnullOwnPtr, Core::Object* parent); + Client(NonnullOwnPtr, LaunchBrowserCallbacks, Core::Object* parent); ErrorOr find_session_with_id(StringView session_id); ErrorOr, Web::WebDriver::Error> take_session_with_id(StringView session_id); @@ -87,6 +93,8 @@ private: static NonnullOwnPtrVector s_sessions; static Atomic s_next_session_id; + + LaunchBrowserCallbacks m_callbacks; }; } diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 46692dc359..08d4deb4fa 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -58,33 +58,17 @@ ErrorOr> Session::create_server(DeprecatedStrin return server; } -ErrorOr Session::start() +ErrorOr Session::start(LaunchBrowserCallbacks const& callbacks) { auto promise = TRY(ServerPromise::try_create()); auto web_content_socket_path = DeprecatedString::formatted("{}/webdriver/session_{}_{}", TRY(Core::StandardPaths::runtime_directory()), getpid(), m_id); auto web_content_server = TRY(create_server(web_content_socket_path, promise)); - if (m_options.headless) { - char const* argv[] = { - "/bin/headless-browser", - "--webdriver-ipc-path", - web_content_socket_path.characters(), - "about:blank", - nullptr, - }; - - m_browser_pid = TRY(Core::System::posix_spawn("/bin/headless-browser"sv, nullptr, nullptr, const_cast(argv), environ)); - } else { - char const* argv[] = { - "/bin/Browser", - "--webdriver-content-path", - web_content_socket_path.characters(), - nullptr, - }; - - m_browser_pid = TRY(Core::System::posix_spawn("/bin/Browser"sv, nullptr, nullptr, const_cast(argv), environ)); - } + if (m_options.headless) + m_browser_pid = TRY(callbacks.launch_headless_browser(web_content_socket_path)); + else + m_browser_pid = TRY(callbacks.launch_browser(web_content_socket_path)); // 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. diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index 31e55a7be7..426df466bd 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -19,6 +19,8 @@ namespace WebDriver { +struct LaunchBrowserCallbacks; + class Session { public: Session(unsigned session_id, NonnullRefPtr client, Web::WebDriver::LadybirdOptions options); @@ -32,7 +34,7 @@ public: return *m_web_content_connection; } - ErrorOr start(); + ErrorOr start(LaunchBrowserCallbacks const&); Web::WebDriver::Response stop(); private: diff --git a/Userland/Services/WebDriver/main.cpp b/Userland/Services/WebDriver/main.cpp index bebf3f7577..29a4eeb242 100644 --- a/Userland/Services/WebDriver/main.cpp +++ b/Userland/Services/WebDriver/main.cpp @@ -13,6 +13,31 @@ #include #include +static ErrorOr launch_browser(DeprecatedString const& socket_path) +{ + char const* argv[] = { + "/bin/Browser", + "--webdriver-content-path", + socket_path.characters(), + nullptr, + }; + + return Core::System::posix_spawn("/bin/Browser"sv, nullptr, nullptr, const_cast(argv), environ); +} + +static ErrorOr launch_headless_browser(DeprecatedString const& socket_path) +{ + char const* argv[] = { + "/bin/headless-browser", + "--webdriver-ipc-path", + socket_path.characters(), + "about:blank", + nullptr, + }; + + return Core::System::posix_spawn("/bin/headless-browser"sv, nullptr, nullptr, const_cast(argv), environ); +} + ErrorOr serenity_main(Main::Arguments arguments) { DeprecatedString default_listen_address = "0.0.0.0"; @@ -62,7 +87,7 @@ ErrorOr serenity_main(Main::Arguments arguments) return; } - auto maybe_client = WebDriver::Client::try_create(maybe_buffered_socket.release_value(), server); + auto maybe_client = WebDriver::Client::try_create(maybe_buffered_socket.release_value(), { launch_browser, launch_headless_browser }, server); if (maybe_client.is_error()) { warnln("Could not create a WebDriver client: {}", maybe_client.error()); return;