diff options
author | Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com> | 2023-03-06 01:57:36 +0300 |
---|---|---|
committer | Tim Flynn <trflynn89@pm.me> | 2023-03-07 07:16:23 -0500 |
commit | 0905fd57e44ab4ad89e8a6be2c5671b754f204c1 (patch) | |
tree | 565c2181442d6640f9a48d7d1c94bf658a114c16 /Userland/Services | |
parent | d036862f2be6a43e4b702f4a55df400cdcb67dbe (diff) | |
download | serenity-0905fd57e44ab4ad89e8a6be2c5671b754f204c1.zip |
WebContent+WebDriver: Move window commands handling back to WebDriver
With current architecture every window has its own WebContent process
and there is one WebDriver process that is responsible for talking to
all opened windows. It thus make sense to manage open windows from
WebDriver process instead of WebContent process that is not supposed
to know about all other opened WebContent processes.
This mostly reverts 826d5f8f9ab0e28606a0d07847056bd6562ebc49 but also
adds `web_content_connection` to window structure and window id
generation (currently out of spec).
With these changes `get_window_handles`, `switch_to_window` and
`close_window` start to actually switch, close and returned handles
of currently opened windows.
Diffstat (limited to 'Userland/Services')
-rw-r--r-- | Userland/Services/WebContent/WebDriverClient.ipc | 3 | ||||
-rw-r--r-- | Userland/Services/WebContent/WebDriverConnection.cpp | 63 | ||||
-rw-r--r-- | Userland/Services/WebContent/WebDriverConnection.h | 10 | ||||
-rw-r--r-- | Userland/Services/WebDriver/Client.cpp | 28 | ||||
-rw-r--r-- | Userland/Services/WebDriver/Session.cpp | 61 | ||||
-rw-r--r-- | Userland/Services/WebDriver/Session.h | 25 |
6 files changed, 99 insertions, 91 deletions
diff --git a/Userland/Services/WebContent/WebDriverClient.ipc b/Userland/Services/WebContent/WebDriverClient.ipc index 411845071c..28e3ac0096 100644 --- a/Userland/Services/WebContent/WebDriverClient.ipc +++ b/Userland/Services/WebContent/WebDriverClient.ipc @@ -15,10 +15,7 @@ endpoint WebDriverClient { forward() => (Web::WebDriver::Response response) refresh() => (Web::WebDriver::Response response) get_title() => (Web::WebDriver::Response response) - get_window_handle() => (Web::WebDriver::Response response) close_window() => (Web::WebDriver::Response response) - switch_to_window(JsonValue payload) => (Web::WebDriver::Response response) - get_window_handles() => (Web::WebDriver::Response response) get_window_rect() => (Web::WebDriver::Response response) set_window_rect(JsonValue payload) => (Web::WebDriver::Response response) maximize_window() => (Web::WebDriver::Response response) diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index bb45dfd80f..ae62835614 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -331,9 +331,7 @@ ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(Web::Pa WebDriverConnection::WebDriverConnection(NonnullOwnPtr<Core::LocalSocket> socket, Web::PageClient& page_client) : IPC::ConnectionToServer<WebDriverClientEndpoint, WebDriverServerEndpoint>(*this, move(socket)) , m_page_client(page_client) - , m_current_window_handle("main"sv) { - m_windows.set(m_current_window_handle, { m_current_window_handle, true }); } // https://w3c.github.io/webdriver/#dfn-close-the-session @@ -518,16 +516,6 @@ Messages::WebDriverClient::GetTitleResponse WebDriverConnection::get_title() return title; } -// 11.1 Get Window Handle, https://w3c.github.io/webdriver/#get-window-handle -Messages::WebDriverClient::GetWindowHandleResponse WebDriverConnection::get_window_handle() -{ - // 1. If the current top-level browsing context is no longer open, return error with error code no such window. - TRY(ensure_open_top_level_browsing_context()); - - // 2. Return success with data being the window handle associated with the current top-level browsing context. - return m_current_window_handle; -} - // 11.2 Close Window, https://w3c.github.io/webdriver/#dfn-close-window Messages::WebDriverClient::CloseWindowResponse WebDriverConnection::close_window() { @@ -539,60 +527,9 @@ Messages::WebDriverClient::CloseWindowResponse WebDriverConnection::close_window // 3. Close the current top-level browsing context. m_page_client.page().top_level_browsing_context().close(); - m_windows.remove(m_current_window_handle); - - // 4. If there are no more open top-level browsing contexts, then close the session. - if (m_windows.is_empty()) - close_session(); - - // 5. Return the result of running the remote end steps for the Get Window Handles command. - return get_window_handles().take_response(); -} - -// 11.3 Switch to Window, https://w3c.github.io/webdriver/#dfn-switch-to-window -Messages::WebDriverClient::SwitchToWindowResponse WebDriverConnection::switch_to_window(JsonValue const& payload) -{ - // 1. Let handle be the result of getting the property "handle" from the parameters argument. - // 2. If handle is undefined, return error with error code invalid argument. - auto handle = TRY(get_property(payload, "handle"sv)); - - // 3. If there is an active user prompt, that prevents the focusing of another top-level browsing - // context, return error with error code unexpected alert open. - if (m_page_client.page().has_pending_dialog()) - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user dialog is open"sv); - - // 4. If handle is equal to the associated window handle for some top-level browsing context in the - // current session, let context be the that browsing context, and set the current top-level - // browsing context with context. - // Otherwise, return error with error code no such window. - auto const& maybe_window = m_windows.get(handle); - - if (!maybe_window.has_value()) - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchWindow, "Window not found"); - - m_current_window_handle = handle; - - // FIXME: 5. Update any implementation-specific state that would result from the user selecting the current - // browsing context for interaction, without altering OS-level focus. - - // 6. Return success with data null. return JsonValue {}; } -// 11.4 Get Window Handles, https://w3c.github.io/webdriver/#dfn-get-window-handles -Messages::WebDriverClient::GetWindowHandlesResponse WebDriverConnection::get_window_handles() -{ - // 1. Let handles be a JSON List. - JsonArray handles {}; - - // 2. For each top-level browsing context in the remote end, push the associated window handle onto handles. - for (auto const& window_handle : m_windows.keys()) - handles.append(window_handle); - - // 3. Return success with data handles. - return handles; -} - // 11.8.1 Get Window Rect, https://w3c.github.io/webdriver/#dfn-get-window-rect Messages::WebDriverClient::GetWindowRectResponse WebDriverConnection::get_window_rect() { diff --git a/Userland/Services/WebContent/WebDriverConnection.h b/Userland/Services/WebContent/WebDriverConnection.h index 2e80d7cede..7b64828fbb 100644 --- a/Userland/Services/WebContent/WebDriverConnection.h +++ b/Userland/Services/WebContent/WebDriverConnection.h @@ -52,10 +52,7 @@ private: virtual Messages::WebDriverClient::ForwardResponse forward() override; virtual Messages::WebDriverClient::RefreshResponse refresh() override; virtual Messages::WebDriverClient::GetTitleResponse get_title() override; - virtual Messages::WebDriverClient::GetWindowHandleResponse get_window_handle() override; virtual Messages::WebDriverClient::CloseWindowResponse close_window() override; - virtual Messages::WebDriverClient::SwitchToWindowResponse switch_to_window(JsonValue const& payload) override; - virtual Messages::WebDriverClient::GetWindowHandlesResponse get_window_handles() override; virtual Messages::WebDriverClient::GetWindowRectResponse get_window_rect() override; virtual Messages::WebDriverClient::SetWindowRectResponse set_window_rect(JsonValue const& payload) override; virtual Messages::WebDriverClient::MaximizeWindowResponse maximize_window() override; @@ -125,13 +122,6 @@ private: // https://w3c.github.io/webdriver/#dfn-session-script-timeout Web::WebDriver::TimeoutsConfiguration m_timeouts_configuration; - - struct Window { - DeprecatedString handle; - bool is_open { false }; - }; - HashMap<DeprecatedString, Window> m_windows; - DeprecatedString m_current_window_handle; }; } diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index 2bd4c15bb3..c6af656ab5 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -309,7 +309,11 @@ Web::WebDriver::Response Client::get_window_handle(Web::WebDriver::Parameters pa { dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/window"); auto* session = TRY(find_session_with_id(parameters[0])); - return session->web_content_connection().get_window_handle(); + + // FIXME: 1. If the current top-level browsing context is no longer open, return error with error code no such window. + + // 2. Return success with data being the window handle associated with the current top-level browsing context. + return JsonValue { session->current_window_handle() }; } // 11.2 Close Window, https://w3c.github.io/webdriver/#dfn-close-window @@ -318,12 +322,7 @@ Web::WebDriver::Response Client::close_window(Web::WebDriver::Parameters paramet { dbgln_if(WEBDRIVER_DEBUG, "Handling DELETE /session/<session_id>/window"); auto* session = TRY(find_session_with_id(parameters[0])); - - auto open_windows = TRY(session->web_content_connection().close_window()); - if (open_windows.is_array() && open_windows.as_array().is_empty()) - TRY(session->stop()); - - return open_windows; + return session->close_window(); } // 11.3 Switch to Window, https://w3c.github.io/webdriver/#dfn-switch-to-window @@ -332,7 +331,18 @@ Web::WebDriver::Response Client::switch_to_window(Web::WebDriver::Parameters par { dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window"); auto* session = TRY(find_session_with_id(parameters[0])); - return session->web_content_connection().switch_to_window(payload); + + if (!payload.is_object()) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload is not a JSON object"); + + // 1. Let handle be the result of getting the property "handle" from the parameters argument. + auto handle = payload.as_object().get("handle"sv); + + // 2. If handle is undefined, return error with error code invalid argument. + if (!handle.has_value()) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "No property called 'handle' present"); + + return session->switch_to_window(handle->as_string()); } // 11.4 Get Window Handles, https://w3c.github.io/webdriver/#dfn-get-window-handles @@ -341,7 +351,7 @@ Web::WebDriver::Response Client::get_window_handles(Web::WebDriver::Parameters p { dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/window/handles"); auto* session = TRY(find_session_with_id(parameters[0])); - return session->web_content_connection().get_window_handles(); + return session->get_window_handles(); } // 11.8.1 Get Window Rect, https://w3c.github.io/webdriver/#dfn-get-window-rect diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 8e56c08192..3de3394790 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -10,6 +10,7 @@ #include "Session.h" #include "Client.h" +#include <AK/JsonObject.h> #include <LibCore/LocalServer.h> #include <LibCore/StandardPaths.h> #include <LibCore/System.h> @@ -45,7 +46,14 @@ ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<S } dbgln("WebDriver is connected to WebContent socket"); - m_web_content_connection = maybe_connection.release_value(); + auto web_content_connection = maybe_connection.release_value(); + + auto handle_name = String::formatted("window-{}"sv, m_next_handle_id).release_value_but_fixme_should_propagate_errors(); + m_next_handle_id++; + m_windows.set(handle_name, Session::Window { handle_name, move(web_content_connection) }); + + if (m_current_window_handle.is_empty()) + m_current_window_handle = handle_name; promise->resolve({}); }; @@ -85,7 +93,7 @@ Web::WebDriver::Response Session::stop() // 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(); + web_content_connection().close_session(); // 2. Remove the current session from active sessions. // NOTE: Handled by WebDriver::Client. @@ -106,4 +114,53 @@ Web::WebDriver::Response Session::stop() return JsonValue {}; } +// 11.2 Close Window, https://w3c.github.io/webdriver/#dfn-close-window +Web::WebDriver::Response Session::close_window() +{ + // 3. Close the current top-level browsing context. + TRY(web_content_connection().close_window()); + m_windows.remove(m_current_window_handle); + + // 4. If there are no more open top-level browsing contexts, then close the session. + if (m_windows.is_empty()) + stop(); + + // 5. Return the result of running the remote end steps for the Get Window Handles command. + return get_window_handles(); +} + +// 11.3 Switch to Window, https://w3c.github.io/webdriver/#dfn-switch-to-window +Web::WebDriver::Response Session::switch_to_window(StringView handle) +{ + // 4. If handle is equal to the associated window handle for some top-level browsing context in the + // current session, let context be the that browsing context, and set the current top-level + // browsing context with context. + // Otherwise, return error with error code no such window. + if (auto it = m_windows.find(handle); it != m_windows.end()) + m_current_window_handle = it->key; + else + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchWindow, "Window not found"); + + // FIXME: 5. Update any implementation-specific state that would result from the user selecting the current + // browsing context for interaction, without altering OS-level focus. + + // 6. Return success with data null. + return JsonValue {}; +} + +// 11.4 Get Window Handles, https://w3c.github.io/webdriver/#dfn-get-window-handles +Web::WebDriver::Response Session::get_window_handles() const +{ + // 1. Let handles be a JSON List. + JsonArray handles {}; + + // 2. For each top-level browsing context in the remote end, push the associated window handle onto handles. + for (auto const& window_handle : m_windows.keys()) { + handles.append(JsonValue(window_handle)); + } + + // 3. Return success with data handles. + return JsonValue { move(handles) }; +} + } diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index 8c56ebc09f..2af79c8f50 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -10,6 +10,7 @@ #include <AK/Error.h> #include <AK/RefPtr.h> +#include <AK/String.h> #include <LibCore/Promise.h> #include <LibWeb/WebDriver/Capabilities.h> #include <LibWeb/WebDriver/Error.h> @@ -28,14 +29,27 @@ public: unsigned session_id() const { return m_id; } - WebContentConnection& web_content_connection() + struct Window { + String handle; + NonnullRefPtr<WebContentConnection> web_content_connection; + }; + + WebContentConnection& web_content_connection() const { - VERIFY(m_web_content_connection); - return *m_web_content_connection; + auto const& current_window = m_windows.get(m_current_window_handle).value(); + return current_window.web_content_connection; + } + + String const& current_window_handle() const + { + return m_current_window_handle; } ErrorOr<void> start(LaunchBrowserCallbacks const&); Web::WebDriver::Response stop(); + Web::WebDriver::Response close_window(); + Web::WebDriver::Response switch_to_window(StringView); + Web::WebDriver::Response get_window_handles() const; private: using ServerPromise = Core::Promise<ErrorOr<void>>; @@ -47,7 +61,10 @@ private: bool m_started { false }; unsigned m_id { 0 }; - RefPtr<WebContentConnection> m_web_content_connection; + unsigned m_next_handle_id = 0; + HashMap<String, Window> m_windows; + String m_current_window_handle; + Optional<DeprecatedString> m_web_content_socket_path; Optional<pid_t> m_browser_pid; }; |