1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 19:07:35 +00:00
serenity/Ladybird/WebDriver/Session.cpp
Timothy Flynn 9e0db602ca Ladybird: Implement WebDriver for Ladybird :^)
This adds a WebDriver binary for Ladybird to make use of Serenity's
WebDriver implementation. This has to use the same IPC socket handling
that was used to make WebContent work out-of-process. Besides that, we
are able to reuse almost everything from Serenity.
2022-12-25 07:58:58 -07:00

104 lines
3.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2022, Florent Castelli <florent.castelli@gmail.com>
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#define AK_DONT_REPLACE_STD
#include "Session.h"
#include <LibCore/Stream.h>
#include <LibCore/System.h>
#include <WebDriver/Client.h>
#include <unistd.h>
namespace WebDriver {
Session::Session(unsigned session_id, NonnullRefPtr<Client> client)
: m_client(move(client))
, m_id(session_id)
{
}
Session::~Session()
{
if (auto error = stop(); error.is_error())
warnln("Failed to stop session {}: {}", m_id, error.error());
}
ErrorOr<void> Session::start()
{
int socket_fds[2] {};
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
auto [webdriver_fd, webcontent_fd] = socket_fds;
int fd_passing_socket_fds[2] {};
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
auto [webdriver_fd_passing_fd, webcontent_fd_passing_fd] = fd_passing_socket_fds;
m_browser_pid = TRY(Core::System::fork());
if (m_browser_pid == 0) {
TRY(Core::System::close(webdriver_fd_passing_fd));
TRY(Core::System::close(webdriver_fd));
auto takeover_string = String::formatted("WebDriver:{}", webcontent_fd);
TRY(Core::System::setenv("SOCKET_TAKEOVER"sv, takeover_string, true));
auto fd_passing_socket_string = String::number(webcontent_fd_passing_fd);
char const* argv[] = {
"ladybird",
"--webdriver-fd-passing-socket",
fd_passing_socket_string.characters(),
nullptr,
};
if (execvp("./ladybird", const_cast<char**>(argv)) < 0)
perror("execvp");
VERIFY_NOT_REACHED();
}
TRY(Core::System::close(webcontent_fd_passing_fd));
TRY(Core::System::close(webcontent_fd));
auto socket = TRY(Core::Stream::LocalSocket::adopt_fd(webdriver_fd));
TRY(socket->set_blocking(true));
m_web_content_connection = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebContentConnection(move(socket), m_client, session_id())));
m_web_content_connection->set_fd_passing_socket(TRY(Core::Stream::LocalSocket::adopt_fd(webdriver_fd_passing_fd)));
m_started = true;
return {};
}
// https://w3c.github.io/webdriver/#dfn-close-the-session
Web::WebDriver::Response Session::stop()
{
if (!m_started)
return JsonValue {};
// 1. Perform the following substeps based on the remote ends type:
// NOTE: We perform the "Remote end is an endpoint node" steps in the WebContent process.
m_web_content_connection->close_session();
// 2. Remove the current session from active sessions.
// NOTE: Handled by WebDriver::Client.
// 3. Perform any implementation-specific cleanup steps.
if (m_browser_pid.has_value()) {
MUST(Core::System::kill(*m_browser_pid, SIGTERM));
m_browser_pid = {};
}
m_started = false;
// 4. If an error has occurred in any of the steps above, return the error, otherwise return success with data null.
return JsonValue {};
}
}