Client.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. /*
  2. * Copyright (c) 2022, Florent Castelli <florent.castelli@gmail.com>
  3. * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
  4. * Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
  5. * Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
  6. * Copyright (c) 2022-2024, Tim Flynn <trflynn89@ladybird.org>
  7. *
  8. * SPDX-License-Identifier: BSD-2-Clause
  9. */
  10. #include <AK/Debug.h>
  11. #include <AK/JsonObject.h>
  12. #include <AK/JsonValue.h>
  13. #include <LibWeb/WebDriver/Capabilities.h>
  14. #include <LibWeb/WebDriver/TimeoutsConfiguration.h>
  15. #include <WebDriver/Client.h>
  16. namespace WebDriver {
  17. Atomic<unsigned> Client::s_next_session_id;
  18. HashMap<unsigned, NonnullRefPtr<Session>> Client::s_sessions;
  19. ErrorOr<NonnullRefPtr<Client>> Client::try_create(NonnullOwnPtr<Core::BufferedTCPSocket> socket, LaunchBrowserCallbacks callbacks, Core::EventReceiver* parent)
  20. {
  21. if (!callbacks.launch_browser || !callbacks.launch_headless_browser)
  22. return Error::from_string_literal("All callbacks to launch a browser must be provided");
  23. TRY(socket->set_blocking(true));
  24. return adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), move(callbacks), parent));
  25. }
  26. Client::Client(NonnullOwnPtr<Core::BufferedTCPSocket> socket, LaunchBrowserCallbacks callbacks, Core::EventReceiver* parent)
  27. : Web::WebDriver::Client(move(socket), parent)
  28. , m_callbacks(move(callbacks))
  29. {
  30. }
  31. Client::~Client() = default;
  32. ErrorOr<NonnullRefPtr<Session>, Web::WebDriver::Error> Client::find_session_with_id(StringView session_id, AllowInvalidWindowHandle allow_invalid_window_handle)
  33. {
  34. auto session_id_or_error = session_id.to_number<unsigned>();
  35. if (!session_id_or_error.has_value())
  36. return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidSessionId, "Invalid session id");
  37. if (auto session = s_sessions.get(*session_id_or_error); session.has_value()) {
  38. if (allow_invalid_window_handle == AllowInvalidWindowHandle::No)
  39. TRY(session.value()->ensure_current_window_handle_is_valid());
  40. return *session.release_value();
  41. }
  42. return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidSessionId, "Invalid session id");
  43. }
  44. void Client::close_session(unsigned session_id)
  45. {
  46. if (s_sessions.remove(session_id))
  47. dbgln_if(WEBDRIVER_DEBUG, "Shut down session {}", session_id);
  48. else
  49. dbgln_if(WEBDRIVER_DEBUG, "Unable to shut down session {}: Not found", session_id);
  50. }
  51. // Step 12 of https://w3c.github.io/webdriver/#dfn-new-sessions
  52. static void initialize_session_from_capabilities(WebContentConnection& web_content_connection, JsonObject& capabilities)
  53. {
  54. // 1. Let strategy be the result of getting property "pageLoadStrategy" from capabilities.
  55. auto strategy = capabilities.get_byte_string("pageLoadStrategy"sv);
  56. // 2. If strategy is a string, set the current session’s 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".
  57. if (strategy.has_value())
  58. web_content_connection.async_set_page_load_strategy(Web::WebDriver::page_load_strategy_from_string(*strategy));
  59. else
  60. capabilities.set("pageLoadStrategy"sv, "normal"sv);
  61. // 3. Let strictFileInteractability be the result of getting property "strictFileInteractability" from capabilities.
  62. auto strict_file_interactiblity = capabilities.get_bool("strictFileInteractability"sv);
  63. // 4. If strictFileInteractability is a boolean, set the current session’s strict file interactability to strictFileInteractability. Otherwise set the current session’s strict file interactability to false.
  64. if (strict_file_interactiblity.has_value())
  65. web_content_connection.async_set_strict_file_interactability(*strict_file_interactiblity);
  66. else
  67. capabilities.set("strictFileInteractability"sv, false);
  68. // FIXME: 5. Let proxy be the result of getting property "proxy" from capabilities and run the substeps of the first matching statement:
  69. // FIXME: proxy is a proxy configuration object
  70. // 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.
  71. // FIXME: Otherwise
  72. // FIXME: Set a property of capabilities with name "proxy" and a value that is a new JSON Object.
  73. // 6. If capabilities has a property with the key "timeouts":
  74. if (auto timeouts = capabilities.get_object("timeouts"sv); timeouts.has_value()) {
  75. // a. Let timeouts be the result of trying to JSON deserialize as a timeouts configuration the value of the "timeouts" property.
  76. // NOTE: This happens on the remote end.
  77. // b. Make the session timeouts the new timeouts.
  78. MUST(web_content_connection.set_timeouts(*timeouts));
  79. } else {
  80. // 7. Set a property on capabilities with name "timeouts" and value that of the JSON deserialization of the session timeouts.
  81. capabilities.set("timeouts"sv, Web::WebDriver::timeouts_object({}));
  82. }
  83. // 8. Apply changes to the user agent for any implementation-defined capabilities selected during the capabilities processing step.
  84. auto behavior = capabilities.get_byte_string("unhandledPromptBehavior"sv);
  85. if (behavior.has_value())
  86. web_content_connection.async_set_unhandled_prompt_behavior(Web::WebDriver::unhandled_prompt_behavior_from_string(*behavior));
  87. else
  88. capabilities.set("unhandledPromptBehavior"sv, "dismiss and notify"sv);
  89. }
  90. // 8.1 New Session, https://w3c.github.io/webdriver/#dfn-new-sessions
  91. // POST /session
  92. Web::WebDriver::Response Client::new_session(Web::WebDriver::Parameters, JsonValue payload)
  93. {
  94. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session");
  95. // FIXME: 1. If the maximum active sessions is equal to the length of the list of active sessions,
  96. // return error with error code session not created.
  97. // FIXME: 2. If the remote end is an intermediary node, take implementation-defined steps that either
  98. // result in returning an error with error code session not created, or in returning a
  99. // success with data that is isomorphic to that returned by remote ends according to the
  100. // rest of this algorithm. If an error is not returned, the intermediary node must retain a
  101. // reference to the session created on the upstream node as the associated session such
  102. // that commands may be forwarded to this associated session on subsequent commands.
  103. // FIXME: 3. If the maximum active sessions is equal to the length of the list of active sessions,
  104. // return error with error code session not created.
  105. // 4. Let capabilities be the result of trying to process capabilities with parameters as an argument.
  106. auto capabilities = TRY(Web::WebDriver::process_capabilities(payload));
  107. // 5. If capabilities’s is null, return error with error code session not created.
  108. if (capabilities.is_null())
  109. return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::SessionNotCreated, "Could not match capabilities"sv);
  110. // 6. Let session id be the result of generating a UUID.
  111. // FIXME: Actually create a UUID.
  112. auto session_id = Client::s_next_session_id++;
  113. // 7. Let session be a new session with the session ID of session id.
  114. Web::WebDriver::LadybirdOptions options { capabilities.as_object() };
  115. auto session = make_ref_counted<Session>(session_id, *this, move(options));
  116. if (auto start_result = session->start(m_callbacks); start_result.is_error())
  117. return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::SessionNotCreated, ByteString::formatted("Failed to start session: {}", start_result.error()));
  118. auto& web_content_connection = session->web_content_connection();
  119. // FIXME: 8. Set the current session to session.
  120. // FIXME: 9. Run any WebDriver new session algorithm defined in external specifications,
  121. // with arguments session and capabilities.
  122. // 10. Append session to active sessions.
  123. s_sessions.set(session_id, move(session));
  124. // NOTE: We do step 12 before 11 because step 12 mutates the capabilities we set in step 11.
  125. // 12. Initialize the following from capabilities:
  126. initialize_session_from_capabilities(web_content_connection, capabilities.as_object());
  127. // 11. Let body be a JSON Object initialized with:
  128. JsonObject body;
  129. // "sessionId"
  130. // session id
  131. body.set("sessionId", ByteString::number(session_id));
  132. // "capabilities"
  133. // capabilities
  134. body.set("capabilities", move(capabilities));
  135. // 13. Set the webdriver-active flag to true.
  136. web_content_connection.async_set_is_webdriver_active(true);
  137. // FIXME: 14. Set the current top-level browsing context for session with the top-level browsing context
  138. // of the UA’s current browsing context.
  139. // FIXME: 15. Set the request queue to a new queue.
  140. // 16. Return success with data body.
  141. return JsonValue { move(body) };
  142. }
  143. // 8.2 Delete Session, https://w3c.github.io/webdriver/#dfn-delete-session
  144. // DELETE /session/{session id}
  145. Web::WebDriver::Response Client::delete_session(Web::WebDriver::Parameters parameters, JsonValue)
  146. {
  147. dbgln_if(WEBDRIVER_DEBUG, "Handling DELETE /session/<session_id>");
  148. // 1. If the current session is an active session, try to close the session.
  149. if (auto session = find_session_with_id(parameters[0], AllowInvalidWindowHandle::Yes); !session.is_error())
  150. close_session(session.value()->session_id());
  151. // 2. Return success with data null.
  152. return JsonValue {};
  153. }
  154. // 8.3 Status, https://w3c.github.io/webdriver/#dfn-status
  155. // GET /status
  156. Web::WebDriver::Response Client::get_status(Web::WebDriver::Parameters, JsonValue)
  157. {
  158. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /status");
  159. // 1. Let body be a new JSON Object with the following properties:
  160. // "ready"
  161. // The remote end’s readiness state.
  162. // "message"
  163. // An implementation-defined string explaining the remote end’s readiness state.
  164. // FIXME: Report if we are somehow not ready.
  165. JsonObject body;
  166. body.set("ready", true);
  167. body.set("message", "Ready to start some sessions!");
  168. // 2. Return success with data body.
  169. return JsonValue { body };
  170. }
  171. // 9.1 Get Timeouts, https://w3c.github.io/webdriver/#dfn-get-timeouts
  172. // GET /session/{session id}/timeouts
  173. Web::WebDriver::Response Client::get_timeouts(Web::WebDriver::Parameters parameters, JsonValue)
  174. {
  175. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session id>/timeouts");
  176. auto session = TRY(find_session_with_id(parameters[0]));
  177. return session->web_content_connection().get_timeouts();
  178. }
  179. // 9.2 Set Timeouts, https://w3c.github.io/webdriver/#dfn-set-timeouts
  180. // POST /session/{session id}/timeouts
  181. Web::WebDriver::Response Client::set_timeouts(Web::WebDriver::Parameters parameters, JsonValue payload)
  182. {
  183. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session id>/timeouts");
  184. auto session = TRY(find_session_with_id(parameters[0]));
  185. return session->web_content_connection().set_timeouts(payload);
  186. }
  187. // 10.1 Navigate To, https://w3c.github.io/webdriver/#dfn-navigate-to
  188. // POST /session/{session id}/url
  189. Web::WebDriver::Response Client::navigate_to(Web::WebDriver::Parameters parameters, JsonValue payload)
  190. {
  191. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/url");
  192. auto session = TRY(find_session_with_id(parameters[0]));
  193. return session->web_content_connection().navigate_to(payload);
  194. }
  195. // 10.2 Get Current URL, https://w3c.github.io/webdriver/#dfn-get-current-url
  196. // GET /session/{session id}/url
  197. Web::WebDriver::Response Client::get_current_url(Web::WebDriver::Parameters parameters, JsonValue)
  198. {
  199. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/url");
  200. auto session = TRY(find_session_with_id(parameters[0]));
  201. return session->web_content_connection().get_current_url();
  202. }
  203. // 10.3 Back, https://w3c.github.io/webdriver/#dfn-back
  204. // POST /session/{session id}/back
  205. Web::WebDriver::Response Client::back(Web::WebDriver::Parameters parameters, JsonValue)
  206. {
  207. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/back");
  208. auto session = TRY(find_session_with_id(parameters[0]));
  209. return session->web_content_connection().back();
  210. }
  211. // 10.4 Forward, https://w3c.github.io/webdriver/#dfn-forward
  212. // POST /session/{session id}/forward
  213. Web::WebDriver::Response Client::forward(Web::WebDriver::Parameters parameters, JsonValue)
  214. {
  215. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/forward");
  216. auto session = TRY(find_session_with_id(parameters[0]));
  217. return session->web_content_connection().forward();
  218. }
  219. // 10.5 Refresh, https://w3c.github.io/webdriver/#dfn-refresh
  220. // POST /session/{session id}/refresh
  221. Web::WebDriver::Response Client::refresh(Web::WebDriver::Parameters parameters, JsonValue)
  222. {
  223. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/refresh");
  224. auto session = TRY(find_session_with_id(parameters[0]));
  225. return session->web_content_connection().refresh();
  226. }
  227. // 10.6 Get Title, https://w3c.github.io/webdriver/#dfn-get-title
  228. // GET /session/{session id}/title
  229. Web::WebDriver::Response Client::get_title(Web::WebDriver::Parameters parameters, JsonValue)
  230. {
  231. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/title");
  232. auto session = TRY(find_session_with_id(parameters[0]));
  233. return session->web_content_connection().get_title();
  234. }
  235. // 11.1 Get Window Handle, https://w3c.github.io/webdriver/#get-window-handle
  236. // GET /session/{session id}/window
  237. Web::WebDriver::Response Client::get_window_handle(Web::WebDriver::Parameters parameters, JsonValue)
  238. {
  239. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/window");
  240. auto session = TRY(find_session_with_id(parameters[0]));
  241. // 1. If the current top-level browsing context is no longer open, return error with error code no such window.
  242. TRY(session->web_content_connection().ensure_top_level_browsing_context_is_open());
  243. // 2. Return success with data being the window handle associated with the current top-level browsing context.
  244. return JsonValue { session->current_window_handle() };
  245. }
  246. // 11.2 Close Window, https://w3c.github.io/webdriver/#dfn-close-window
  247. // DELETE /session/{session id}/window
  248. Web::WebDriver::Response Client::close_window(Web::WebDriver::Parameters parameters, JsonValue)
  249. {
  250. dbgln_if(WEBDRIVER_DEBUG, "Handling DELETE /session/<session_id>/window");
  251. auto session = TRY(find_session_with_id(parameters[0]));
  252. return session->close_window();
  253. }
  254. // 11.3 Switch to Window, https://w3c.github.io/webdriver/#dfn-switch-to-window
  255. // POST /session/{session id}/window
  256. Web::WebDriver::Response Client::switch_to_window(Web::WebDriver::Parameters parameters, AK::JsonValue payload)
  257. {
  258. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window");
  259. auto session = TRY(find_session_with_id(parameters[0], AllowInvalidWindowHandle::Yes));
  260. if (!payload.is_object())
  261. return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload is not a JSON object");
  262. // 1. Let handle be the result of getting the property "handle" from the parameters argument.
  263. auto handle = payload.as_object().get("handle"sv);
  264. // 2. If handle is undefined, return error with error code invalid argument.
  265. if (!handle.has_value())
  266. return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "No property called 'handle' present");
  267. return session->switch_to_window(handle->as_string());
  268. }
  269. // 11.4 Get Window Handles, https://w3c.github.io/webdriver/#dfn-get-window-handles
  270. // GET /session/{session id}/window/handles
  271. Web::WebDriver::Response Client::get_window_handles(Web::WebDriver::Parameters parameters, JsonValue)
  272. {
  273. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/window/handles");
  274. auto session = TRY(find_session_with_id(parameters[0], AllowInvalidWindowHandle::Yes));
  275. return session->get_window_handles();
  276. }
  277. // 11.5 New Window, https://w3c.github.io/webdriver/#dfn-new-window
  278. // POST /session/{session id}/window/new
  279. Web::WebDriver::Response Client::new_window(Web::WebDriver::Parameters parameters, JsonValue payload)
  280. {
  281. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/new");
  282. auto session = TRY(find_session_with_id(parameters[0]));
  283. return session->web_content_connection().new_window(payload);
  284. }
  285. // 11.6 Switch To Frame, https://w3c.github.io/webdriver/#dfn-switch-to-frame
  286. // POST /session/{session id}/frame
  287. Web::WebDriver::Response Client::switch_to_frame(Web::WebDriver::Parameters parameters, JsonValue payload)
  288. {
  289. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/frame");
  290. auto session = TRY(find_session_with_id(parameters[0]));
  291. return session->web_content_connection().switch_to_frame(move(payload));
  292. }
  293. // 11.7 Switch To Parent Frame, https://w3c.github.io/webdriver/#dfn-switch-to-parent-frame
  294. // POST /session/{session id}/frame/parent
  295. Web::WebDriver::Response Client::switch_to_parent_frame(Web::WebDriver::Parameters parameters, JsonValue payload)
  296. {
  297. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/frame/parent");
  298. auto session = TRY(find_session_with_id(parameters[0]));
  299. return session->web_content_connection().switch_to_parent_frame(move(payload));
  300. }
  301. // 11.8.1 Get Window Rect, https://w3c.github.io/webdriver/#dfn-get-window-rect
  302. // GET /session/{session id}/window/rect
  303. Web::WebDriver::Response Client::get_window_rect(Web::WebDriver::Parameters parameters, JsonValue)
  304. {
  305. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/window/rect");
  306. auto session = TRY(find_session_with_id(parameters[0]));
  307. return session->web_content_connection().get_window_rect();
  308. }
  309. // 11.8.2 Set Window Rect, https://w3c.github.io/webdriver/#dfn-set-window-rect
  310. // POST /session/{session id}/window/rect
  311. Web::WebDriver::Response Client::set_window_rect(Web::WebDriver::Parameters parameters, JsonValue payload)
  312. {
  313. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/rect");
  314. auto session = TRY(find_session_with_id(parameters[0]));
  315. return session->web_content_connection().set_window_rect(payload);
  316. }
  317. // 11.8.3 Maximize Window, https://w3c.github.io/webdriver/#dfn-maximize-window
  318. // POST /session/{session id}/window/maximize
  319. Web::WebDriver::Response Client::maximize_window(Web::WebDriver::Parameters parameters, JsonValue)
  320. {
  321. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/maximize");
  322. auto session = TRY(find_session_with_id(parameters[0]));
  323. return session->web_content_connection().maximize_window();
  324. }
  325. // 11.8.4 Minimize Window, https://w3c.github.io/webdriver/#minimize-window
  326. // POST /session/{session id}/window/minimize
  327. Web::WebDriver::Response Client::minimize_window(Web::WebDriver::Parameters parameters, JsonValue)
  328. {
  329. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/minimize");
  330. auto session = TRY(find_session_with_id(parameters[0]));
  331. return session->web_content_connection().minimize_window();
  332. }
  333. // 11.8.5 Fullscreen Window, https://w3c.github.io/webdriver/#dfn-fullscreen-window
  334. // POST /session/{session id}/window/fullscreen
  335. Web::WebDriver::Response Client::fullscreen_window(Web::WebDriver::Parameters parameters, JsonValue)
  336. {
  337. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/fullscreen");
  338. auto session = TRY(find_session_with_id(parameters[0]));
  339. return session->web_content_connection().fullscreen_window();
  340. }
  341. // Extension: Consume User Activation, https://html.spec.whatwg.org/multipage/interaction.html#user-activation-user-agent-automation
  342. // POST /session/{session id}/window/consume-user-activation
  343. Web::WebDriver::Response Client::consume_user_activation(Web::WebDriver::Parameters parameters, JsonValue)
  344. {
  345. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/consume-user-activation");
  346. auto session = TRY(find_session_with_id(parameters[0]));
  347. return session->web_content_connection().consume_user_activation();
  348. }
  349. // 12.3.2 Find Element, https://w3c.github.io/webdriver/#dfn-find-element
  350. // POST /session/{session id}/element
  351. Web::WebDriver::Response Client::find_element(Web::WebDriver::Parameters parameters, JsonValue payload)
  352. {
  353. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element");
  354. auto session = TRY(find_session_with_id(parameters[0]));
  355. return session->web_content_connection().find_element(payload);
  356. }
  357. // 12.3.3 Find Elements, https://w3c.github.io/webdriver/#dfn-find-elements
  358. // POST /session/{session id}/elements
  359. Web::WebDriver::Response Client::find_elements(Web::WebDriver::Parameters parameters, JsonValue payload)
  360. {
  361. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/elements");
  362. auto session = TRY(find_session_with_id(parameters[0]));
  363. return session->web_content_connection().find_elements(payload);
  364. }
  365. // 12.3.4 Find Element From Element, https://w3c.github.io/webdriver/#dfn-find-element-from-element
  366. // POST /session/{session id}/element/{element id}/element
  367. Web::WebDriver::Response Client::find_element_from_element(Web::WebDriver::Parameters parameters, JsonValue payload)
  368. {
  369. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/element");
  370. auto session = TRY(find_session_with_id(parameters[0]));
  371. return session->web_content_connection().find_element_from_element(payload, move(parameters[1]));
  372. }
  373. // 12.3.5 Find Elements From Element, https://w3c.github.io/webdriver/#dfn-find-elements-from-element
  374. // POST /session/{session id}/element/{element id}/elements
  375. Web::WebDriver::Response Client::find_elements_from_element(Web::WebDriver::Parameters parameters, JsonValue payload)
  376. {
  377. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/elements");
  378. auto session = TRY(find_session_with_id(parameters[0]));
  379. return session->web_content_connection().find_elements_from_element(payload, move(parameters[1]));
  380. }
  381. // 12.3.6 Find Element From Shadow Root, https://w3c.github.io/webdriver/#find-element-from-shadow-root
  382. // POST /session/{session id}/shadow/{shadow id}/element
  383. Web::WebDriver::Response Client::find_element_from_shadow_root(Web::WebDriver::Parameters parameters, JsonValue payload)
  384. {
  385. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/shadow/<shadow_id>/element");
  386. auto session = TRY(find_session_with_id(parameters[0]));
  387. return session->web_content_connection().find_element_from_shadow_root(payload, move(parameters[1]));
  388. }
  389. // 12.3.7 Find Elements From Shadow Root, https://w3c.github.io/webdriver/#find-elements-from-shadow-root
  390. // POST /session/{session id}/shadow/{shadow id}/elements
  391. Web::WebDriver::Response Client::find_elements_from_shadow_root(Web::WebDriver::Parameters parameters, JsonValue payload)
  392. {
  393. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/shadow/<shadow_id>/elements");
  394. auto session = TRY(find_session_with_id(parameters[0]));
  395. return session->web_content_connection().find_elements_from_shadow_root(payload, move(parameters[1]));
  396. }
  397. // 12.3.8 Get Active Element, https://w3c.github.io/webdriver/#get-active-element
  398. // GET /session/{session id}/element/active
  399. Web::WebDriver::Response Client::get_active_element(Web::WebDriver::Parameters parameters, JsonValue)
  400. {
  401. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/active");
  402. auto session = TRY(find_session_with_id(parameters[0]));
  403. return session->web_content_connection().get_active_element();
  404. }
  405. // 12.3.9 Get Element Shadow Root, https://w3c.github.io/webdriver/#get-element-shadow-root
  406. // GET /session/{session id}/element/{element id}/shadow
  407. Web::WebDriver::Response Client::get_element_shadow_root(Web::WebDriver::Parameters parameters, JsonValue)
  408. {
  409. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/shadow");
  410. auto session = TRY(find_session_with_id(parameters[0]));
  411. return session->web_content_connection().get_element_shadow_root(move(parameters[1]));
  412. }
  413. // 12.4.1 Is Element Selected, https://w3c.github.io/webdriver/#dfn-is-element-selected
  414. // GET /session/{session id}/element/{element id}/selected
  415. Web::WebDriver::Response Client::is_element_selected(Web::WebDriver::Parameters parameters, JsonValue)
  416. {
  417. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/selected");
  418. auto session = TRY(find_session_with_id(parameters[0]));
  419. return session->web_content_connection().is_element_selected(move(parameters[1]));
  420. }
  421. // 12.4.2 Get Element Attribute, https://w3c.github.io/webdriver/#dfn-get-element-attribute
  422. // GET /session/{session id}/element/{element id}/attribute/{name}
  423. Web::WebDriver::Response Client::get_element_attribute(Web::WebDriver::Parameters parameters, JsonValue)
  424. {
  425. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/attribute/<name>");
  426. auto session = TRY(find_session_with_id(parameters[0]));
  427. return session->web_content_connection().get_element_attribute(move(parameters[1]), move(parameters[2]));
  428. }
  429. // 12.4.3 Get Element Property, https://w3c.github.io/webdriver/#dfn-get-element-property
  430. // GET /session/{session id}/element/{element id}/property/{name}
  431. Web::WebDriver::Response Client::get_element_property(Web::WebDriver::Parameters parameters, JsonValue)
  432. {
  433. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/property/<name>");
  434. auto session = TRY(find_session_with_id(parameters[0]));
  435. return session->web_content_connection().get_element_property(move(parameters[1]), move(parameters[2]));
  436. }
  437. // 12.4.4 Get Element CSS Value, https://w3c.github.io/webdriver/#dfn-get-element-css-value
  438. // GET /session/{session id}/element/{element id}/css/{property name}
  439. Web::WebDriver::Response Client::get_element_css_value(Web::WebDriver::Parameters parameters, JsonValue)
  440. {
  441. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/css/<property_name>");
  442. auto session = TRY(find_session_with_id(parameters[0]));
  443. return session->web_content_connection().get_element_css_value(move(parameters[1]), move(parameters[2]));
  444. }
  445. // 12.4.5 Get Element Text, https://w3c.github.io/webdriver/#dfn-get-element-text
  446. // GET /session/{session id}/element/{element id}/text
  447. Web::WebDriver::Response Client::get_element_text(Web::WebDriver::Parameters parameters, JsonValue)
  448. {
  449. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/text");
  450. auto session = TRY(find_session_with_id(parameters[0]));
  451. return session->web_content_connection().get_element_text(move(parameters[1]));
  452. }
  453. // 12.4.6 Get Element Tag Name, https://w3c.github.io/webdriver/#dfn-get-element-tag-name
  454. // GET /session/{session id}/element/{element id}/name
  455. Web::WebDriver::Response Client::get_element_tag_name(Web::WebDriver::Parameters parameters, JsonValue)
  456. {
  457. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/name");
  458. auto session = TRY(find_session_with_id(parameters[0]));
  459. return session->web_content_connection().get_element_tag_name(move(parameters[1]));
  460. }
  461. // 12.4.7 Get Element Rect, https://w3c.github.io/webdriver/#dfn-get-element-rect
  462. // GET /session/{session id}/element/{element id}/rect
  463. Web::WebDriver::Response Client::get_element_rect(Web::WebDriver::Parameters parameters, JsonValue)
  464. {
  465. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/rect");
  466. auto session = TRY(find_session_with_id(parameters[0]));
  467. return session->web_content_connection().get_element_rect(move(parameters[1]));
  468. }
  469. // 12.4.8 Is Element Enabled, https://w3c.github.io/webdriver/#dfn-is-element-enabled
  470. // GET /session/{session id}/element/{element id}/enabled
  471. Web::WebDriver::Response Client::is_element_enabled(Web::WebDriver::Parameters parameters, JsonValue)
  472. {
  473. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/enabled");
  474. auto session = TRY(find_session_with_id(parameters[0]));
  475. return session->web_content_connection().is_element_enabled(move(parameters[1]));
  476. }
  477. // 12.4.9 https://w3c.github.io/webdriver/#dfn-get-computed-role
  478. // GET /session/{session id}/element/{element id}/computedrole
  479. Web::WebDriver::Response Client::get_computed_role(Web::WebDriver::Parameters parameters, AK::JsonValue)
  480. {
  481. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session id>/element/<element id>/computedrole");
  482. auto session = TRY(find_session_with_id(parameters[0]));
  483. return session->web_content_connection().get_computed_role(move(parameters[1]));
  484. }
  485. // 12.4.10 Get Computed Label, https://w3c.github.io/webdriver/#get-computed-label
  486. // GET /session/{session id}/element/{element id}/computedlabel
  487. Web::WebDriver::Response Client::get_computed_label(Web::WebDriver::Parameters parameters, JsonValue)
  488. {
  489. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session id>/element/<element id>/computedlabel");
  490. auto session = TRY(find_session_with_id(parameters[0]));
  491. return session->web_content_connection().get_computed_label(move(parameters[1]));
  492. }
  493. // 12.5.1 Element Click, https://w3c.github.io/webdriver/#element-click
  494. // POST /session/{session id}/element/{element id}/click
  495. Web::WebDriver::Response Client::element_click(Web::WebDriver::Parameters parameters, JsonValue)
  496. {
  497. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/click");
  498. auto session = TRY(find_session_with_id(parameters[0]));
  499. return session->element_click(move(parameters[1]));
  500. }
  501. // 12.5.2 Element Clear, https://w3c.github.io/webdriver/#dfn-element-clear
  502. // POST /session/{session id}/element/{element id}/clear
  503. Web::WebDriver::Response Client::element_clear(Web::WebDriver::Parameters parameters, JsonValue)
  504. {
  505. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/clear");
  506. auto session = TRY(find_session_with_id(parameters[0]));
  507. return session->web_content_connection().element_clear(move(parameters[1]));
  508. }
  509. // 12.5.3 Element Send Keys, https://w3c.github.io/webdriver/#dfn-element-send-keys
  510. // POST /session/{session id}/element/{element id}/value
  511. Web::WebDriver::Response Client::element_send_keys(Web::WebDriver::Parameters parameters, JsonValue payload)
  512. {
  513. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/value");
  514. auto session = TRY(find_session_with_id(parameters[0]));
  515. return session->web_content_connection().element_send_keys(move(parameters[1]), move(payload));
  516. }
  517. // 13.1 Get Page Source, https://w3c.github.io/webdriver/#dfn-get-page-source
  518. // GET /session/{session id}/source
  519. Web::WebDriver::Response Client::get_source(Web::WebDriver::Parameters parameters, JsonValue)
  520. {
  521. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/source");
  522. auto session = TRY(find_session_with_id(parameters[0]));
  523. return session->web_content_connection().get_source();
  524. }
  525. // 13.2.1 Execute Script, https://w3c.github.io/webdriver/#dfn-execute-script
  526. // POST /session/{session id}/execute/sync
  527. Web::WebDriver::Response Client::execute_script(Web::WebDriver::Parameters parameters, JsonValue payload)
  528. {
  529. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/execute/sync");
  530. auto session = TRY(find_session_with_id(parameters[0]));
  531. return session->execute_script(move(payload), Session::ScriptMode::Sync);
  532. }
  533. // 13.2.2 Execute Async Script, https://w3c.github.io/webdriver/#dfn-execute-async-script
  534. // POST /session/{session id}/execute/async
  535. Web::WebDriver::Response Client::execute_async_script(Web::WebDriver::Parameters parameters, JsonValue payload)
  536. {
  537. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/execute/async");
  538. auto session = TRY(find_session_with_id(parameters[0]));
  539. return session->execute_script(move(payload), Session::ScriptMode::Async);
  540. }
  541. // 14.1 Get All Cookies, https://w3c.github.io/webdriver/#dfn-get-all-cookies
  542. // GET /session/{session id}/cookie
  543. Web::WebDriver::Response Client::get_all_cookies(Web::WebDriver::Parameters parameters, JsonValue)
  544. {
  545. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/cookie");
  546. auto session = TRY(find_session_with_id(parameters[0]));
  547. return session->web_content_connection().get_all_cookies();
  548. }
  549. // 14.2 Get Named Cookie, https://w3c.github.io/webdriver/#dfn-get-named-cookie
  550. // GET /session/{session id}/cookie/{name}
  551. Web::WebDriver::Response Client::get_named_cookie(Web::WebDriver::Parameters parameters, JsonValue)
  552. {
  553. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/cookie/<name>");
  554. auto session = TRY(find_session_with_id(parameters[0]));
  555. return session->web_content_connection().get_named_cookie(move(parameters[1]));
  556. }
  557. // 14.3 Add Cookie, https://w3c.github.io/webdriver/#dfn-adding-a-cookie
  558. // POST /session/{session id}/cookie
  559. Web::WebDriver::Response Client::add_cookie(Web::WebDriver::Parameters parameters, JsonValue payload)
  560. {
  561. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/cookie");
  562. auto session = TRY(find_session_with_id(parameters[0]));
  563. return session->web_content_connection().add_cookie(payload);
  564. }
  565. // 14.4 Delete Cookie, https://w3c.github.io/webdriver/#dfn-delete-cookie
  566. // DELETE /session/{session id}/cookie/{name}
  567. Web::WebDriver::Response Client::delete_cookie(Web::WebDriver::Parameters parameters, JsonValue)
  568. {
  569. dbgln_if(WEBDRIVER_DEBUG, "Handling DELETE /session/<session_id>/cookie/<name>");
  570. auto session = TRY(find_session_with_id(parameters[0]));
  571. return session->web_content_connection().delete_cookie(move(parameters[1]));
  572. }
  573. // 14.5 Delete All Cookies, https://w3c.github.io/webdriver/#dfn-delete-all-cookies
  574. // DELETE /session/{session id}/cookie
  575. Web::WebDriver::Response Client::delete_all_cookies(Web::WebDriver::Parameters parameters, JsonValue)
  576. {
  577. dbgln_if(WEBDRIVER_DEBUG, "Handling DELETE /session/<session_id>/cookie");
  578. auto session = TRY(find_session_with_id(parameters[0]));
  579. return session->web_content_connection().delete_all_cookies();
  580. }
  581. // 15.7 Perform Actions, https://w3c.github.io/webdriver/#perform-actions
  582. // POST /session/{session id}/actions
  583. Web::WebDriver::Response Client::perform_actions(Web::WebDriver::Parameters parameters, JsonValue payload)
  584. {
  585. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/actions");
  586. auto session = TRY(find_session_with_id(parameters[0]));
  587. return session->perform_actions(move(payload));
  588. }
  589. // 15.8 Release Actions, https://w3c.github.io/webdriver/#release-actions
  590. // DELETE /session/{session id}/actions
  591. Web::WebDriver::Response Client::release_actions(Web::WebDriver::Parameters parameters, JsonValue)
  592. {
  593. dbgln_if(WEBDRIVER_DEBUG, "Handling DELETE /session/<session_id>/actions");
  594. auto session = TRY(find_session_with_id(parameters[0]));
  595. return session->web_content_connection().release_actions();
  596. }
  597. // 16.1 Dismiss Alert, https://w3c.github.io/webdriver/#dismiss-alert
  598. // POST /session/{session id}/alert/dismiss
  599. Web::WebDriver::Response Client::dismiss_alert(Web::WebDriver::Parameters parameters, JsonValue)
  600. {
  601. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/alert/dismiss");
  602. auto session = TRY(find_session_with_id(parameters[0]));
  603. return session->web_content_connection().dismiss_alert();
  604. }
  605. // 16.2 Accept Alert, https://w3c.github.io/webdriver/#accept-alert
  606. // POST /session/{session id}/alert/accept
  607. Web::WebDriver::Response Client::accept_alert(Web::WebDriver::Parameters parameters, JsonValue)
  608. {
  609. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/alert/accept");
  610. auto session = TRY(find_session_with_id(parameters[0]));
  611. return session->web_content_connection().accept_alert();
  612. }
  613. // 16.3 Get Alert Text, https://w3c.github.io/webdriver/#get-alert-text
  614. // GET /session/{session id}/alert/text
  615. Web::WebDriver::Response Client::get_alert_text(Web::WebDriver::Parameters parameters, JsonValue)
  616. {
  617. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/alert/text");
  618. auto session = TRY(find_session_with_id(parameters[0]));
  619. return session->web_content_connection().get_alert_text();
  620. }
  621. // 16.4 Send Alert Text, https://w3c.github.io/webdriver/#send-alert-text
  622. // POST /session/{session id}/alert/text
  623. Web::WebDriver::Response Client::send_alert_text(Web::WebDriver::Parameters parameters, JsonValue payload)
  624. {
  625. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/alert/text");
  626. auto session = TRY(find_session_with_id(parameters[0]));
  627. return session->web_content_connection().send_alert_text(payload);
  628. }
  629. // 17.1 Take Screenshot, https://w3c.github.io/webdriver/#take-screenshot
  630. // GET /session/{session id}/screenshot
  631. Web::WebDriver::Response Client::take_screenshot(Web::WebDriver::Parameters parameters, JsonValue)
  632. {
  633. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/screenshot");
  634. auto session = TRY(find_session_with_id(parameters[0]));
  635. return session->web_content_connection().take_screenshot();
  636. }
  637. // 17.2 Take Element Screenshot, https://w3c.github.io/webdriver/#dfn-take-element-screenshot
  638. // GET /session/{session id}/element/{element id}/screenshot
  639. Web::WebDriver::Response Client::take_element_screenshot(Web::WebDriver::Parameters parameters, JsonValue)
  640. {
  641. dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/screenshot");
  642. auto session = TRY(find_session_with_id(parameters[0]));
  643. return session->web_content_connection().take_element_screenshot(move(parameters[1]));
  644. }
  645. // 18.1 Print Page, https://w3c.github.io/webdriver/#dfn-print-page
  646. // POST /session/{session id}/print
  647. Web::WebDriver::Response Client::print_page(Web::WebDriver::Parameters parameters, JsonValue payload)
  648. {
  649. dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session id>/print");
  650. auto session = TRY(find_session_with_id(parameters[0]));
  651. return session->web_content_connection().print_page(move(payload));
  652. }
  653. }