WebContent+WebDriver: Transfer WebDriver capability init to Session

Capabilities are configured on a per-session basis, but we were only
applying these options to the first WebContent process created. We will
need to pass these options to new windows created from that process.
This patch re-organizes capability processing so that our session can
remember them for new windows.
This commit is contained in:
Timothy Flynn 2024-11-04 08:37:16 -05:00 committed by Andrew Kaster
parent f5d67cefc1
commit d66b54fec5
Notes: github-actions[bot] 2024-11-05 19:07:17 +00:00
4 changed files with 77 additions and 53 deletions

View file

@ -279,7 +279,8 @@ Messages::WebDriverClient::SetTimeoutsResponse WebDriverConnection::set_timeouts
// 2. Make the session timeouts the new timeouts.
// 3. Return success with data null.
return JsonValue {};
// NOTE: We return the current timeouts configuration so the client may store them for new sessions.
return Web::WebDriver::timeouts_object(m_timeouts_configuration);
}
// 10.1 Navigate To, https://w3c.github.io/webdriver/#navigate-to

View file

@ -14,7 +14,6 @@
#include <LibCore/EventLoop.h>
#include <LibCore/Timer.h>
#include <LibWeb/WebDriver/Capabilities.h>
#include <LibWeb/WebDriver/TimeoutsConfiguration.h>
#include <WebDriver/Client.h>
namespace WebDriver {
@ -63,53 +62,6 @@ void Client::close_session(unsigned session_id)
dbgln_if(WEBDRIVER_DEBUG, "Unable to shut down session {}: Not found", session_id);
}
// Step 12 of https://w3c.github.io/webdriver/#dfn-new-sessions
static void initialize_session_from_capabilities(WebContentConnection& web_content_connection, JsonObject& capabilities)
{
// 1. Let strategy be the result of getting property "pageLoadStrategy" from capabilities.
auto strategy = capabilities.get_byte_string("pageLoadStrategy"sv);
// 2. If strategy is a string, set the current sessions page loading strategy to strategy. Otherwise, set the page loading strategy to normal and set a property of capabilities with name "pageLoadStrategy" and value "normal".
if (strategy.has_value())
web_content_connection.async_set_page_load_strategy(Web::WebDriver::page_load_strategy_from_string(*strategy));
else
capabilities.set("pageLoadStrategy"sv, "normal"sv);
// 3. Let strictFileInteractability be the result of getting property "strictFileInteractability" from capabilities.
auto strict_file_interactiblity = capabilities.get_bool("strictFileInteractability"sv);
// 4. If strictFileInteractability is a boolean, set the current sessions strict file interactability to strictFileInteractability. Otherwise set the current sessions strict file interactability to false.
if (strict_file_interactiblity.has_value())
web_content_connection.async_set_strict_file_interactability(*strict_file_interactiblity);
else
capabilities.set("strictFileInteractability"sv, false);
// FIXME: 5. Let proxy be the result of getting property "proxy" from capabilities and run the substeps of the first matching statement:
// FIXME: proxy is a proxy configuration object
// FIXME: Take implementation-defined steps to set the user agent proxy using the extracted proxy configuration. If the defined proxy cannot be configured return error with error code session not created.
// FIXME: Otherwise
// FIXME: Set a property of capabilities with name "proxy" and a value that is a new JSON Object.
// 6. If capabilities has a property with the key "timeouts":
if (auto timeouts = capabilities.get_object("timeouts"sv); timeouts.has_value()) {
// a. Let timeouts be the result of trying to JSON deserialize as a timeouts configuration the value of the "timeouts" property.
// NOTE: This happens on the remote end.
// b. Make the session timeouts the new timeouts.
MUST(web_content_connection.set_timeouts(*timeouts));
} else {
// 7. Set a property on capabilities with name "timeouts" and value that of the JSON deserialization of the session timeouts.
capabilities.set("timeouts"sv, Web::WebDriver::timeouts_object({}));
}
// 8. Apply changes to the user agent for any implementation-defined capabilities selected during the capabilities processing step.
auto behavior = capabilities.get_byte_string("unhandledPromptBehavior"sv);
if (behavior.has_value())
web_content_connection.async_set_unhandled_prompt_behavior(Web::WebDriver::unhandled_prompt_behavior_from_string(*behavior));
else
capabilities.set("unhandledPromptBehavior"sv, "dismiss and notify"sv);
}
// 8.1 New Session, https://w3c.github.io/webdriver/#dfn-new-sessions
// POST /session
Web::WebDriver::Response Client::new_session(Web::WebDriver::Parameters, JsonValue payload)
@ -155,12 +107,12 @@ Web::WebDriver::Response Client::new_session(Web::WebDriver::Parameters, JsonVal
// with arguments session and capabilities.
// 10. Append session to active sessions.
s_sessions.set(session_id, move(session));
s_sessions.set(session_id, session);
// NOTE: We do step 12 before 11 because step 12 mutates the capabilities we set in step 11.
// 12. Initialize the following from capabilities:
initialize_session_from_capabilities(web_content_connection, capabilities.as_object());
session->initialize_from_capabilities(capabilities.as_object());
// 11. Let body be a JSON Object initialized with:
JsonObject body;
@ -232,7 +184,7 @@ Web::WebDriver::Response Client::set_timeouts(Web::WebDriver::Parameters paramet
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session id>/timeouts");
auto session = TRY(find_session_with_id(parameters[0]));
return session->web_content_connection().set_timeouts(payload);
return session->set_timeouts(move(payload));
}
// 10.1 Navigate To, https://w3c.github.io/webdriver/#dfn-navigate-to

View file

@ -11,10 +11,10 @@
#include "Session.h"
#include "Client.h"
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <LibCore/LocalServer.h>
#include <LibCore/StandardPaths.h>
#include <LibCore/System.h>
#include <LibWeb/WebDriver/TimeoutsConfiguration.h>
#include <unistd.h>
namespace WebDriver {
@ -53,6 +53,60 @@ Session::~Session()
}
}
// Step 12 of https://w3c.github.io/webdriver/#dfn-new-sessions
void Session::initialize_from_capabilities(JsonObject& capabilities)
{
auto& connection = web_content_connection();
// 1. Let strategy be the result of getting property "pageLoadStrategy" from capabilities.
auto strategy = capabilities.get_byte_string("pageLoadStrategy"sv);
// 2. If strategy is a string, set the current sessions page loading strategy to strategy. Otherwise, set the page loading strategy to normal and set a property of capabilities with name "pageLoadStrategy" and value "normal".
if (strategy.has_value()) {
m_page_load_strategy = Web::WebDriver::page_load_strategy_from_string(*strategy);
connection.async_set_page_load_strategy(m_page_load_strategy);
} else {
capabilities.set("pageLoadStrategy"sv, "normal"sv);
}
// 3. Let strictFileInteractability be the result of getting property "strictFileInteractability" from capabilities.
auto strict_file_interactiblity = capabilities.get_bool("strictFileInteractability"sv);
// 4. If strictFileInteractability is a boolean, set the current sessions strict file interactability to strictFileInteractability. Otherwise set the current sessions strict file interactability to false.
if (strict_file_interactiblity.has_value()) {
m_strict_file_interactiblity = *strict_file_interactiblity;
connection.async_set_strict_file_interactability(m_strict_file_interactiblity);
} else {
capabilities.set("strictFileInteractability"sv, false);
}
// FIXME: 5. Let proxy be the result of getting property "proxy" from capabilities and run the substeps of the first matching statement:
// FIXME: proxy is a proxy configuration object
// FIXME: Take implementation-defined steps to set the user agent proxy using the extracted proxy configuration. If the defined proxy cannot be configured return error with error code session not created.
// FIXME: Otherwise
// FIXME: Set a property of capabilities with name "proxy" and a value that is a new JSON Object.
// 6. If capabilities has a property with the key "timeouts":
if (auto timeouts = capabilities.get_object("timeouts"sv); timeouts.has_value()) {
// a. Let timeouts be the result of trying to JSON deserialize as a timeouts configuration the value of the "timeouts" property.
// NOTE: This happens on the remote end.
// b. Make the session timeouts the new timeouts.
MUST(set_timeouts(*timeouts));
} else {
// 7. Set a property on capabilities with name "timeouts" and value that of the JSON deserialization of the session timeouts.
capabilities.set("timeouts"sv, Web::WebDriver::timeouts_object({}));
}
// 8. Apply changes to the user agent for any implementation-defined capabilities selected during the capabilities processing step.
if (auto behavior = capabilities.get_byte_string("unhandledPromptBehavior"sv); behavior.has_value()) {
m_unhandled_prompt_behavior = Web::WebDriver::unhandled_prompt_behavior_from_string(*behavior);
connection.async_set_unhandled_prompt_behavior(m_unhandled_prompt_behavior);
} else {
capabilities.set("unhandledPromptBehavior"sv, "dismiss and notify"sv);
}
}
ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<ServerPromise> promise)
{
static_assert(IsSame<IPC::Transport, IPC::TransportSocket>, "Need to handle other IPC transports here");
@ -123,6 +177,12 @@ ErrorOr<void> Session::start(LaunchBrowserCallbacks const& callbacks)
return {};
}
Web::WebDriver::Response Session::set_timeouts(JsonValue payload)
{
m_timeouts_configuration = TRY(web_content_connection().set_timeouts(move(payload)));
return JsonValue {};
}
// 11.2 Close Window, https://w3c.github.io/webdriver/#dfn-close-window
Web::WebDriver::Response Session::close_window()
{

View file

@ -9,12 +9,14 @@
#pragma once
#include <AK/Error.h>
#include <AK/JsonValue.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/ScopeGuard.h>
#include <AK/String.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Promise.h>
#include <LibWeb/WebDriver/Capabilities.h>
#include <LibWeb/WebDriver/Error.h>
#include <LibWeb/WebDriver/Response.h>
#include <WebDriver/WebContentConnection.h>
@ -29,6 +31,8 @@ public:
Session(unsigned session_id, NonnullRefPtr<Client> client, Web::WebDriver::LadybirdOptions options);
~Session();
void initialize_from_capabilities(JsonObject&);
unsigned session_id() const { return m_id; }
struct Window {
@ -52,6 +56,8 @@ public:
bool has_window_handle(StringView handle) const { return m_windows.contains(handle); }
ErrorOr<void> start(LaunchBrowserCallbacks const&);
Web::WebDriver::Response set_timeouts(JsonValue);
Web::WebDriver::Response close_window();
Web::WebDriver::Response switch_to_window(StringView);
Web::WebDriver::Response get_window_handles() const;
@ -92,6 +98,11 @@ private:
Optional<pid_t> m_browser_pid;
RefPtr<Core::LocalServer> m_web_content_server;
Web::WebDriver::PageLoadStrategy m_page_load_strategy { Web::WebDriver::PageLoadStrategy::Normal };
Web::WebDriver::UnhandledPromptBehavior m_unhandled_prompt_behavior { Web::WebDriver::UnhandledPromptBehavior::DismissAndNotify };
Optional<JsonValue> m_timeouts_configuration;
bool m_strict_file_interactiblity { false };
};
}