mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 05:57:44 +00:00
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.
This commit is contained in:
parent
54321f49ad
commit
9e0db602ca
6 changed files with 238 additions and 2 deletions
104
Ladybird/WebDriver/Session.cpp
Normal file
104
Ladybird/WebDriver/Session.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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 end’s 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 {};
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue