1#![crate_name = "webdriver_server"]
6#![crate_type = "rlib"]
7#![deny(unsafe_code)]
8
9mod actions;
10mod capabilities;
11mod script_argument_extraction;
12mod server;
13mod session;
14mod timeout;
15mod user_prompt;
16
17use std::borrow::ToOwned;
18use std::cell::LazyCell;
19use std::collections::{BTreeMap, HashMap};
20use std::io::Cursor;
21use std::net::{SocketAddr, SocketAddrV4};
22use std::thread::sleep;
23use std::time::{Duration, Instant};
24use std::{env, fmt, process, thread};
25
26use base64::Engine;
27use capabilities::ServoCapabilities;
28use cookie::{CookieBuilder, Expiration, SameSite};
29use crossbeam_channel::{Receiver, RecvTimeoutError, Sender, after, select, unbounded};
30use embedder_traits::{
31 CustomHandlersAutomationMode, EventLoopWaker, ImeEvent, InputEvent, JSValue,
32 JavaScriptEvaluationError, JavaScriptEvaluationResultSerializationError, NewWindowTypeHint,
33 WebDriverCommandMsg, WebDriverFrameId, WebDriverJSResult, WebDriverLoadStatus,
34 WebDriverScriptCommand,
35};
36use euclid::{Point2D, Rect, Size2D};
37use http::method::Method;
38use image::{DynamicImage, ImageFormat};
39use keyboard_types::webdriver::{Event as DispatchStringEvent, KeyInputState, send_keys};
40use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, NamedKey};
41use log::{debug, error, info};
42use serde::de::{Deserializer, MapAccess, Visitor};
43use serde::ser::Serializer;
44use serde::{Deserialize, Serialize};
45use serde_json::{Value, json};
46use server::{Session, SessionTeardownKind, WebDriverHandler};
47use servo_base::generic_channel::{self, GenericReceiver, GenericSender, RoutedReceiver};
48use servo_base::id::{BrowsingContextId, WebViewId};
49use servo_config::prefs::{self, PrefValue, Preferences};
50use servo_geometry::DeviceIndependentIntRect;
51use servo_url::ServoUrl;
52use style_traits::CSSPixel;
53use time::OffsetDateTime;
54use uuid::Uuid;
55use webdriver::actions::{
56 ActionSequence, ActionsType, KeyAction, KeyActionItem, KeyDownAction, KeyUpAction,
57 PointerAction, PointerActionItem, PointerActionParameters, PointerDownAction,
58 PointerMoveAction, PointerOrigin, PointerType, PointerUpAction,
59};
60use webdriver::capabilities::CapabilitiesMatching;
61use webdriver::command::{
62 ActionsParameters, AddCookieParameters, GetParameters, JavascriptCommandParameters,
63 LocatorParameters, NewSessionParameters, NewWindowParameters, SendKeysParameters,
64 SwitchToFrameParameters, SwitchToWindowParameters, TimeoutsParameters, WebDriverCommand,
65 WebDriverExtensionCommand, WebDriverMessage, WindowRectParameters,
66};
67use webdriver::common::{
68 Cookie, Date, LocatorStrategy, Parameters, ShadowRoot, WebElement, WebFrame, WebWindow,
69};
70use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
71use webdriver::httpapi::WebDriverExtensionRoute;
72use webdriver::response::{
73 CloseWindowResponse, CookieResponse, CookiesResponse, ElementRectResponse, NewSessionResponse,
74 NewWindowResponse, TimeoutsResponse, ValueResponse, WebDriverResponse, WindowRectResponse,
75};
76
77use crate::actions::{ELEMENT_CLICK_BUTTON, InputSourceState, PendingActions, PointerInputState};
78use crate::session::{PageLoadStrategy, WebDriverSession};
79use crate::timeout::{DEFAULT_IMPLICIT_WAIT, DEFAULT_PAGE_LOAD_TIMEOUT, SCREENSHOT_TIMEOUT};
80
81pub(crate) static MAXIMUM_SAFE_INTEGER: u64 = 9_007_199_254_740_991;
84
85fn extension_routes() -> Vec<(Method, &'static str, ServoExtensionRoute)> {
86 vec![
87 (
88 Method::GET,
89 "/session/{sessionId}/servo/prefs/get",
90 ServoExtensionRoute::GetPrefs,
91 ),
92 (
93 Method::POST,
94 "/session/{sessionId}/servo/prefs/set",
95 ServoExtensionRoute::SetPrefs,
96 ),
97 (
98 Method::POST,
99 "/session/{sessionId}/servo/prefs/reset",
100 ServoExtensionRoute::ResetPrefs,
101 ),
102 (
103 Method::DELETE,
104 "/session/{sessionId}/servo/shutdown",
105 ServoExtensionRoute::Shutdown,
106 ),
107 (
109 Method::POST,
110 "/session/{sessionId}/custom-handlers/set-mode",
111 ServoExtensionRoute::CustomHandlersSetMode,
112 ),
113 (
114 Method::POST,
115 "/session/{sessionId}/servo/cookies/reset",
116 ServoExtensionRoute::ResetAllCookies,
117 ),
118 ]
119}
120
121fn cookie_msg_to_cookie(cookie: cookie::Cookie) -> Cookie {
122 Cookie {
123 name: cookie.name().to_owned(),
124 value: cookie.value().to_owned(),
125 path: cookie.path().map(|s| s.to_owned()),
126 domain: cookie.domain().map(|s| s.to_owned()),
127 expiry: cookie.expires().and_then(|expiration| match expiration {
128 Expiration::DateTime(date_time) => Some(Date(date_time.unix_timestamp() as u64)),
129 Expiration::Session => None,
130 }),
131 secure: cookie.secure().unwrap_or(false),
132 http_only: cookie.http_only().unwrap_or(false),
133 same_site: cookie.same_site().map(|s| s.to_string()),
134 }
135}
136
137pub fn start_server(
138 port: u16,
139 embedder_sender: Sender<WebDriverCommandMsg>,
140 event_loop_waker: Box<dyn EventLoopWaker>,
141 default_preferences: Preferences,
142) {
143 let handler = Handler::new(embedder_sender, event_loop_waker, default_preferences);
144
145 thread::Builder::new()
146 .name("WebDriverHttpServer".to_owned())
147 .spawn(move || {
148 let address = SocketAddrV4::new("0.0.0.0".parse().unwrap(), port);
149 match server::start(
150 SocketAddr::V4(address),
151 vec![],
152 vec![],
153 handler,
154 extension_routes(),
155 ) {
156 Ok(listening) => info!("WebDriver server listening on {}", listening.socket),
157 Err(e) => panic!("Unable to start WebDriver HTTP server {e:?}"),
158 }
159 })
160 .expect("Thread spawning failed");
161}
162
163struct Handler {
164 load_status_receiver: RoutedReceiver<WebDriverLoadStatus>,
168 load_status_sender: GenericSender<WebDriverLoadStatus>,
172
173 session: Option<WebDriverSession>,
174
175 embedder_sender: Sender<WebDriverCommandMsg>,
179
180 event_loop_waker: Box<dyn EventLoopWaker>,
182
183 pending_input_event_receivers: Vec<Receiver<()>>,
188
189 pending_actions: Vec<PendingActions>,
192
193 default_preferences: Preferences,
195}
196
197#[derive(Clone, Copy, Debug, PartialEq)]
198enum ServoExtensionRoute {
199 GetPrefs,
200 SetPrefs,
201 ResetPrefs,
202 Shutdown,
208 CustomHandlersSetMode,
209 ResetAllCookies,
210}
211
212impl WebDriverExtensionRoute for ServoExtensionRoute {
213 type Command = ServoExtensionCommand;
214
215 fn command(
216 &self,
217 _parameters: &Parameters,
218 body_data: &Value,
219 ) -> WebDriverResult<WebDriverCommand<ServoExtensionCommand>> {
220 let command = match *self {
221 ServoExtensionRoute::GetPrefs => {
222 let parameters: GetPrefsParameters = serde_json::from_value(body_data.clone())?;
223 ServoExtensionCommand::GetPrefs(parameters)
224 },
225 ServoExtensionRoute::SetPrefs => {
226 let parameters: SetPrefsParameters = serde_json::from_value(body_data.clone())?;
227 ServoExtensionCommand::SetPrefs(parameters)
228 },
229 ServoExtensionRoute::ResetPrefs => {
230 let parameters: GetPrefsParameters = serde_json::from_value(body_data.clone())?;
231 ServoExtensionCommand::ResetPrefs(parameters)
232 },
233 ServoExtensionRoute::CustomHandlersSetMode => {
234 let parameters: CustomHandlersSetModeParameters =
235 serde_json::from_value(body_data.clone())?;
236 ServoExtensionCommand::CustomHandlersSetMode(parameters)
237 },
238 ServoExtensionRoute::Shutdown => ServoExtensionCommand::Shutdown,
239 ServoExtensionRoute::ResetAllCookies => ServoExtensionCommand::ResetAllCookies,
240 };
241 Ok(WebDriverCommand::Extension(command))
242 }
243}
244
245#[derive(Clone, Debug)]
246enum ServoExtensionCommand {
247 GetPrefs(GetPrefsParameters),
248 SetPrefs(SetPrefsParameters),
249 ResetPrefs(GetPrefsParameters),
250 CustomHandlersSetMode(CustomHandlersSetModeParameters),
251 Shutdown,
252 ResetAllCookies,
253}
254
255impl WebDriverExtensionCommand for ServoExtensionCommand {
256 fn parameters_json(&self) -> Option<Value> {
257 match *self {
258 ServoExtensionCommand::GetPrefs(ref x) => serde_json::to_value(x).ok(),
259 ServoExtensionCommand::SetPrefs(ref x) => serde_json::to_value(x).ok(),
260 ServoExtensionCommand::ResetPrefs(ref x) => serde_json::to_value(x).ok(),
261 ServoExtensionCommand::CustomHandlersSetMode(ref x) => serde_json::to_value(x).ok(),
262 ServoExtensionCommand::Shutdown | ServoExtensionCommand::ResetAllCookies => None,
263 }
264 }
265}
266
267#[derive(Clone)]
268struct SendableJSValue(JSValue);
269
270impl Serialize for SendableJSValue {
271 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
272 where
273 S: Serializer,
274 {
275 match self.0 {
276 JSValue::Undefined | JSValue::Null => serializer.serialize_unit(),
277 JSValue::Boolean(x) => serializer.serialize_bool(x),
278 JSValue::Number(x) => {
279 if x.fract() == 0.0 {
280 serializer.serialize_i64(x as i64)
281 } else {
282 serializer.serialize_f64(x)
283 }
284 },
285 JSValue::String(ref x) => serializer.serialize_str(x),
286 JSValue::Element(ref x) => WebElement(x.clone()).serialize(serializer),
287 JSValue::ShadowRoot(ref x) => ShadowRoot(x.clone()).serialize(serializer),
288 JSValue::Frame(ref x) => WebFrame(x.clone()).serialize(serializer),
289 JSValue::Window(ref x) => WebWindow(x.clone()).serialize(serializer),
290 JSValue::Array(ref x) => x
291 .iter()
292 .map(|element| SendableJSValue(element.clone()))
293 .collect::<Vec<SendableJSValue>>()
294 .serialize(serializer),
295 JSValue::Object(ref x) => x
296 .iter()
297 .map(|(k, v)| (k.clone(), SendableJSValue(v.clone())))
298 .collect::<HashMap<String, SendableJSValue>>()
299 .serialize(serializer),
300 }
301 }
302}
303
304#[derive(Clone, Debug, PartialEq)]
305struct WebDriverPrefValue(PrefValue);
306
307impl Serialize for WebDriverPrefValue {
308 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
309 where
310 S: Serializer,
311 {
312 match self.0 {
313 PrefValue::Bool(b) => serializer.serialize_bool(b),
314 PrefValue::Str(ref s) => serializer.serialize_str(s),
315 PrefValue::Float(f) => serializer.serialize_f64(f),
316 PrefValue::Int(i) => serializer.serialize_i64(i),
317 PrefValue::Array(ref v) => v
318 .iter()
319 .map(|value| WebDriverPrefValue(value.clone()))
320 .collect::<Vec<WebDriverPrefValue>>()
321 .serialize(serializer),
322 PrefValue::UInt(u) => serializer.serialize_u64(u),
323 }
324 }
325}
326
327impl<'de> Deserialize<'de> for WebDriverPrefValue {
328 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
329 where
330 D: Deserializer<'de>,
331 {
332 struct Visitor;
333
334 impl ::serde::de::Visitor<'_> for Visitor {
335 type Value = WebDriverPrefValue;
336
337 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
338 formatter.write_str("preference value")
339 }
340
341 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
342 where
343 E: ::serde::de::Error,
344 {
345 Ok(WebDriverPrefValue(PrefValue::Float(value)))
346 }
347
348 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
349 where
350 E: ::serde::de::Error,
351 {
352 Ok(WebDriverPrefValue(PrefValue::Int(value)))
353 }
354
355 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
356 where
357 E: ::serde::de::Error,
358 {
359 Ok(WebDriverPrefValue(PrefValue::Int(value as i64)))
360 }
361
362 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
363 where
364 E: ::serde::de::Error,
365 {
366 Ok(WebDriverPrefValue(PrefValue::Str(String::from(value))))
367 }
368
369 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
370 where
371 E: ::serde::de::Error,
372 {
373 Ok(WebDriverPrefValue(PrefValue::Bool(value)))
374 }
375 }
376
377 deserializer.deserialize_any(Visitor)
378 }
379}
380
381#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
382struct GetPrefsParameters {
383 prefs: Vec<String>,
384}
385
386#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
387struct SetPrefsParameters {
388 #[serde(deserialize_with = "map_to_vec")]
389 prefs: Vec<(String, WebDriverPrefValue)>,
390}
391
392#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
393struct CustomHandlersSetModeParameters {
394 mode: String,
395}
396
397fn map_to_vec<'de, D>(de: D) -> Result<Vec<(String, WebDriverPrefValue)>, D::Error>
398where
399 D: Deserializer<'de>,
400{
401 de.deserialize_map(TupleVecMapVisitor)
402}
403
404struct TupleVecMapVisitor;
405
406impl<'de> Visitor<'de> for TupleVecMapVisitor {
407 type Value = Vec<(String, WebDriverPrefValue)>;
408
409 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
410 formatter.write_str("a map")
411 }
412
413 #[inline]
414 fn visit_unit<E>(self) -> Result<Self::Value, E> {
415 Ok(Vec::new())
416 }
417
418 #[inline]
419 fn visit_map<T>(self, mut access: T) -> Result<Self::Value, T::Error>
420 where
421 T: MapAccess<'de>,
422 {
423 let mut values = Vec::new();
424
425 while let Some((key, value)) = access.next_entry()? {
426 values.push((key, value));
427 }
428
429 Ok(values)
430 }
431}
432
433enum VerifyBrowsingContextIsOpen {
434 Yes,
435 No,
436}
437
438enum ImplicitWait {
439 Return,
440 #[expect(dead_code, reason = "This will be used in the next patch")]
441 Continue,
442}
443
444impl From<ImplicitWait> for bool {
445 fn from(implicit_wait: ImplicitWait) -> Self {
446 match implicit_wait {
447 ImplicitWait::Return => true,
448 ImplicitWait::Continue => false,
449 }
450 }
451}
452
453impl Handler {
454 fn new(
455 embedder_sender: Sender<WebDriverCommandMsg>,
456 event_loop_waker: Box<dyn EventLoopWaker>,
457 default_preferences: Preferences,
458 ) -> Handler {
459 let (load_status_sender, receiver) = generic_channel::channel().unwrap();
465 let load_status_receiver = receiver.route_preserving_errors();
466
467 Handler {
468 load_status_sender,
469 load_status_receiver,
470 session: None,
471 embedder_sender,
472 event_loop_waker,
473 default_preferences,
474 pending_input_event_receivers: Default::default(),
475 pending_actions: Default::default(),
476 }
477 }
478
479 fn browsing_context_id(&self) -> WebDriverResult<BrowsingContextId> {
480 self.session()?
481 .current_browsing_context_id()
482 .ok_or_else(|| {
483 WebDriverError::new(ErrorStatus::UnknownError, "No browsing context available")
484 })
485 }
486
487 fn webview_id(&self) -> WebDriverResult<WebViewId> {
488 self.session()?
489 .current_webview_id()
490 .ok_or_else(|| WebDriverError::new(ErrorStatus::UnknownError, "No webview available"))
491 }
492
493 fn send_input_event_to_embedder(&self, input_event: InputEvent) {
495 let _ = self.send_message_to_embedder(WebDriverCommandMsg::InputEvent(
496 self.verified_webview_id(),
497 input_event,
498 None,
499 ));
500 }
501
502 fn send_blocking_input_event_to_embedder(&mut self, input_event: InputEvent) {
503 let (result_sender, result_receiver) = unbounded();
504 if self
505 .send_message_to_embedder(WebDriverCommandMsg::InputEvent(
506 self.verified_webview_id(),
507 input_event,
508 Some(result_sender),
509 ))
510 .is_ok()
511 {
512 self.pending_input_event_receivers.push(result_receiver);
513 }
514 }
515
516 fn send_message_to_embedder(&self, msg: WebDriverCommandMsg) -> WebDriverResult<()> {
517 self.embedder_sender.send(msg).map_err(|_| {
518 WebDriverError::new(
519 ErrorStatus::UnknownError,
520 "Failed to send message to embedder",
521 )
522 })?;
523 self.event_loop_waker.wake();
524 Ok(())
525 }
526
527 fn add_load_status_sender(&self) -> WebDriverResult<()> {
528 self.send_message_to_embedder(WebDriverCommandMsg::ScriptCommand(
529 self.browsing_context_id()?,
530 WebDriverScriptCommand::AddLoadStatusSender(
531 self.webview_id()?,
532 self.load_status_sender.clone(),
533 ),
534 ))
535 }
536
537 fn clear_load_status_sender(&self) -> WebDriverResult<()> {
538 self.send_message_to_embedder(WebDriverCommandMsg::ScriptCommand(
539 self.browsing_context_id()?,
540 WebDriverScriptCommand::RemoveLoadStatusSender(self.webview_id()?),
541 ))
542 }
543
544 fn verified_webview_id(&self) -> WebViewId {
546 self.session().unwrap().current_webview_id().unwrap()
547 }
548
549 fn focused_webview_id(&self) -> WebDriverResult<Option<WebViewId>> {
550 let (sender, receiver) = generic_channel::oneshot().unwrap();
551 self.send_message_to_embedder(WebDriverCommandMsg::GetFocusedWebView(sender))?;
552 wait_for_oneshot_response(receiver)
554 }
555
556 fn session(&self) -> WebDriverResult<&WebDriverSession> {
557 match self.session {
558 Some(ref x) => Ok(x),
559 None => Err(WebDriverError::new(
561 ErrorStatus::InvalidSessionId,
562 "Session not created",
563 )),
564 }
565 }
566
567 fn session_mut(&mut self) -> WebDriverResult<&mut WebDriverSession> {
568 match self.session {
569 Some(ref mut x) => Ok(x),
570 None => Err(WebDriverError::new(
572 ErrorStatus::InvalidSessionId,
573 "Session not created",
574 )),
575 }
576 }
577
578 fn handle_new_session(
580 &mut self,
581 parameters: &NewSessionParameters,
582 ) -> WebDriverResult<WebDriverResponse> {
583 if let Ok(value) = env::var("DELAY_AFTER_ACCEPT") {
584 let seconds = value.parse::<u64>().unwrap_or_default();
585 println!("Waiting for {} seconds...", seconds);
586 println!("lldb -p {}", process::id());
587 thread::sleep(Duration::from_secs(seconds));
588 }
589
590 if self.session.is_some() {
593 return Err(WebDriverError::new(
594 ErrorStatus::SessionNotCreated,
595 "Session already created",
596 ));
597 }
598
599 let mut servo_capabilities = ServoCapabilities::new();
604 let processed_capabilities = parameters.match_browser(&mut servo_capabilities)?;
605
606 let mut capabilities = match processed_capabilities {
608 Some(capabilities) => capabilities,
609 None => {
610 return Err(WebDriverError::new(
611 ErrorStatus::SessionNotCreated,
612 "Session not created due to invalid capabilities",
613 ));
614 },
615 };
616
617 let session_id = self.create_session(&mut capabilities, &servo_capabilities)?;
619
620 let response = NewSessionResponse::new(session_id.to_string(), Value::Object(capabilities));
622
623 match self.focused_webview_id()? {
625 Some(webview_id) => {
626 self.session_mut()?.set_webview_id(webview_id);
627 self.wait_until_browsing_context_is_open(BrowsingContextId::from(webview_id))?;
628 self.session_mut()?
629 .set_browsing_context_id(BrowsingContextId::from(webview_id));
630 },
631 None => {
632 let (sender, receiver) = generic_channel::oneshot().unwrap();
635
636 self.send_message_to_embedder(WebDriverCommandMsg::NewWindow(
637 NewWindowTypeHint::Auto,
638 sender,
639 Some(self.load_status_sender.clone()),
640 ))?;
641 let webview_id = receiver
642 .recv()
643 .expect("IPC failure when creating new webview for new session");
644 self.focus_webview(webview_id)?;
645 self.session_mut()?.set_webview_id(webview_id);
646 self.wait_until_browsing_context_is_open(BrowsingContextId::from(webview_id))?;
647 self.session_mut()?
648 .set_browsing_context_id(BrowsingContextId::from(webview_id));
649 let _ = self.wait_document_ready(Some(DEFAULT_PAGE_LOAD_TIMEOUT));
650 },
651 };
652
653 Ok(WebDriverResponse::NewSession(response))
658 }
659
660 fn handle_delete_session(&mut self) -> WebDriverResult<WebDriverResponse> {
662 self.session = None;
664
665 Ok(WebDriverResponse::DeleteSession)
667 }
668
669 fn handle_status(&self) -> WebDriverResult<WebDriverResponse> {
671 Ok(WebDriverResponse::Generic(ValueResponse(
672 if self.session.is_none() {
673 json!({ "ready": true, "message": "Ready for a new session" })
674 } else {
675 json!({ "ready": false, "message": "Not ready for a new session" })
676 },
677 )))
678 }
679
680 fn browsing_context_script_command(
684 &self,
685 cmd_msg: WebDriverScriptCommand,
686 verify: VerifyBrowsingContextIsOpen,
687 ) -> WebDriverResult<()> {
688 let browsing_context_id = self.browsing_context_id()?;
689 if let VerifyBrowsingContextIsOpen::Yes = verify {
690 self.verify_browsing_context_is_open(browsing_context_id)?;
691 }
692 self.send_message_to_embedder(WebDriverCommandMsg::ScriptCommand(
693 browsing_context_id,
694 cmd_msg,
695 ))?;
696 Ok(())
697 }
698
699 fn top_level_script_command(
703 &self,
704 cmd_msg: WebDriverScriptCommand,
705 verify: VerifyBrowsingContextIsOpen,
706 ) -> WebDriverResult<()> {
707 let webview_id = self.webview_id()?;
708 if let VerifyBrowsingContextIsOpen::Yes = verify {
709 self.verify_top_level_browsing_context_is_open(webview_id)?;
710 }
711 let browsing_context_id = BrowsingContextId::from(webview_id);
712 self.send_message_to_embedder(WebDriverCommandMsg::ScriptCommand(
713 browsing_context_id,
714 cmd_msg,
715 ))?;
716 Ok(())
717 }
718
719 fn handle_get(&mut self, parameters: &GetParameters) -> WebDriverResult<WebDriverResponse> {
721 let webview_id = self.webview_id()?;
722 self.verify_top_level_browsing_context_is_open(webview_id)?;
725 let url = ServoUrl::parse(¶meters.url)
728 .map(|url| url.into_url())
729 .map_err(|_| WebDriverError::new(ErrorStatus::InvalidArgument, "Invalid URL"))?;
730
731 self.handle_any_user_prompts(webview_id)?;
733
734 let cmd_msg =
735 WebDriverCommandMsg::LoadUrl(webview_id, url, self.load_status_sender.clone());
736 self.send_message_to_embedder(cmd_msg)?;
737
738 self.wait_for_navigation_complete()?;
740
741 self.session_mut()?
743 .set_browsing_context_id(BrowsingContextId::from(webview_id));
744
745 Ok(WebDriverResponse::Void)
746 }
747
748 fn wait_document_ready(&self, timeout: Option<u64>) -> WebDriverResult<WebDriverResponse> {
749 let timeout_channel = match timeout {
750 Some(timeout) => after(Duration::from_millis(timeout)),
751 None => crossbeam_channel::never(),
752 };
753
754 select! {
755 recv(self.load_status_receiver) -> res => {
756 match res {
757 Ok(Ok(WebDriverLoadStatus::Blocked)) => {
759 Ok(WebDriverResponse::Void)
766 },
767 Ok(Ok(WebDriverLoadStatus::Complete)) |
768 Ok(Ok(WebDriverLoadStatus::NavigationStop)) =>
769 Ok(WebDriverResponse::Void)
770 ,
771 _ => Err(WebDriverError::new(
772 ErrorStatus::UnknownError,
773 "Unexpected load status received while waiting for document ready state",
774 )),
775 }
776 },
777 recv(timeout_channel) -> _ => Err(
778 WebDriverError::new(ErrorStatus::Timeout, "Load timed out")
779 ),
780 }
781 }
782
783 fn wait_for_navigation_complete(&self) -> WebDriverResult<WebDriverResponse> {
785 debug!("waiting for load");
786
787 let session = self.session()?;
788
789 if session.page_loading_strategy() == PageLoadStrategy::None {
792 return Ok(WebDriverResponse::Void);
793 }
794
795 if self
798 .verify_browsing_context_is_open(self.browsing_context_id()?)
799 .is_err()
800 {
801 return Ok(WebDriverResponse::Void);
802 }
803
804 let timeout = session.session_timeouts().page_load;
806
807 let result = self.wait_document_ready(timeout);
810 debug!("finished waiting for load with {:?}", result);
811 result
812 }
813
814 fn wait_for_navigation(&self) -> WebDriverResult<WebDriverResponse> {
816 let navigation_status = match self.load_status_receiver.try_recv() {
817 Ok(Ok(status)) => status,
818 Err(crossbeam_channel::TryRecvError::Empty) => {
820 return Ok(WebDriverResponse::Void);
821 },
822 Err(crossbeam_channel::TryRecvError::Disconnected) => {
823 return Err(WebDriverError::new(
824 ErrorStatus::UnknownError,
825 "Load status channel disconnected",
826 ));
827 },
828 Ok(Err(ipc_error)) => {
829 return Err(WebDriverError::new(
830 ErrorStatus::UnknownError,
831 format!("Load status channel ipc error: {ipc_error}"),
832 ));
833 },
834 };
835
836 match navigation_status {
837 WebDriverLoadStatus::NavigationStart => self.wait_for_navigation_complete(),
838 WebDriverLoadStatus::Timeout => Err(WebDriverError::new(
840 ErrorStatus::Timeout,
841 "Navigation timed out",
842 )),
843 WebDriverLoadStatus::Blocked => Ok(WebDriverResponse::Void),
846 WebDriverLoadStatus::NavigationStop | WebDriverLoadStatus::Complete => {
847 unreachable!("Unexpected load status received")
848 },
849 }
850 }
851
852 fn handle_current_url(&self) -> WebDriverResult<WebDriverResponse> {
854 let webview_id = self.webview_id()?;
855
856 self.verify_top_level_browsing_context_is_open(webview_id)?;
859
860 self.handle_any_user_prompts(webview_id)?;
862
863 let (sender, receiver) = generic_channel::channel().unwrap();
864 self.top_level_script_command(
865 WebDriverScriptCommand::GetUrl(sender),
866 VerifyBrowsingContextIsOpen::No,
867 )?;
868
869 let url = wait_for_ipc_response(receiver)?;
870
871 Ok(WebDriverResponse::Generic(ValueResponse(
872 serde_json::to_value(url)?,
873 )))
874 }
875
876 fn handle_window_rect(
878 &self,
879 verify: VerifyBrowsingContextIsOpen,
880 ) -> WebDriverResult<WebDriverResponse> {
881 let (sender, receiver) = generic_channel::oneshot().unwrap();
882 let webview_id = self.webview_id()?;
883 if let VerifyBrowsingContextIsOpen::Yes = verify {
886 self.verify_top_level_browsing_context_is_open(webview_id)?;
887 }
888
889 self.handle_any_user_prompts(webview_id)?;
891
892 self.send_message_to_embedder(WebDriverCommandMsg::GetWindowRect(webview_id, sender))?;
893
894 let window_rect = wait_for_oneshot_response(receiver)?;
895 let window_size_response = WindowRectResponse {
896 x: window_rect.min.x,
897 y: window_rect.min.y,
898 width: window_rect.width(),
899 height: window_rect.height(),
900 };
901 Ok(WebDriverResponse::WindowRect(window_size_response))
902 }
903
904 fn handle_set_window_rect(
906 &self,
907 params: &WindowRectParameters,
908 ) -> WebDriverResult<WebDriverResponse> {
909 let webview_id = self.webview_id()?;
917 self.verify_top_level_browsing_context_is_open(webview_id)?;
920
921 self.handle_any_user_prompts(webview_id)?;
923
924 let current = LazyCell::new(|| {
928 let WebDriverResponse::WindowRect(current) = self
929 .handle_window_rect(VerifyBrowsingContextIsOpen::No)
930 .unwrap()
931 else {
932 unreachable!("handle_window_size() must return WindowRect");
933 };
934 current
935 });
936
937 let (x, y, width, height) = (
938 params.x.unwrap_or_else(|| current.x),
939 params.y.unwrap_or_else(|| current.y),
940 params.width.unwrap_or_else(|| current.width),
941 params.height.unwrap_or_else(|| current.height),
942 );
943 let (sender, receiver) = generic_channel::oneshot().unwrap();
944 self.send_message_to_embedder(WebDriverCommandMsg::SetWindowRect(
950 webview_id,
951 DeviceIndependentIntRect::from_origin_and_size(
952 Point2D::new(x, y),
953 Size2D::new(width, height),
954 ),
955 sender,
956 ))?;
957
958 let window_rect = wait_for_oneshot_response(receiver)?;
959 debug!("Result window_rect: {window_rect:?}");
960 let window_size_response = WindowRectResponse {
961 x: window_rect.min.x,
962 y: window_rect.min.y,
963 width: window_rect.width(),
964 height: window_rect.height(),
965 };
966 Ok(WebDriverResponse::WindowRect(window_size_response))
967 }
968
969 fn handle_maximize_window(&mut self) -> WebDriverResult<WebDriverResponse> {
971 let webview_id = self.webview_id()?;
975 self.verify_top_level_browsing_context_is_open(webview_id)?;
978
979 self.handle_any_user_prompts(self.webview_id()?)?;
981
982 let (sender, receiver) = generic_channel::oneshot().unwrap();
988 self.send_message_to_embedder(WebDriverCommandMsg::MaximizeWebView(webview_id, sender))?;
989
990 let window_rect = wait_for_oneshot_response(receiver)?;
991 debug!("Result window_rect: {window_rect:?}");
992 let window_size_response = WindowRectResponse {
993 x: window_rect.min.x,
994 y: window_rect.min.y,
995 width: window_rect.width(),
996 height: window_rect.height(),
997 };
998 Ok(WebDriverResponse::WindowRect(window_size_response))
999 }
1000
1001 fn handle_is_enabled(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
1002 let browsing_context = self.browsing_context_id()?;
1005 self.verify_browsing_context_is_open(browsing_context)?;
1006
1007 let webview_id = self.webview_id()?;
1009 self.handle_any_user_prompts(webview_id)?;
1010
1011 let (sender, receiver) = generic_channel::channel().unwrap();
1012 self.browsing_context_script_command(
1013 WebDriverScriptCommand::IsEnabled(element.to_string(), sender),
1014 VerifyBrowsingContextIsOpen::No,
1015 )?;
1016
1017 Ok(WebDriverResponse::Generic(ValueResponse(
1018 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1019 )))
1020 }
1021
1022 fn handle_is_selected(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
1023 let browsing_context = self.browsing_context_id()?;
1026 self.verify_browsing_context_is_open(browsing_context)?;
1027
1028 let webview_id = self.webview_id()?;
1030 self.handle_any_user_prompts(webview_id)?;
1031
1032 let (sender, receiver) = generic_channel::channel().unwrap();
1033 self.browsing_context_script_command(
1034 WebDriverScriptCommand::IsSelected(element.to_string(), sender),
1035 VerifyBrowsingContextIsOpen::No,
1036 )?;
1037
1038 Ok(WebDriverResponse::Generic(ValueResponse(
1039 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1040 )))
1041 }
1042
1043 fn handle_go_back(&self) -> WebDriverResult<WebDriverResponse> {
1045 let webview_id = self.webview_id()?;
1046 self.verify_top_level_browsing_context_is_open(webview_id)?;
1049
1050 self.handle_any_user_prompts(webview_id)?;
1052
1053 self.send_message_to_embedder(WebDriverCommandMsg::GoBack(
1054 webview_id,
1055 self.load_status_sender.clone(),
1056 ))?;
1057 self.wait_for_navigation_complete()
1058 }
1059
1060 fn handle_go_forward(&self) -> WebDriverResult<WebDriverResponse> {
1062 let webview_id = self.webview_id()?;
1063 self.verify_top_level_browsing_context_is_open(webview_id)?;
1066
1067 self.handle_any_user_prompts(webview_id)?;
1069
1070 self.send_message_to_embedder(WebDriverCommandMsg::GoForward(
1071 webview_id,
1072 self.load_status_sender.clone(),
1073 ))?;
1074 self.wait_for_navigation_complete()
1075 }
1076
1077 fn handle_refresh(&mut self) -> WebDriverResult<WebDriverResponse> {
1079 let webview_id = self.webview_id()?;
1080 self.verify_top_level_browsing_context_is_open(webview_id)?;
1083
1084 self.handle_any_user_prompts(webview_id)?;
1086
1087 let cmd_msg = WebDriverCommandMsg::Refresh(webview_id, self.load_status_sender.clone());
1088 self.send_message_to_embedder(cmd_msg)?;
1089
1090 self.wait_for_navigation_complete()?;
1092
1093 self.session_mut()?
1095 .set_browsing_context_id(BrowsingContextId::from(webview_id));
1096
1097 Ok(WebDriverResponse::Void)
1098 }
1099
1100 fn handle_title(&self) -> WebDriverResult<WebDriverResponse> {
1102 let webview_id = self.webview_id()?;
1103
1104 self.verify_top_level_browsing_context_is_open(webview_id)?;
1107 self.handle_any_user_prompts(webview_id)?;
1109
1110 let (sender, receiver) = generic_channel::channel().unwrap();
1111
1112 self.top_level_script_command(
1113 WebDriverScriptCommand::GetTitle(sender),
1114 VerifyBrowsingContextIsOpen::No,
1115 )?;
1116
1117 let title = wait_for_ipc_response(receiver)?;
1120 Ok(WebDriverResponse::Generic(ValueResponse(
1121 serde_json::to_value(title)?,
1122 )))
1123 }
1124
1125 fn handle_window_handle(&mut self) -> WebDriverResult<WebDriverResponse> {
1127 let webview_id = self.webview_id()?;
1128
1129 self.verify_top_level_browsing_context_is_open(webview_id)?;
1132
1133 let handle = self
1135 .get_window_handle(webview_id)
1136 .expect("Failed to get window handle of an existing webview");
1137
1138 Ok(WebDriverResponse::Generic(ValueResponse(
1139 serde_json::to_value(handle)?,
1140 )))
1141 }
1142
1143 fn handle_window_handles(&mut self) -> WebDriverResult<WebDriverResponse> {
1145 let mut handles = self.get_window_handles();
1146 handles.sort_unstable();
1147
1148 Ok(WebDriverResponse::Generic(ValueResponse(
1149 serde_json::to_value(handles)?,
1150 )))
1151 }
1152
1153 fn get_window_handle(&mut self, webview_id: WebViewId) -> Option<String> {
1154 self.get_window_handles()
1155 .iter()
1156 .find(|id| id == &&webview_id.to_string())
1157 .cloned()
1158 }
1159
1160 fn get_window_handles(&self) -> Vec<String> {
1161 self.get_all_webview_ids()
1162 .into_iter()
1163 .map(|id| id.to_string())
1164 .collect()
1165 }
1166
1167 fn get_all_webview_ids(&self) -> Vec<WebViewId> {
1168 let (sender, receiver) = generic_channel::oneshot().unwrap();
1169 self.send_message_to_embedder(WebDriverCommandMsg::GetAllWebViews(sender))
1170 .unwrap();
1171 wait_for_oneshot_response(receiver).unwrap_or_default()
1172 }
1173
1174 fn handle_close_window(&mut self) -> WebDriverResult<WebDriverResponse> {
1176 let webview_id = self.webview_id()?;
1177 self.verify_top_level_browsing_context_is_open(webview_id)?;
1180
1181 self.handle_any_user_prompts(webview_id)?;
1183
1184 let (sender, receiver) = generic_channel::oneshot().unwrap();
1186
1187 let cmd_msg = WebDriverCommandMsg::CloseWebView(webview_id, sender);
1188 self.send_message_to_embedder(cmd_msg)?;
1189
1190 wait_for_oneshot_response(receiver)?;
1191
1192 let window_handles = self.get_window_handles();
1194
1195 if window_handles.is_empty() {
1196 self.session = None;
1197 }
1198
1199 Ok(WebDriverResponse::CloseWindow(CloseWindowResponse(
1201 window_handles,
1202 )))
1203 }
1204
1205 fn handle_new_window(
1207 &mut self,
1208 parameters: &NewWindowParameters,
1209 ) -> WebDriverResult<WebDriverResponse> {
1210 let (sender, receiver) = generic_channel::oneshot().unwrap();
1211
1212 let webview_id = self.webview_id()?;
1213
1214 self.verify_top_level_browsing_context_is_open(webview_id)?;
1217
1218 self.handle_any_user_prompts(webview_id)?;
1220
1221 let type_hint = match parameters.type_hint.as_deref() {
1224 Some("tab") => NewWindowTypeHint::Tab,
1225 Some("window") => NewWindowTypeHint::Window,
1226 _ => NewWindowTypeHint::Auto,
1227 };
1228
1229 self.send_message_to_embedder(WebDriverCommandMsg::NewWindow(
1241 type_hint,
1242 sender,
1243 Some(self.load_status_sender.clone()),
1244 ))?;
1245
1246 if let Ok(webview_id) = receiver.recv() {
1247 let _ = self.wait_for_navigation_complete();
1248 let handle = self
1249 .get_window_handle(webview_id)
1250 .expect("Failed to get window handle of an existing webview");
1251
1252 Ok(WebDriverResponse::NewWindow(NewWindowResponse {
1253 handle,
1254 typ: "tab".to_string(),
1255 }))
1256 } else {
1257 Err(WebDriverError::new(
1258 ErrorStatus::UnknownError,
1259 "No webview ID received",
1260 ))
1261 }
1262 }
1263
1264 fn handle_switch_to_frame(
1266 &mut self,
1267 parameters: &SwitchToFrameParameters,
1268 ) -> WebDriverResult<WebDriverResponse> {
1269 use webdriver::common::FrameId;
1270 let frame_id = match parameters.id {
1271 FrameId::Top => {
1273 let webview_id = self.webview_id()?;
1274 self.verify_top_level_browsing_context_is_open(webview_id)?;
1277 self.handle_any_user_prompts(webview_id)?;
1279 let browsing_context_id = BrowsingContextId::from(webview_id);
1282 self.session_mut()?
1283 .set_browsing_context_id(browsing_context_id);
1284
1285 self.focus_browsing_context(browsing_context_id)?;
1289 return Ok(WebDriverResponse::Void);
1290 },
1291 FrameId::Short(ref x) => {
1293 WebDriverFrameId::Short(*x)
1297 },
1298 FrameId::Element(ref x) => WebDriverFrameId::Element(x.to_string()),
1299 };
1300
1301 self.switch_to_frame(frame_id)
1302 }
1303
1304 fn handle_switch_to_parent_frame(&mut self) -> WebDriverResult<WebDriverResponse> {
1306 let webview_id = self.webview_id()?;
1307 let browsing_context = self.browsing_context_id()?;
1308
1309 if browsing_context == webview_id {
1311 self.verify_browsing_context_is_open(browsing_context)?;
1314 return Ok(WebDriverResponse::Void);
1316 }
1317
1318 let (sender, receiver) = generic_channel::channel().unwrap();
1321 let cmd = WebDriverScriptCommand::GetParentFrameId(sender);
1322 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
1323
1324 self.handle_any_user_prompts(webview_id)?;
1326
1327 let browsing_context_id = wait_for_ipc_response_flatten(receiver)?;
1330 self.session_mut()?
1331 .set_browsing_context_id(browsing_context_id);
1332 self.focus_browsing_context(browsing_context_id)?;
1336 Ok(WebDriverResponse::Void)
1337 }
1338
1339 fn handle_switch_to_window(
1341 &mut self,
1342 parameters: &SwitchToWindowParameters,
1343 ) -> WebDriverResult<WebDriverResponse> {
1344 let Some(webview_id) = self
1345 .get_all_webview_ids()
1346 .into_iter()
1347 .find(|id| id.to_string() == parameters.handle)
1348 else {
1349 return Err(WebDriverError::new(
1350 ErrorStatus::NoSuchWindow,
1351 "No such window while switching to window",
1352 ));
1353 };
1354
1355 let session = self.session_mut()?;
1356 session.set_webview_id(webview_id);
1357 session.set_browsing_context_id(BrowsingContextId::from(webview_id));
1358
1359 self.focus_webview(webview_id)?;
1363
1364 Ok(WebDriverResponse::Void)
1365 }
1366
1367 fn switch_to_frame(
1368 &mut self,
1369 frame_id: WebDriverFrameId,
1370 ) -> WebDriverResult<WebDriverResponse> {
1371 let (sender, receiver) = generic_channel::channel().unwrap();
1372 let cmd = WebDriverScriptCommand::GetBrowsingContextId(frame_id, sender);
1373 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
1374 self.handle_any_user_prompts(self.webview_id()?)?;
1375
1376 let browsing_context_id = wait_for_ipc_response_flatten(receiver)?;
1377 self.session_mut()?
1378 .set_browsing_context_id(browsing_context_id);
1379 self.focus_browsing_context(browsing_context_id)?;
1383 Ok(WebDriverResponse::Void)
1384 }
1385
1386 fn handle_find_element(
1388 &self,
1389 parameters: &LocatorParameters,
1390 ) -> WebDriverResult<WebDriverResponse> {
1391 let res = self.handle_find_elements(parameters)?;
1393 unwrap_first_element_response(res)
1396 }
1397
1398 fn implicit_wait<T>(
1401 &self,
1402 callback: impl Fn() -> Result<(bool, T), (bool, WebDriverError)>,
1403 ) -> Result<T, WebDriverError> {
1404 let now = Instant::now();
1405 let (implicit_wait, sleep_interval) = {
1406 let timeouts = self.session()?.session_timeouts();
1407 (
1408 timeouts
1409 .implicit_wait
1410 .map_or(Duration::MAX, Duration::from_millis),
1411 Duration::from_millis(timeouts.sleep_interval),
1412 )
1413 };
1414
1415 loop {
1416 match callback() {
1417 Ok((can_early_return, value)) => {
1418 if can_early_return || now.elapsed() >= implicit_wait {
1419 return Ok(value);
1420 }
1421 },
1422 Err((can_early_return, error)) => {
1423 if can_early_return || now.elapsed() >= implicit_wait {
1424 return Err(error);
1425 }
1426 },
1427 }
1428 sleep(sleep_interval);
1429 }
1430 }
1431
1432 fn handle_find_elements(
1434 &self,
1435 parameters: &LocatorParameters,
1436 ) -> WebDriverResult<WebDriverResponse> {
1437 if parameters.value.is_empty() {
1439 return Err(WebDriverError::new(ErrorStatus::InvalidArgument, ""));
1440 }
1441 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1444
1445 self.handle_any_user_prompts(self.webview_id()?)?;
1447
1448 self.implicit_wait(|| {
1449 let (sender, receiver) = generic_channel::channel().unwrap();
1450 let cmd = match parameters.using {
1451 LocatorStrategy::CSSSelector => WebDriverScriptCommand::FindElementsCSSSelector(
1452 parameters.value.clone(),
1453 sender,
1454 ),
1455 LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => {
1456 WebDriverScriptCommand::FindElementsLinkText(
1457 parameters.value.clone(),
1458 parameters.using == LocatorStrategy::PartialLinkText,
1459 sender,
1460 )
1461 },
1462 LocatorStrategy::TagName => {
1463 WebDriverScriptCommand::FindElementsTagName(parameters.value.clone(), sender)
1464 },
1465 LocatorStrategy::XPath => WebDriverScriptCommand::FindElementsXpathSelector(
1466 parameters.value.clone(),
1467 sender,
1468 ),
1469 };
1470 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)
1471 .map_err(|error| (ImplicitWait::Return.into(), error))?;
1472 wait_for_ipc_response_flatten(receiver)
1473 .map(|value| (!value.is_empty(), value))
1474 .map_err(|error| (ImplicitWait::Return.into(), error))
1475 })
1476 .and_then(|response| {
1477 let resp_value: Vec<WebElement> = response.into_iter().map(WebElement).collect();
1478 Ok(WebDriverResponse::Generic(ValueResponse(
1479 serde_json::to_value(resp_value)?,
1480 )))
1481 })
1482 }
1483
1484 fn handle_find_element_from_element(
1486 &self,
1487 element: &WebElement,
1488 parameters: &LocatorParameters,
1489 ) -> WebDriverResult<WebDriverResponse> {
1490 let res = self.handle_find_elements_from_element(element, parameters)?;
1492 unwrap_first_element_response(res)
1495 }
1496
1497 fn handle_find_elements_from_element(
1499 &self,
1500 element: &WebElement,
1501 parameters: &LocatorParameters,
1502 ) -> WebDriverResult<WebDriverResponse> {
1503 if parameters.value.is_empty() {
1505 return Err(WebDriverError::new(ErrorStatus::InvalidArgument, ""));
1506 }
1507 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1510
1511 self.handle_any_user_prompts(self.webview_id()?)?;
1513
1514 self.implicit_wait(|| {
1515 let (sender, receiver) = generic_channel::channel().unwrap();
1516
1517 let cmd = match parameters.using {
1518 LocatorStrategy::CSSSelector => {
1519 WebDriverScriptCommand::FindElementElementsCSSSelector(
1520 parameters.value.clone(),
1521 element.to_string(),
1522 sender,
1523 )
1524 },
1525 LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => {
1526 WebDriverScriptCommand::FindElementElementsLinkText(
1527 parameters.value.clone(),
1528 element.to_string(),
1529 parameters.using == LocatorStrategy::PartialLinkText,
1530 sender,
1531 )
1532 },
1533 LocatorStrategy::TagName => WebDriverScriptCommand::FindElementElementsTagName(
1534 parameters.value.clone(),
1535 element.to_string(),
1536 sender,
1537 ),
1538 LocatorStrategy::XPath => WebDriverScriptCommand::FindElementElementsXPathSelector(
1539 parameters.value.clone(),
1540 element.to_string(),
1541 sender,
1542 ),
1543 };
1544 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)
1545 .map_err(|error| (ImplicitWait::Return.into(), error))?;
1546 wait_for_ipc_response_flatten(receiver)
1547 .map(|value| (!value.is_empty(), value))
1548 .map_err(|error| (ImplicitWait::Return.into(), error))
1549 })
1550 .and_then(|response| {
1551 let resp_value: Vec<Value> = response
1552 .into_iter()
1553 .map(|x| serde_json::to_value(WebElement(x)).unwrap())
1554 .collect();
1555 Ok(WebDriverResponse::Generic(ValueResponse(
1556 serde_json::to_value(resp_value)?,
1557 )))
1558 })
1559 }
1560
1561 fn handle_find_elements_from_shadow_root(
1563 &self,
1564 shadow_root: &ShadowRoot,
1565 parameters: &LocatorParameters,
1566 ) -> WebDriverResult<WebDriverResponse> {
1567 if parameters.value.is_empty() {
1569 return Err(WebDriverError::new(ErrorStatus::InvalidArgument, ""));
1570 }
1571
1572 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1575
1576 self.handle_any_user_prompts(self.webview_id()?)?;
1578
1579 self.implicit_wait(|| {
1580 let (sender, receiver) = generic_channel::channel().unwrap();
1581
1582 let cmd = match parameters.using {
1583 LocatorStrategy::CSSSelector => {
1584 WebDriverScriptCommand::FindShadowElementsCSSSelector(
1585 parameters.value.clone(),
1586 shadow_root.to_string(),
1587 sender,
1588 )
1589 },
1590 LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => {
1591 WebDriverScriptCommand::FindShadowElementsLinkText(
1592 parameters.value.clone(),
1593 shadow_root.to_string(),
1594 parameters.using == LocatorStrategy::PartialLinkText,
1595 sender,
1596 )
1597 },
1598 LocatorStrategy::TagName => WebDriverScriptCommand::FindShadowElementsTagName(
1599 parameters.value.clone(),
1600 shadow_root.to_string(),
1601 sender,
1602 ),
1603 LocatorStrategy::XPath => WebDriverScriptCommand::FindShadowElementsXPathSelector(
1604 parameters.value.clone(),
1605 shadow_root.to_string(),
1606 sender,
1607 ),
1608 };
1609 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)
1610 .map_err(|error| (ImplicitWait::Return.into(), error))?;
1611 wait_for_ipc_response_flatten(receiver)
1612 .map(|value| (!value.is_empty(), value))
1613 .map_err(|error| (ImplicitWait::Return.into(), error))
1614 })
1615 .and_then(|response| {
1616 let resp_value: Vec<Value> = response
1617 .into_iter()
1618 .map(|x| serde_json::to_value(WebElement(x)).unwrap())
1619 .collect();
1620 Ok(WebDriverResponse::Generic(ValueResponse(
1621 serde_json::to_value(resp_value)?,
1622 )))
1623 })
1624 }
1625
1626 fn handle_find_element_from_shadow_root(
1628 &self,
1629 shadow_root: &ShadowRoot,
1630 parameters: &LocatorParameters,
1631 ) -> WebDriverResult<WebDriverResponse> {
1632 let res = self.handle_find_elements_from_shadow_root(shadow_root, parameters)?;
1634 unwrap_first_element_response(res)
1637 }
1638
1639 fn handle_get_shadow_root(&self, element: WebElement) -> WebDriverResult<WebDriverResponse> {
1641 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1644 self.handle_any_user_prompts(self.webview_id()?)?;
1646 let (sender, receiver) = generic_channel::channel().unwrap();
1647 let cmd = WebDriverScriptCommand::GetElementShadowRoot(element.to_string(), sender);
1648 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1649 let Some(value) = wait_for_ipc_response_flatten(receiver)? else {
1651 return Err(WebDriverError::new(ErrorStatus::NoSuchShadowRoot, ""));
1652 };
1653 Ok(WebDriverResponse::Generic(ValueResponse(
1654 serde_json::to_value(ShadowRoot(value))?,
1655 )))
1656 }
1657
1658 fn handle_element_rect(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
1660 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1663 self.handle_any_user_prompts(self.webview_id()?)?;
1665 let (sender, receiver) = generic_channel::channel().unwrap();
1666 let cmd = WebDriverScriptCommand::GetElementRect(element.to_string(), sender);
1667 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1668 let rect = wait_for_ipc_response_flatten(receiver)?;
1669 let response = ElementRectResponse {
1670 x: rect.origin.x,
1671 y: rect.origin.y,
1672 width: rect.size.width,
1673 height: rect.size.height,
1674 };
1675 Ok(WebDriverResponse::ElementRect(response))
1676 }
1677
1678 fn handle_element_text(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
1680 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1683 self.handle_any_user_prompts(self.webview_id()?)?;
1685 let (sender, receiver) = generic_channel::channel().unwrap();
1686 let cmd = WebDriverScriptCommand::GetElementText(element.to_string(), sender);
1687 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1688 Ok(WebDriverResponse::Generic(ValueResponse(
1689 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1690 )))
1691 }
1692
1693 fn handle_active_element(&self) -> WebDriverResult<WebDriverResponse> {
1695 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1698 self.handle_any_user_prompts(self.webview_id()?)?;
1700 let (sender, receiver) = generic_channel::channel().unwrap();
1701 let cmd = WebDriverScriptCommand::GetActiveElement(sender);
1702 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1703 let value =
1704 wait_for_ipc_response(receiver)?.map(|x| serde_json::to_value(WebElement(x)).unwrap());
1705 if value.is_some() {
1709 Ok(WebDriverResponse::Generic(ValueResponse(
1710 serde_json::to_value(value)?,
1711 )))
1712 } else {
1713 Err(WebDriverError::new(
1714 ErrorStatus::NoSuchElement,
1715 "No active element found",
1716 ))
1717 }
1718 }
1719
1720 fn handle_computed_role(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
1722 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1725 self.handle_any_user_prompts(self.webview_id()?)?;
1727 let (sender, receiver) = generic_channel::channel().unwrap();
1728 let cmd = WebDriverScriptCommand::GetComputedRole(element.to_string(), sender);
1729 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1730 Ok(WebDriverResponse::Generic(ValueResponse(
1731 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1732 )))
1733 }
1734
1735 fn handle_element_tag_name(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
1737 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1740 self.handle_any_user_prompts(self.webview_id()?)?;
1742 let (sender, receiver) = generic_channel::channel().unwrap();
1743 let cmd = WebDriverScriptCommand::GetElementTagName(element.to_string(), sender);
1744 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1745 Ok(WebDriverResponse::Generic(ValueResponse(
1746 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1747 )))
1748 }
1749
1750 fn handle_element_attribute(
1752 &self,
1753 element: &WebElement,
1754 name: &str,
1755 ) -> WebDriverResult<WebDriverResponse> {
1756 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1759 self.handle_any_user_prompts(self.webview_id()?)?;
1761 let (sender, receiver) = generic_channel::channel().unwrap();
1762 let cmd = WebDriverScriptCommand::GetElementAttribute(
1763 element.to_string(),
1764 name.to_owned(),
1765 sender,
1766 );
1767 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1768 Ok(WebDriverResponse::Generic(ValueResponse(
1769 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1770 )))
1771 }
1772
1773 fn handle_element_property(
1775 &self,
1776 element: &WebElement,
1777 name: &str,
1778 ) -> WebDriverResult<WebDriverResponse> {
1779 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1782 self.handle_any_user_prompts(self.webview_id()?)?;
1784 let (sender, receiver) = generic_channel::channel().unwrap();
1785
1786 let cmd = WebDriverScriptCommand::GetElementProperty(
1787 element.to_string(),
1788 name.to_owned(),
1789 sender,
1790 );
1791 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1792
1793 Ok(WebDriverResponse::Generic(ValueResponse(
1794 serde_json::to_value(SendableJSValue(wait_for_ipc_response_flatten(receiver)?))?,
1795 )))
1796 }
1797
1798 fn handle_element_css(
1800 &self,
1801 element: &WebElement,
1802 name: &str,
1803 ) -> WebDriverResult<WebDriverResponse> {
1804 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1807 self.handle_any_user_prompts(self.webview_id()?)?;
1809 let (sender, receiver) = generic_channel::channel().unwrap();
1810 let cmd =
1811 WebDriverScriptCommand::GetElementCSS(element.to_string(), name.to_owned(), sender);
1812 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1813 Ok(WebDriverResponse::Generic(ValueResponse(
1814 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1815 )))
1816 }
1817
1818 fn handle_get_cookies(&self) -> WebDriverResult<WebDriverResponse> {
1820 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1823 self.handle_any_user_prompts(self.webview_id()?)?;
1825 let (sender, receiver) = generic_channel::channel().unwrap();
1826 let cmd = WebDriverScriptCommand::GetCookies(sender);
1827 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1828 let cookies = wait_for_ipc_response_flatten(receiver)?;
1829 let response = cookies
1830 .into_iter()
1831 .map(|cookie| cookie_msg_to_cookie(cookie.into_inner()))
1832 .collect::<Vec<Cookie>>();
1833 Ok(WebDriverResponse::Cookies(CookiesResponse(response)))
1834 }
1835
1836 fn handle_get_cookie(&self, name: String) -> WebDriverResult<WebDriverResponse> {
1838 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1841 self.handle_any_user_prompts(self.webview_id()?)?;
1843 let (sender, receiver) = generic_channel::channel().unwrap();
1844 let cmd = WebDriverScriptCommand::GetCookie(name, sender);
1845 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1846 let cookies = wait_for_ipc_response_flatten(receiver)?;
1847 let Some(response) = cookies
1848 .into_iter()
1849 .map(|cookie| cookie_msg_to_cookie(cookie.into_inner()))
1850 .next()
1851 else {
1852 return Err(WebDriverError::new(ErrorStatus::NoSuchCookie, ""));
1853 };
1854 Ok(WebDriverResponse::Cookie(CookieResponse(response)))
1855 }
1856
1857 fn handle_add_cookie(
1859 &self,
1860 params: &AddCookieParameters,
1861 ) -> WebDriverResult<WebDriverResponse> {
1862 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1865 self.handle_any_user_prompts(self.webview_id()?)?;
1867 let (sender, receiver) = generic_channel::channel().unwrap();
1868
1869 if let Some(ref expiry) = params.expiry &&
1873 expiry.0 > MAXIMUM_SAFE_INTEGER
1874 {
1875 return Err(WebDriverError::new(
1876 ErrorStatus::InvalidArgument,
1877 "expiry time greater than maximum safe integer",
1878 ));
1879 }
1880
1881 let mut cookie_builder =
1882 CookieBuilder::new(params.name.to_owned(), params.value.to_owned())
1883 .secure(params.secure)
1884 .http_only(params.httpOnly);
1885 if let Some(ref domain) = params.domain {
1886 cookie_builder = cookie_builder.domain(domain.clone());
1887 }
1888 if let Some(ref path) = params.path {
1889 cookie_builder = cookie_builder.path(path.clone());
1890 }
1891 if let Some(ref expiry) = params.expiry {
1892 let datetime = OffsetDateTime::from_unix_timestamp(expiry.0 as i64).map_err(|_| {
1893 WebDriverError::new(ErrorStatus::InvalidArgument, "invalid expiry time")
1894 })?;
1895 cookie_builder = cookie_builder.expires(datetime);
1896 }
1897 if let Some(ref same_site) = params.sameSite {
1898 cookie_builder = match same_site.as_str() {
1899 "None" => Ok(cookie_builder.same_site(SameSite::None)),
1900 "Lax" => Ok(cookie_builder.same_site(SameSite::Lax)),
1901 "Strict" => Ok(cookie_builder.same_site(SameSite::Strict)),
1902 _ => Err(WebDriverError::new(
1903 ErrorStatus::InvalidArgument,
1904 "invalid argument",
1905 )),
1906 }?;
1907 }
1908
1909 let cmd = WebDriverScriptCommand::AddCookie(cookie_builder.build(), sender);
1910 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1911 wait_for_ipc_response_flatten(receiver)?;
1912 Ok(WebDriverResponse::Void)
1913 }
1914
1915 fn handle_delete_cookie(&self, name: String) -> WebDriverResult<WebDriverResponse> {
1917 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1920 self.handle_any_user_prompts(self.webview_id()?)?;
1922 let (sender, receiver) = generic_channel::channel().unwrap();
1923 let cmd = WebDriverScriptCommand::DeleteCookie(name, sender);
1924 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1925 wait_for_ipc_response_flatten(receiver)?;
1926 Ok(WebDriverResponse::Void)
1927 }
1928
1929 fn handle_delete_cookies(&self) -> WebDriverResult<WebDriverResponse> {
1931 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1934 self.handle_any_user_prompts(self.webview_id()?)?;
1936 let (sender, receiver) = generic_channel::channel().unwrap();
1937 let cmd = WebDriverScriptCommand::DeleteCookies(sender);
1938 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1939 wait_for_ipc_response_flatten(receiver)?;
1940 Ok(WebDriverResponse::Void)
1941 }
1942
1943 fn handle_get_timeouts(&mut self) -> WebDriverResult<WebDriverResponse> {
1945 let timeouts = self.session()?.session_timeouts();
1946
1947 let timeouts = TimeoutsResponse {
1952 script: timeouts.script,
1953 page_load: timeouts.page_load.unwrap_or(DEFAULT_PAGE_LOAD_TIMEOUT),
1954 implicit: timeouts.implicit_wait.unwrap_or(DEFAULT_IMPLICIT_WAIT),
1955 };
1956
1957 Ok(WebDriverResponse::Timeouts(timeouts))
1958 }
1959
1960 fn handle_set_timeouts(
1962 &mut self,
1963 parameters: &TimeoutsParameters,
1964 ) -> WebDriverResult<WebDriverResponse> {
1965 let session = self.session_mut()?;
1966
1967 if let Some(timeout) = parameters.script {
1968 session.session_timeouts_mut().script = timeout;
1969 }
1970 if let Some(timeout) = parameters.page_load {
1971 session.session_timeouts_mut().page_load = Some(timeout);
1972 }
1973 if let Some(timeout) = parameters.implicit {
1974 session.session_timeouts_mut().implicit_wait = Some(timeout);
1975 }
1976
1977 Ok(WebDriverResponse::Void)
1978 }
1979
1980 fn handle_get_page_source(&self) -> WebDriverResult<WebDriverResponse> {
1982 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
1985 self.handle_any_user_prompts(self.webview_id()?)?;
1987 let (sender, receiver) = generic_channel::channel().unwrap();
1988
1989 let cmd = WebDriverScriptCommand::GetPageSource(sender);
1990 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
1991
1992 Ok(WebDriverResponse::Generic(ValueResponse(
1993 serde_json::to_value(wait_for_ipc_response_flatten(receiver)?)?,
1994 )))
1995 }
1996
1997 fn handle_perform_actions(
1999 &mut self,
2000 parameters: ActionsParameters,
2001 ) -> WebDriverResult<WebDriverResponse> {
2002 let browsing_context = self.browsing_context_id()?;
2003 self.verify_browsing_context_is_open(browsing_context)?;
2006
2007 self.handle_any_user_prompts(self.webview_id()?)?;
2009
2010 let actions_by_tick = self.extract_an_action_sequence(parameters.actions);
2012
2013 match self.dispatch_actions(actions_by_tick, browsing_context) {
2015 Ok(_) => Ok(WebDriverResponse::Void),
2016 Err(error) => Err(WebDriverError::new(error, "")),
2017 }
2018 }
2019
2020 fn handle_release_actions(&mut self) -> WebDriverResult<WebDriverResponse> {
2022 let browsing_context_id = self.browsing_context_id()?;
2023 self.verify_browsing_context_is_open(browsing_context_id)?;
2026
2027 self.handle_any_user_prompts(self.webview_id()?)?;
2029
2030 let undo_actions = self
2037 .session_mut()?
2038 .input_cancel_list
2039 .drain(..)
2040 .rev()
2041 .map(|(id, action_item)| Vec::from([(id, action_item)]))
2042 .collect();
2043 if let Err(err) = self.dispatch_actions(undo_actions, browsing_context_id) {
2045 return Err(WebDriverError::new(err, "Failed to dispatch undo actions"));
2046 }
2047
2048 self.session_mut()?.input_state_table.clear();
2050
2051 Ok(WebDriverResponse::Void)
2052 }
2053
2054 fn handle_execute_script(
2056 &self,
2057 parameters: JavascriptCommandParameters,
2058 ) -> WebDriverResult<WebDriverResponse> {
2059 let (func_body, args_string) = self.extract_script_arguments(parameters)?;
2062
2063 let script = format!(
2067 r#"(async function() {{
2068 try {{
2069 let result = (async function() {{
2070 {func_body}
2071 }})({});
2072 let value = await result;
2073 window.webdriverCallback(value);
2074 }} catch (err) {{
2075 window.webdriverException(err);
2076 }}
2077 }})();"#,
2078 args_string.join(", ")
2079 );
2080
2081 debug!("{}", script);
2082
2083 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
2086
2087 self.handle_any_user_prompts(self.webview_id()?)?;
2089
2090 let (sender, receiver) = generic_channel::channel().unwrap();
2091 let cmd = WebDriverScriptCommand::ExecuteScriptWithCallback(script, sender);
2092
2093 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
2094
2095 let timeout_duration = self
2096 .session()?
2097 .session_timeouts()
2098 .script
2099 .map_or(Duration::MAX, Duration::from_millis);
2100
2101 let result = wait_for_script_ipc_response_with_timeout(receiver, timeout_duration)?;
2102
2103 self.javascript_evaluation_result_to_webdriver_response(result)
2104 }
2105
2106 fn handle_execute_async_script(
2107 &self,
2108 parameters: JavascriptCommandParameters,
2109 ) -> WebDriverResult<WebDriverResponse> {
2110 let (function_body, mut args_string) = self.extract_script_arguments(parameters)?;
2113 args_string.push("resolve".to_string());
2114
2115 let joined_args = args_string.join(", ");
2116 let script = format!(
2117 r#"(function() {{
2118 new Promise(function(resolve, reject) {{
2119 (async function() {{
2120 {function_body}
2121 }})({joined_args})
2122 .catch(reject)
2123 }})
2124 .then((v) => window.webdriverCallback(v), (r) => window.webdriverException(r))
2125 .catch((r) => window.webdriverException(r));
2126 }})();"#,
2127 );
2128 debug!("{}", script);
2129
2130 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
2133
2134 self.handle_any_user_prompts(self.webview_id()?)?;
2136
2137 let (sender, receiver) = generic_channel::channel().unwrap();
2138 self.browsing_context_script_command(
2139 WebDriverScriptCommand::ExecuteScriptWithCallback(script, sender),
2140 VerifyBrowsingContextIsOpen::No,
2141 )?;
2142
2143 let timeout_duration = self
2144 .session()?
2145 .session_timeouts()
2146 .script
2147 .map_or(Duration::MAX, Duration::from_millis);
2148 let result = wait_for_script_ipc_response_with_timeout(receiver, timeout_duration)?;
2149
2150 self.javascript_evaluation_result_to_webdriver_response(result)
2151 }
2152
2153 fn javascript_evaluation_result_to_webdriver_response(
2154 &self,
2155 result: WebDriverJSResult,
2156 ) -> WebDriverResult<WebDriverResponse> {
2157 match result {
2158 Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
2159 serde_json::to_value(SendableJSValue(value))?,
2160 ))),
2161 Err(error) => {
2162 let message = format!("{error:?}");
2163 let status = match error {
2164 JavaScriptEvaluationError::DocumentNotFound => ErrorStatus::NoSuchWindow,
2165 JavaScriptEvaluationError::CompilationFailure => ErrorStatus::JavascriptError,
2166 JavaScriptEvaluationError::EvaluationFailure(Some(error_info)) => {
2167 return Err(WebDriverError::new_with_data(
2168 ErrorStatus::JavascriptError,
2169 error_info.message,
2170 None,
2171 error_info.stack,
2172 ));
2173 },
2174 JavaScriptEvaluationError::EvaluationFailure(None) => {
2175 ErrorStatus::JavascriptError
2176 },
2177 JavaScriptEvaluationError::InternalError => ErrorStatus::JavascriptError,
2178 JavaScriptEvaluationError::SerializationError(serialization_error) => {
2179 match serialization_error {
2180 JavaScriptEvaluationResultSerializationError::DetachedShadowRoot => {
2181 ErrorStatus::DetachedShadowRoot
2182 },
2183 JavaScriptEvaluationResultSerializationError::OtherJavaScriptError => {
2184 ErrorStatus::JavascriptError
2185 },
2186 JavaScriptEvaluationResultSerializationError::StaleElementReference => {
2187 ErrorStatus::StaleElementReference
2188 },
2189 JavaScriptEvaluationResultSerializationError::UnknownType => {
2190 ErrorStatus::UnsupportedOperation
2191 },
2192 }
2193 },
2194 JavaScriptEvaluationError::WebViewNotReady => ErrorStatus::NoSuchWindow,
2195 };
2196 Err(WebDriverError::new(status, message))
2197 },
2198 }
2199 }
2200
2201 fn handle_element_send_keys(
2203 &mut self,
2204 element: &WebElement,
2205 keys: &SendKeysParameters,
2206 ) -> WebDriverResult<WebDriverResponse> {
2207 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
2210 self.handle_any_user_prompts(self.webview_id()?)?;
2212
2213 let (sender, receiver) = generic_channel::channel().unwrap();
2214 let cmd = WebDriverScriptCommand::WillSendKeys(
2215 element.to_string(),
2216 keys.text.to_string(),
2217 self.session()?.strict_file_interactability(),
2218 sender,
2219 );
2220 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
2221
2222 if !wait_for_ipc_response_flatten(receiver)? {
2225 return Ok(WebDriverResponse::Void);
2226 }
2227
2228 let id = Uuid::new_v4().to_string();
2230
2231 self.session_mut()?
2233 .input_state_table
2234 .insert(id.clone(), InputSourceState::Key(KeyInputState::new()));
2235
2236 let input_events = send_keys(&keys.text);
2239
2240 for event in input_events {
2241 match event {
2242 DispatchStringEvent::Keyboard(event) => {
2243 let raw_string = convert_keyboard_event_to_string(&event);
2244 let key_action = match event.state {
2245 KeyState::Down => KeyAction::Down(KeyDownAction { value: raw_string }),
2246 KeyState::Up => KeyAction::Up(KeyUpAction { value: raw_string }),
2247 };
2248 let action_sequence = ActionSequence {
2249 id: id.clone(),
2250 actions: ActionsType::Key {
2251 actions: vec![KeyActionItem::Key(key_action)],
2252 },
2253 };
2254
2255 let actions_by_tick = self.extract_an_action_sequence(vec![action_sequence]);
2256 if let Err(e) =
2257 self.dispatch_actions(actions_by_tick, self.browsing_context_id()?)
2258 {
2259 error!("handle_element_send_keys: dispatch_actions failed: {:?}", e);
2260 }
2261 },
2262 DispatchStringEvent::Composition(event) => {
2263 self.send_blocking_input_event_to_embedder(InputEvent::Ime(
2264 ImeEvent::Composition(event),
2265 ));
2266 },
2267 }
2268 }
2269
2270 if self
2275 .session()?
2276 .input_cancel_list
2277 .iter()
2278 .all(|(cancel_item_id, _)| &id != cancel_item_id)
2279 {
2280 self.session_mut()?.input_state_table.remove(&id);
2281 }
2282
2283 Ok(WebDriverResponse::Void)
2284 }
2285
2286 fn handle_element_clear(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
2288 self.verify_browsing_context_is_open(self.browsing_context_id()?)?;
2291
2292 self.handle_any_user_prompts(self.webview_id()?)?;
2294
2295 let (sender, receiver) = generic_channel::channel().unwrap();
2297 let cmd = WebDriverScriptCommand::ElementClear(element.to_string(), sender);
2298 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
2299
2300 wait_for_ipc_response_flatten(receiver)?;
2301 Ok(WebDriverResponse::Void)
2302 }
2303
2304 fn handle_element_click(&mut self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
2306 let browsing_context_id = self.browsing_context_id()?;
2309 self.verify_browsing_context_is_open(browsing_context_id)?;
2310
2311 self.handle_any_user_prompts(self.webview_id()?)?;
2313
2314 let (sender, receiver) = generic_channel::channel().unwrap();
2315
2316 let cmd = WebDriverScriptCommand::ElementClick(element.to_string(), sender);
2318 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
2319
2320 match wait_for_ipc_response_flatten(receiver)? {
2321 Some(element_id) => {
2322 self.add_load_status_sender()?;
2325
2326 self.perform_element_click(element_id)?;
2327
2328 let res = self.wait_for_navigation()?;
2331
2332 self.clear_load_status_sender()?;
2334
2335 Ok(res)
2336 },
2337 None => Ok(WebDriverResponse::Void),
2339 }
2340 }
2341
2342 fn perform_element_click(&mut self, element: String) -> WebDriverResult<WebDriverResponse> {
2345 let id = Uuid::new_v4().to_string();
2347
2348 let pointer_ids = self.session()?.pointer_ids();
2349 #[cfg(not(any(target_env = "ohos", target_os = "android")))]
2350 let pointer_type = PointerType::Mouse;
2351
2352 #[cfg(any(target_env = "ohos", target_os = "android"))]
2357 let pointer_type = PointerType::Touch;
2358
2359 self.session_mut()?.input_state_table.insert(
2360 id.clone(),
2361 InputSourceState::Pointer(PointerInputState::new(pointer_type, pointer_ids, 0.0, 0.0)),
2362 );
2363
2364 let pointer_move_action = PointerMoveAction {
2369 duration: None,
2370 origin: PointerOrigin::Element(WebElement(element)),
2371 x: 0.0,
2372 y: 0.0,
2373 ..Default::default()
2374 };
2375
2376 let pointer_down_action = PointerDownAction {
2379 button: ELEMENT_CLICK_BUTTON,
2380 ..Default::default()
2381 };
2382
2383 let pointer_up_action = PointerUpAction {
2386 button: ELEMENT_CLICK_BUTTON,
2387 ..Default::default()
2388 };
2389
2390 let action_sequence = ActionSequence {
2391 id: id.clone(),
2392 actions: ActionsType::Pointer {
2393 parameters: PointerActionParameters {
2394 pointer_type: PointerType::Mouse,
2395 },
2396 actions: vec![
2397 PointerActionItem::Pointer(PointerAction::Move(pointer_move_action)),
2398 PointerActionItem::Pointer(PointerAction::Down(pointer_down_action)),
2399 PointerActionItem::Pointer(PointerAction::Up(pointer_up_action)),
2400 ],
2401 },
2402 };
2403
2404 let actions_by_tick = self.extract_an_action_sequence(vec![action_sequence]);
2406 if let Err(e) = self.dispatch_actions(actions_by_tick, self.browsing_context_id()?) {
2407 error!("handle_element_click: dispatch_actions failed: {:?}", e);
2408 }
2409
2410 self.session_mut()?.input_state_table.remove(&id);
2412
2413 Ok(WebDriverResponse::Void)
2414 }
2415
2416 fn take_screenshot(&self, rect: Option<Rect<f32, CSSPixel>>) -> WebDriverResult<String> {
2417 let _ = self.handle_execute_async_script(JavascriptCommandParameters {
2419 script: "requestAnimationFrame(() => arguments[0]());".to_string(),
2420 args: None,
2421 });
2422 if rect.as_ref().is_some_and(Rect::is_empty) {
2423 return Err(WebDriverError::new(
2424 ErrorStatus::UnknownError,
2425 "The requested `rect` has zero width and/or height",
2426 ));
2427 }
2428
2429 let webview_id = self.webview_id()?;
2430 let (sender, receiver) = crossbeam_channel::unbounded();
2431 self.send_message_to_embedder(WebDriverCommandMsg::TakeScreenshot(
2432 webview_id, rect, sender,
2433 ))?;
2434
2435 let result = match receiver.recv_timeout(SCREENSHOT_TIMEOUT) {
2436 Ok(result) => Ok(result),
2437 Err(RecvTimeoutError::Timeout) => Err(WebDriverError::new(
2438 ErrorStatus::Timeout,
2439 "Timed out waiting to take screenshot. Test likely didn't finish.",
2440 )),
2441 Err(RecvTimeoutError::Disconnected) => Err(WebDriverError::new(
2442 ErrorStatus::UnknownError,
2443 "Could not take screenshot because channel disconnected.",
2444 )),
2445 }?;
2446
2447 let image = result.map_err(|error| {
2448 WebDriverError::new(
2449 ErrorStatus::UnknownError,
2450 format!("Failed to take screenshot: {error:?}"),
2451 )
2452 })?;
2453
2454 let mut png_data = Cursor::new(Vec::new());
2455 DynamicImage::ImageRgba8(image)
2456 .write_to(&mut png_data, ImageFormat::Png)
2457 .unwrap();
2458
2459 Ok(base64::engine::general_purpose::STANDARD.encode(png_data.get_ref()))
2460 }
2461
2462 fn handle_take_screenshot(&self) -> WebDriverResult<WebDriverResponse> {
2463 let webview_id = self.webview_id()?;
2466 self.verify_top_level_browsing_context_is_open(webview_id)?;
2467
2468 self.handle_any_user_prompts(webview_id)?;
2469
2470 let encoded = self.take_screenshot(None)?;
2472
2473 Ok(WebDriverResponse::Generic(ValueResponse(
2474 serde_json::to_value(encoded)?,
2475 )))
2476 }
2477
2478 fn handle_take_element_screenshot(
2479 &self,
2480 element: &WebElement,
2481 ) -> WebDriverResult<WebDriverResponse> {
2482 let webview_id = self.webview_id()?;
2485 self.verify_top_level_browsing_context_is_open(webview_id)?;
2486
2487 self.handle_any_user_prompts(webview_id)?;
2489
2490 let (sender, receiver) = generic_channel::channel().unwrap();
2493 let cmd =
2494 WebDriverScriptCommand::ScrollAndGetBoundingClientRect(element.to_string(), sender);
2495 self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
2496
2497 let rect = wait_for_ipc_response_flatten(receiver)?;
2498
2499 let encoded = self.take_screenshot(Some(Rect::from_untyped(&rect)))?;
2501
2502 Ok(WebDriverResponse::Generic(ValueResponse(
2504 serde_json::to_value(encoded)?,
2505 )))
2506 }
2507
2508 fn handle_custom_handlers_set_mode(
2510 &self,
2511 parameters: &CustomHandlersSetModeParameters,
2512 ) -> WebDriverResult<WebDriverResponse> {
2513 let mode = match parameters.mode.as_str() {
2516 "autoAccept" => CustomHandlersAutomationMode::AutoAccept,
2517 "autoReject" => CustomHandlersAutomationMode::AutoReject,
2518 "none" => CustomHandlersAutomationMode::None,
2519 _ => {
2520 return Err(WebDriverError::new(
2521 ErrorStatus::InvalidArgument,
2522 "invalid argument",
2523 ));
2524 },
2525 };
2526 self.top_level_script_command(
2529 WebDriverScriptCommand::SetProtocolHandlerAutomationMode(mode),
2530 VerifyBrowsingContextIsOpen::Yes,
2531 )?;
2532 Ok(WebDriverResponse::Void)
2534 }
2535
2536 fn handle_get_prefs(
2537 &self,
2538 parameters: &GetPrefsParameters,
2539 ) -> WebDriverResult<WebDriverResponse> {
2540 let prefs = parameters
2541 .prefs
2542 .iter()
2543 .map(|item| {
2544 (
2545 item.clone(),
2546 serde_json::to_value(prefs::get().get_value(item)).unwrap(),
2547 )
2548 })
2549 .collect::<BTreeMap<_, _>>();
2550
2551 Ok(WebDriverResponse::Generic(ValueResponse(
2552 serde_json::to_value(prefs)?,
2553 )))
2554 }
2555
2556 fn handle_set_prefs(
2557 &self,
2558 parameters: &SetPrefsParameters,
2559 ) -> WebDriverResult<WebDriverResponse> {
2560 let mut current_preferences = prefs::get().clone();
2561 for (key, value) in parameters.prefs.iter() {
2562 current_preferences.set_value(key, value.0.clone());
2563 }
2564 prefs::set(current_preferences);
2565
2566 Ok(WebDriverResponse::Void)
2567 }
2568
2569 fn handle_reset_prefs(
2570 &self,
2571 parameters: &GetPrefsParameters,
2572 ) -> WebDriverResult<WebDriverResponse> {
2573 let (new_preferences, map) = if parameters.prefs.is_empty() {
2574 (self.default_preferences.clone(), BTreeMap::new())
2575 } else {
2576 let mut new_preferences = prefs::get().clone();
2578 for key in parameters.prefs.iter() {
2579 new_preferences.set_value(key, self.default_preferences.get_value(key))
2580 }
2581
2582 let map = parameters
2583 .prefs
2584 .iter()
2585 .map(|item| (item.clone(), new_preferences.get_value(item)))
2586 .collect::<BTreeMap<_, _>>();
2587
2588 (new_preferences, map)
2589 };
2590
2591 prefs::set(new_preferences);
2592
2593 Ok(WebDriverResponse::Generic(ValueResponse(
2594 serde_json::to_value(map)?,
2595 )))
2596 }
2597
2598 fn handle_shutdown(&self) -> WebDriverResult<WebDriverResponse> {
2599 self.send_message_to_embedder(WebDriverCommandMsg::Shutdown)?;
2600 Ok(WebDriverResponse::Void)
2601 }
2602
2603 fn handle_reset_all_cookies(&self) -> WebDriverResult<WebDriverResponse> {
2604 let (sender, receiver) = unbounded();
2605 self.send_message_to_embedder(WebDriverCommandMsg::ResetAllCookies(sender))?;
2606 if receiver.recv().is_err() {
2607 log::warn!("Communication failure while clearing cookies; status unknown");
2608 }
2609 Ok(WebDriverResponse::Void)
2610 }
2611
2612 fn verify_top_level_browsing_context_is_open(
2613 &self,
2614 webview_id: WebViewId,
2615 ) -> Result<(), WebDriverError> {
2616 let (sender, receiver) = generic_channel::oneshot().unwrap();
2617 self.send_message_to_embedder(WebDriverCommandMsg::IsWebViewOpen(webview_id, sender))?;
2618 if wait_for_oneshot_response(receiver)? {
2619 Ok(())
2620 } else {
2621 Err(WebDriverError::new(ErrorStatus::NoSuchWindow, ""))
2622 }
2623 }
2624
2625 fn verify_browsing_context_is_open(
2626 &self,
2627 browsing_context_id: BrowsingContextId,
2628 ) -> Result<(), WebDriverError> {
2629 let (sender, receiver) = generic_channel::oneshot().unwrap();
2630 self.send_message_to_embedder(WebDriverCommandMsg::IsBrowsingContextOpen(
2631 browsing_context_id,
2632 sender,
2633 ))?;
2634 if !receiver.recv().unwrap_or(false) {
2635 Err(WebDriverError::new(
2636 ErrorStatus::NoSuchWindow,
2637 "No such window",
2638 ))
2639 } else {
2640 Ok(())
2641 }
2642 }
2643
2644 fn wait_until_browsing_context_is_open(
2645 &self,
2646 browsing_context_id: BrowsingContextId,
2647 ) -> WebDriverResult<()> {
2648 const OPEN_BROWSING_CONTEXT_TIMEOUT: Duration =
2651 Duration::from_millis(DEFAULT_PAGE_LOAD_TIMEOUT);
2652 let now = Instant::now();
2653 let timeouts = self.session()?.session_timeouts();
2654
2655 let sleep_interval = Duration::from_millis(timeouts.sleep_interval);
2656
2657 while now.elapsed() < OPEN_BROWSING_CONTEXT_TIMEOUT {
2658 if self
2659 .verify_browsing_context_is_open(browsing_context_id)
2660 .is_ok()
2661 {
2662 return Ok(());
2663 }
2664
2665 sleep(sleep_interval);
2666 }
2667 Err(WebDriverError::new(
2668 ErrorStatus::Timeout,
2669 format!(
2670 "Timed out waiting for the top-level browsing context {browsing_context_id} to be ready"
2671 ),
2672 ))
2673 }
2674
2675 fn focus_webview(&self, webview_id: WebViewId) -> WebDriverResult<()> {
2676 self.send_message_to_embedder(WebDriverCommandMsg::FocusWebView(webview_id))
2677 }
2678
2679 fn focus_browsing_context(&self, browsing_cotext_id: BrowsingContextId) -> WebDriverResult<()> {
2680 self.send_message_to_embedder(WebDriverCommandMsg::FocusBrowsingContext(
2681 browsing_cotext_id,
2682 ))
2683 }
2684}
2685
2686impl WebDriverHandler<ServoExtensionRoute> for Handler {
2687 fn handle_command(
2688 &mut self,
2689 _session: &Option<Session>,
2690 msg: WebDriverMessage<ServoExtensionRoute>,
2691 ) -> WebDriverResult<WebDriverResponse> {
2692 info!("{:?}", msg.command);
2693
2694 while self.load_status_receiver.try_recv().is_ok() {}
2696
2697 match msg.command {
2700 WebDriverCommand::NewSession(_) |
2701 WebDriverCommand::Status |
2702 WebDriverCommand::DeleteSession |
2703 WebDriverCommand::Extension(ServoExtensionCommand::Shutdown) |
2704 WebDriverCommand::Extension(ServoExtensionCommand::ResetAllCookies) => {},
2705 _ => {
2706 self.session()?;
2707 },
2708 }
2709
2710 match msg.command {
2711 WebDriverCommand::NewSession(ref parameters) => self.handle_new_session(parameters),
2712 WebDriverCommand::DeleteSession => self.handle_delete_session(),
2713 WebDriverCommand::Status => self.handle_status(),
2714 WebDriverCommand::AddCookie(ref parameters) => self.handle_add_cookie(parameters),
2715 WebDriverCommand::Get(ref parameters) => self.handle_get(parameters),
2716 WebDriverCommand::GetCurrentUrl => self.handle_current_url(),
2717 WebDriverCommand::GetWindowRect => {
2718 self.handle_window_rect(VerifyBrowsingContextIsOpen::Yes)
2719 },
2720 WebDriverCommand::SetWindowRect(ref size) => self.handle_set_window_rect(size),
2721 WebDriverCommand::IsEnabled(ref element) => self.handle_is_enabled(element),
2722 WebDriverCommand::IsSelected(ref element) => self.handle_is_selected(element),
2723 WebDriverCommand::GoBack => self.handle_go_back(),
2724 WebDriverCommand::GoForward => self.handle_go_forward(),
2725 WebDriverCommand::Refresh => self.handle_refresh(),
2726 WebDriverCommand::GetTitle => self.handle_title(),
2727 WebDriverCommand::GetWindowHandle => self.handle_window_handle(),
2728 WebDriverCommand::GetWindowHandles => self.handle_window_handles(),
2729 WebDriverCommand::NewWindow(ref parameters) => self.handle_new_window(parameters),
2730 WebDriverCommand::CloseWindow => self.handle_close_window(),
2731 WebDriverCommand::MaximizeWindow => self.handle_maximize_window(),
2732 WebDriverCommand::SwitchToFrame(ref parameters) => {
2733 self.handle_switch_to_frame(parameters)
2734 },
2735 WebDriverCommand::SwitchToParentFrame => self.handle_switch_to_parent_frame(),
2736 WebDriverCommand::SwitchToWindow(ref parameters) => {
2737 self.handle_switch_to_window(parameters)
2738 },
2739 WebDriverCommand::FindElement(ref parameters) => self.handle_find_element(parameters),
2740 WebDriverCommand::FindElements(ref parameters) => self.handle_find_elements(parameters),
2741 WebDriverCommand::FindElementElement(ref element, ref parameters) => {
2742 self.handle_find_element_from_element(element, parameters)
2743 },
2744 WebDriverCommand::FindElementElements(ref element, ref parameters) => {
2745 self.handle_find_elements_from_element(element, parameters)
2746 },
2747 WebDriverCommand::FindShadowRootElements(ref shadow_root, ref parameters) => {
2748 self.handle_find_elements_from_shadow_root(shadow_root, parameters)
2749 },
2750 WebDriverCommand::FindShadowRootElement(ref shadow_root, ref parameters) => {
2751 self.handle_find_element_from_shadow_root(shadow_root, parameters)
2752 },
2753 WebDriverCommand::GetShadowRoot(element) => self.handle_get_shadow_root(element),
2754 WebDriverCommand::GetNamedCookie(name) => self.handle_get_cookie(name),
2755 WebDriverCommand::GetCookies => self.handle_get_cookies(),
2756 WebDriverCommand::GetActiveElement => self.handle_active_element(),
2757 WebDriverCommand::GetComputedRole(ref element) => self.handle_computed_role(element),
2758 WebDriverCommand::GetElementRect(ref element) => self.handle_element_rect(element),
2759 WebDriverCommand::GetElementText(ref element) => self.handle_element_text(element),
2760 WebDriverCommand::GetElementTagName(ref element) => {
2761 self.handle_element_tag_name(element)
2762 },
2763 WebDriverCommand::GetElementAttribute(ref element, ref name) => {
2764 self.handle_element_attribute(element, name)
2765 },
2766 WebDriverCommand::GetElementProperty(ref element, ref name) => {
2767 self.handle_element_property(element, name)
2768 },
2769 WebDriverCommand::GetCSSValue(ref element, ref name) => {
2770 self.handle_element_css(element, name)
2771 },
2772 WebDriverCommand::GetPageSource => self.handle_get_page_source(),
2773 WebDriverCommand::PerformActions(actions_parameters) => {
2774 self.handle_perform_actions(actions_parameters)
2775 },
2776 WebDriverCommand::ReleaseActions => self.handle_release_actions(),
2777 WebDriverCommand::ExecuteScript(x) => self.handle_execute_script(x),
2778 WebDriverCommand::ExecuteAsyncScript(x) => self.handle_execute_async_script(x),
2779 WebDriverCommand::ElementSendKeys(ref element, ref keys) => {
2780 self.handle_element_send_keys(element, keys)
2781 },
2782 WebDriverCommand::ElementClear(ref element) => self.handle_element_clear(element),
2783 WebDriverCommand::ElementClick(ref element) => self.handle_element_click(element),
2784 WebDriverCommand::DismissAlert => self.handle_dismiss_alert(),
2785 WebDriverCommand::AcceptAlert => self.handle_accept_alert(),
2786 WebDriverCommand::GetAlertText => self.handle_get_alert_text(),
2787 WebDriverCommand::SendAlertText(text) => self.handle_send_alert_text(text.text),
2788 WebDriverCommand::DeleteCookies => self.handle_delete_cookies(),
2789 WebDriverCommand::DeleteCookie(name) => self.handle_delete_cookie(name),
2790 WebDriverCommand::GetTimeouts => self.handle_get_timeouts(),
2791 WebDriverCommand::SetTimeouts(ref x) => self.handle_set_timeouts(x),
2792 WebDriverCommand::TakeScreenshot => self.handle_take_screenshot(),
2793 WebDriverCommand::TakeElementScreenshot(ref x) => {
2794 self.handle_take_element_screenshot(x)
2795 },
2796 WebDriverCommand::Extension(extension) => match extension {
2797 ServoExtensionCommand::GetPrefs(ref x) => self.handle_get_prefs(x),
2798 ServoExtensionCommand::SetPrefs(ref x) => self.handle_set_prefs(x),
2799 ServoExtensionCommand::ResetPrefs(ref x) => self.handle_reset_prefs(x),
2800 ServoExtensionCommand::CustomHandlersSetMode(ref x) => {
2801 self.handle_custom_handlers_set_mode(x)
2802 },
2803 ServoExtensionCommand::Shutdown => self.handle_shutdown(),
2804 ServoExtensionCommand::ResetAllCookies => self.handle_reset_all_cookies(),
2805 },
2806 _ => Err(WebDriverError::new(
2807 ErrorStatus::UnsupportedOperation,
2808 format!("Command not implemented: {:?}", msg.command),
2809 )),
2810 }
2811 }
2812
2813 fn teardown_session(&mut self, _session: SessionTeardownKind) {
2814 self.session = None;
2815 }
2816}
2817
2818fn wait_for_oneshot_response<T>(
2819 receiver: generic_channel::GenericOneshotReceiver<T>,
2820) -> Result<T, WebDriverError>
2821where
2822 T: for<'de> Deserialize<'de> + Serialize,
2823{
2824 receiver
2825 .recv()
2826 .map_err(|_| WebDriverError::new(ErrorStatus::NoSuchWindow, ""))
2827}
2828
2829fn wait_for_ipc_response<T>(receiver: GenericReceiver<T>) -> Result<T, WebDriverError>
2830where
2831 T: for<'de> Deserialize<'de> + Serialize,
2832{
2833 receiver
2834 .recv()
2835 .map_err(|_| WebDriverError::new(ErrorStatus::NoSuchWindow, ""))
2836}
2837
2838fn wait_for_ipc_response_flatten<T>(
2841 receiver: GenericReceiver<Result<T, ErrorStatus>>,
2842) -> Result<T, WebDriverError>
2843where
2844 T: for<'de> Deserialize<'de> + Serialize,
2845{
2846 match receiver.recv() {
2847 Ok(Ok(value)) => Ok(value),
2848 Ok(Err(error_status)) => Err(WebDriverError::new(error_status, "")),
2849 Err(_) => Err(WebDriverError::new(ErrorStatus::NoSuchWindow, "")),
2850 }
2851}
2852
2853fn wait_for_script_ipc_response_with_timeout<T>(
2854 receiver: GenericReceiver<T>,
2855 timeout: Duration,
2856) -> Result<T, WebDriverError>
2857where
2858 T: for<'de> Deserialize<'de> + Serialize,
2859{
2860 receiver
2861 .try_recv_timeout(timeout)
2862 .map_err(|error| match error {
2863 generic_channel::TryReceiveError::ReceiveError(_) => {
2864 WebDriverError::new(ErrorStatus::NoSuchWindow, "")
2865 },
2866 generic_channel::TryReceiveError::Empty => {
2867 WebDriverError::new(ErrorStatus::ScriptTimeout, "")
2868 },
2869 })
2870}
2871
2872fn unwrap_first_element_response(res: WebDriverResponse) -> WebDriverResult<WebDriverResponse> {
2873 if let WebDriverResponse::Generic(ValueResponse(values)) = res {
2874 let arr = values.as_array().unwrap();
2875 if let Some(first) = arr.first() {
2876 Ok(WebDriverResponse::Generic(ValueResponse(first.clone())))
2877 } else {
2878 Err(WebDriverError::new(ErrorStatus::NoSuchElement, ""))
2879 }
2880 } else {
2881 unreachable!()
2882 }
2883}
2884
2885fn convert_keyboard_event_to_string(event: &KeyboardEvent) -> String {
2886 let key = &event.key;
2887 let named_key = match key {
2888 Key::Character(s) => return s.to_string(),
2889 Key::Named(named_key) => named_key,
2890 };
2891
2892 match event.location {
2893 Location::Left | Location::Standard => match named_key {
2894 NamedKey::Unidentified => '\u{E000}'.to_string(),
2895 NamedKey::Cancel => '\u{E001}'.to_string(),
2896 NamedKey::Help => '\u{E002}'.to_string(),
2897 NamedKey::Backspace => '\u{E003}'.to_string(),
2898 NamedKey::Tab => '\u{E004}'.to_string(),
2899 NamedKey::Clear => '\u{E005}'.to_string(),
2900 NamedKey::Enter => match event.code {
2901 Code::NumpadEnter => '\u{E007}'.to_string(),
2902 _ => '\u{E006}'.to_string(),
2903 },
2904 NamedKey::Shift => '\u{E008}'.to_string(),
2905 NamedKey::Control => '\u{E009}'.to_string(),
2906 NamedKey::Alt => '\u{E00A}'.to_string(),
2907 NamedKey::Pause => '\u{E00B}'.to_string(),
2908 NamedKey::Escape => '\u{E00C}'.to_string(),
2909 NamedKey::PageUp => '\u{E00E}'.to_string(),
2910 NamedKey::PageDown => '\u{E00F}'.to_string(),
2911 NamedKey::End => '\u{E010}'.to_string(),
2912 NamedKey::Home => '\u{E011}'.to_string(),
2913 NamedKey::ArrowLeft => '\u{E012}'.to_string(),
2914 NamedKey::ArrowUp => '\u{E013}'.to_string(),
2915 NamedKey::ArrowRight => '\u{E014}'.to_string(),
2916 NamedKey::ArrowDown => '\u{E015}'.to_string(),
2917 NamedKey::Insert => '\u{E016}'.to_string(),
2918 NamedKey::Delete => '\u{E017}'.to_string(),
2919 NamedKey::F1 => '\u{E031}'.to_string(),
2920 NamedKey::F2 => '\u{E032}'.to_string(),
2921 NamedKey::F3 => '\u{E033}'.to_string(),
2922 NamedKey::F4 => '\u{E034}'.to_string(),
2923 NamedKey::F5 => '\u{E035}'.to_string(),
2924 NamedKey::F6 => '\u{E036}'.to_string(),
2925 NamedKey::F7 => '\u{E037}'.to_string(),
2926 NamedKey::F8 => '\u{E038}'.to_string(),
2927 NamedKey::F9 => '\u{E039}'.to_string(),
2928 NamedKey::F10 => '\u{E03A}'.to_string(),
2929 NamedKey::F11 => '\u{E03B}'.to_string(),
2930 NamedKey::F12 => '\u{E03C}'.to_string(),
2931 NamedKey::Meta => '\u{E03D}'.to_string(),
2932 NamedKey::ZenkakuHankaku => '\u{E040}'.to_string(),
2933 _ => {
2934 error!("Unexpected NamedKey on send_keys");
2935 '\u{E000}'.to_string()
2936 },
2937 },
2938 Location::Right | Location::Numpad => match named_key {
2939 NamedKey::Shift => '\u{E050}'.to_string(),
2940 NamedKey::Control => '\u{E051}'.to_string(),
2941 NamedKey::Alt => '\u{E052}'.to_string(),
2942 NamedKey::Meta => '\u{E053}'.to_string(),
2943 NamedKey::PageUp => '\u{E054}'.to_string(),
2944 NamedKey::PageDown => '\u{E055}'.to_string(),
2945 NamedKey::End => '\u{E056}'.to_string(),
2946 NamedKey::Home => '\u{E057}'.to_string(),
2947 NamedKey::ArrowLeft => '\u{E058}'.to_string(),
2948 NamedKey::ArrowUp => '\u{E059}'.to_string(),
2949 NamedKey::ArrowRight => '\u{E05A}'.to_string(),
2950 NamedKey::ArrowDown => '\u{E05B}'.to_string(),
2951 NamedKey::Insert => '\u{E05C}'.to_string(),
2952 NamedKey::Delete => '\u{E05D}'.to_string(),
2953 _ => {
2954 error!("Unexpected NamedKey on send_keys");
2955 '\u{E000}'.to_string()
2956 },
2957 },
2958 }
2959}