mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
WebDriver: Send window handle asynchronously after WebContent connects
This prevents a potential deadlock when tests open many popup windows in quick succession.
This commit is contained in:
Notes:
github-actions[bot]
2026-02-15 13:22:53 +00:00
Author: https://github.com/tcl3 Commit: https://github.com/LadybirdBrowser/ladybird/commit/cb803899c26 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7889 Reviewed-by: https://github.com/trflynn89
@@ -203,7 +203,9 @@ ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(Web::Pa
|
||||
page_client.page().set_should_block_pop_ups(false);
|
||||
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Connected to WebDriver");
|
||||
return adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(make<IPC::Transport>(move(socket)), page_client));
|
||||
auto connection = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(make<IPC::Transport>(move(socket)), page_client)));
|
||||
connection->async_did_set_window_handle(page_client.page().top_level_traversable()->window_handle());
|
||||
return connection;
|
||||
}
|
||||
|
||||
WebDriverConnection::WebDriverConnection(NonnullOwnPtr<IPC::Transport> transport, Web::PageClient& page_client)
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
endpoint WebDriverServer {
|
||||
driver_execution_complete(Web::WebDriver::Response response) =|
|
||||
did_set_window_handle(String handle) =|
|
||||
}
|
||||
|
||||
@@ -181,6 +181,12 @@ void Session::close()
|
||||
// before returning the error.
|
||||
|
||||
// 4. Perform any implementation-specific cleanup steps.
|
||||
for (auto& [_, connection] : m_pending_connections) {
|
||||
connection->on_close = nullptr;
|
||||
connection->on_did_set_window_handle = nullptr;
|
||||
}
|
||||
m_pending_connections.clear();
|
||||
|
||||
if (m_browser_process.has_value())
|
||||
MUST(Core::System::kill(m_browser_process->pid(), SIGTERM));
|
||||
|
||||
@@ -217,33 +223,47 @@ ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<S
|
||||
dbgln("WebDriver is connected to WebContent socket");
|
||||
auto web_content_connection = maybe_connection.release_value();
|
||||
|
||||
auto maybe_window_handle = web_content_connection->get_window_handle();
|
||||
if (maybe_window_handle.is_error()) {
|
||||
promise->reject(Error::from_string_literal("Window was closed immediately"));
|
||||
return;
|
||||
}
|
||||
auto connection_id = m_next_pending_connection_id++;
|
||||
|
||||
auto const& window_handle = maybe_window_handle.value().as_string();
|
||||
|
||||
web_content_connection->on_close = [this, window_handle]() {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} was closed remotely.", window_handle);
|
||||
m_windows.remove(window_handle);
|
||||
if (m_windows.is_empty())
|
||||
close();
|
||||
web_content_connection->on_close = [this, promise, connection_id]() {
|
||||
if (m_pending_connections.remove(connection_id)) {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Pending connection {} closed before sending its handle", connection_id);
|
||||
promise->reject(Error::from_string_literal("Window was closed before sending its handle"));
|
||||
}
|
||||
};
|
||||
|
||||
web_content_connection->async_set_page_load_strategy(m_page_load_strategy);
|
||||
web_content_connection->async_set_strict_file_interactability(m_strict_file_interactiblity);
|
||||
web_content_connection->async_set_user_prompt_handler(Web::WebDriver::user_prompt_handler());
|
||||
if (m_timeouts_configuration.has_value())
|
||||
web_content_connection->async_set_timeouts(*m_timeouts_configuration);
|
||||
web_content_connection->on_did_set_window_handle = [this, promise, connection_id](String window_handle) {
|
||||
auto maybe_pending_connection = m_pending_connections.take(connection_id);
|
||||
if (!maybe_pending_connection.has_value())
|
||||
return;
|
||||
|
||||
m_windows.set(window_handle, Session::Window { window_handle, move(web_content_connection) });
|
||||
auto pending_connection = maybe_pending_connection.value();
|
||||
pending_connection->on_did_set_window_handle = nullptr;
|
||||
|
||||
if (m_current_window_handle.is_empty())
|
||||
m_current_window_handle = window_handle;
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} registered with WebDriver.", window_handle);
|
||||
|
||||
promise->resolve({});
|
||||
pending_connection->on_close = [this, window_handle]() {
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Window {} was closed remotely.", window_handle);
|
||||
m_windows.remove(window_handle);
|
||||
if (m_windows.is_empty())
|
||||
close();
|
||||
};
|
||||
|
||||
pending_connection->async_set_page_load_strategy(m_page_load_strategy);
|
||||
pending_connection->async_set_strict_file_interactability(m_strict_file_interactiblity);
|
||||
pending_connection->async_set_user_prompt_handler(Web::WebDriver::user_prompt_handler());
|
||||
if (m_timeouts_configuration.has_value())
|
||||
pending_connection->async_set_timeouts(*m_timeouts_configuration);
|
||||
|
||||
m_windows.set(window_handle, Session::Window { window_handle, move(pending_connection) });
|
||||
|
||||
if (m_current_window_handle.is_empty())
|
||||
m_current_window_handle = window_handle;
|
||||
|
||||
promise->resolve({});
|
||||
};
|
||||
|
||||
m_pending_connections.set(connection_id, move(web_content_connection));
|
||||
};
|
||||
|
||||
server->on_accept_error = [promise](auto error) {
|
||||
|
||||
@@ -99,6 +99,9 @@ private:
|
||||
HashMap<String, Window> m_windows;
|
||||
String m_current_window_handle;
|
||||
|
||||
HashMap<u64, NonnullRefPtr<WebContentConnection>> m_pending_connections;
|
||||
u64 m_next_pending_connection_id { 0 };
|
||||
|
||||
Optional<ByteString> m_web_content_socket_path;
|
||||
Optional<Core::Process> m_browser_process;
|
||||
|
||||
|
||||
@@ -26,4 +26,10 @@ void WebContentConnection::driver_execution_complete(Web::WebDriver::Response re
|
||||
on_driver_execution_complete(move(response));
|
||||
}
|
||||
|
||||
void WebContentConnection::did_set_window_handle(String handle)
|
||||
{
|
||||
if (on_did_set_window_handle)
|
||||
on_did_set_window_handle(move(handle));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,11 +23,13 @@ public:
|
||||
|
||||
Function<void()> on_close;
|
||||
Function<void(Web::WebDriver::Response)> on_driver_execution_complete;
|
||||
Function<void(String)> on_did_set_window_handle;
|
||||
|
||||
private:
|
||||
virtual void die() override;
|
||||
|
||||
virtual void driver_execution_complete(Web::WebDriver::Response) override;
|
||||
virtual void did_set_window_handle(String) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user