1use cookie::SameSite;
4use serde::{Deserialize, Serialize};
5use std::convert::{TryFrom, TryInto};
6use time::OffsetDateTime;
7use webdriver::command::{AddCookieParameters, WebDriverCommand};
8use webdriver::common::Date;
9
10use crate::client::Client;
11use crate::error;
12
13pub type Cookie<'a> = cookie::Cookie<'a>;
15
16#[derive(Debug, Serialize)]
18pub(crate) struct AddCookieParametersWrapper<'a> {
19 #[serde(with = "AddCookieParameters")]
21 pub(crate) cookie: &'a AddCookieParameters,
22}
23
24#[derive(Debug, Deserialize, Serialize)]
26pub(crate) struct WebDriverCookie {
27 name: String,
28 value: String,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 path: Option<String>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 domain: Option<String>,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 secure: Option<bool>,
35 #[serde(skip_serializing_if = "Option::is_none", rename = "httpOnly")]
36 http_only: Option<bool>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 expiry: Option<u64>,
39 #[serde(skip_serializing_if = "Option::is_none", rename = "sameSite")]
40 same_site: Option<String>,
41}
42
43impl WebDriverCookie {
44 fn into_params(self) -> AddCookieParameters {
45 AddCookieParameters {
46 name: self.name,
47 value: self.value,
48 path: self.path,
49 domain: self.domain,
50 secure: self.secure.unwrap_or_default(),
51 httpOnly: self.http_only.unwrap_or_default(),
52 expiry: self.expiry.map(Date),
53 sameSite: self.same_site,
54 }
55 }
56}
57
58impl TryFrom<WebDriverCookie> for Cookie<'static> {
59 type Error = error::CmdError;
60
61 fn try_from(webdriver_cookie: WebDriverCookie) -> Result<Self, Self::Error> {
62 let mut cookie = cookie::Cookie::new(webdriver_cookie.name, webdriver_cookie.value);
63
64 if let Some(path) = webdriver_cookie.path {
65 cookie.set_path(path);
66 }
67
68 if let Some(domain) = webdriver_cookie.domain {
69 cookie.set_domain(domain);
70 }
71
72 if let Some(secure) = webdriver_cookie.secure {
73 cookie.set_secure(secure);
74 }
75
76 if let Some(http_only) = webdriver_cookie.http_only {
77 cookie.set_http_only(http_only);
78 }
79
80 if let Some(expiry) = webdriver_cookie.expiry {
81 let dt = OffsetDateTime::from_unix_timestamp(expiry as i64).ok();
82 cookie.set_expires(dt);
83 }
84
85 if let Some(same_site) = webdriver_cookie.same_site {
86 cookie.set_same_site(match &same_site {
87 x if x.eq_ignore_ascii_case("strict") => SameSite::Strict,
88 x if x.eq_ignore_ascii_case("lax") => SameSite::Lax,
89 x if x.eq_ignore_ascii_case("none") => SameSite::None,
90 _ => {
91 return Err(error::CmdError::InvalidArgument(
92 "same_site".to_string(),
93 same_site,
94 ))
95 }
96 });
97 }
98
99 Ok(cookie)
100 }
101}
102
103impl<'a> From<Cookie<'a>> for WebDriverCookie {
104 fn from(cookie: Cookie<'a>) -> Self {
105 let name = cookie.name().to_string();
106 let value = cookie.value().to_string();
107 let path = cookie.path().map(String::from);
108 let domain = cookie.domain().map(String::from);
109 let secure = cookie.secure();
110 let http_only = cookie.http_only();
111 let expiry = cookie
112 .expires()
113 .and_then(|e| e.datetime().map(|dt| dt.unix_timestamp() as u64));
114 let same_site = Some(match cookie.same_site() {
115 Some(x) => match x {
116 SameSite::Strict => "Strict".to_string(),
117 SameSite::Lax => "Lax".to_string(),
118 SameSite::None => "None".to_string(),
119 },
120 None => "None".to_string(),
121 });
122
123 Self {
124 name,
125 value,
126 path,
127 domain,
128 secure,
129 http_only,
130 expiry,
131 same_site,
132 }
133 }
134}
135
136impl Client {
138 pub async fn get_all_cookies(&self) -> Result<Vec<Cookie<'static>>, error::CmdError> {
143 let resp = self.issue(WebDriverCommand::GetCookies).await?;
144
145 let webdriver_cookies: Vec<WebDriverCookie> = serde_json::from_value(resp)?;
146 webdriver_cookies
147 .into_iter()
148 .map(|raw_cookie| raw_cookie.try_into())
149 .collect()
150 }
151
152 pub async fn get_named_cookie(&self, name: &str) -> Result<Cookie<'static>, error::CmdError> {
157 let resp = self
158 .issue(WebDriverCommand::GetNamedCookie(name.to_string()))
159 .await?;
160 let webdriver_cookie: WebDriverCookie = serde_json::from_value(resp)?;
161 webdriver_cookie.try_into()
162 }
163
164 pub async fn add_cookie(&self, cookie: Cookie<'static>) -> Result<(), error::CmdError> {
169 let webdriver_cookie: WebDriverCookie = cookie.into();
170 self.issue(WebDriverCommand::AddCookie(webdriver_cookie.into_params()))
171 .await?;
172 Ok(())
173 }
174
175 pub async fn delete_cookie(&self, name: &str) -> Result<(), error::CmdError> {
180 self.issue(WebDriverCommand::DeleteCookie(name.to_string()))
181 .await
182 .map(|_| ())
183 }
184
185 pub async fn delete_all_cookies(&self) -> Result<(), error::CmdError> {
190 self.issue(WebDriverCommand::DeleteCookies)
191 .await
192 .map(|_| ())
193 }
194}