use crate::browser::views::{Cookie, CookieParam};
use crate::error::{BrowsingError, Result};
use serde_json::Value;
use std::sync::Arc;
pub struct CookieManager {
client: Arc<crate::browser::cdp::CdpClient>,
}
impl CookieManager {
pub fn new(client: Arc<crate::browser::cdp::CdpClient>) -> Self {
Self { client }
}
pub async fn get_cookies(&self) -> Result<Vec<Cookie>> {
let result = self
.client
.send_command("Network.getCookies", serde_json::json!({}))
.await?;
let cookies = result
.get("cookies")
.and_then(|v| v.as_array())
.ok_or_else(|| BrowsingError::Browser("No cookies array in response".to_string()))?;
cookies
.iter()
.map(parse_cookie)
.collect()
}
pub async fn get_cookies_for_url(&self, url: &str) -> Result<Vec<Cookie>> {
let result = self
.client
.send_command(
"Network.getCookies",
serde_json::json!({ "urls": [url] }),
)
.await?;
let cookies = result
.get("cookies")
.and_then(|v| v.as_array())
.ok_or_else(|| BrowsingError::Browser("No cookies array in response".to_string()))?;
cookies
.iter()
.map(parse_cookie)
.collect()
}
pub async fn set_cookie(&self, param: &CookieParam) -> Result<()> {
let mut params = serde_json::json!({
"name": param.name,
"value": param.value,
});
if let Some(url) = ¶m.url {
params["url"] = serde_json::json!(url);
}
if let Some(domain) = ¶m.domain {
params["domain"] = serde_json::json!(domain);
}
if let Some(path) = ¶m.path {
params["path"] = serde_json::json!(path);
}
if let Some(secure) = param.secure {
params["secure"] = serde_json::json!(secure);
}
if let Some(http_only) = param.http_only {
params["httpOnly"] = serde_json::json!(http_only);
}
if let Some(expires) = param.expires {
params["expires"] = serde_json::json!(expires);
}
if let Some(same_site) = ¶m.same_site {
params["sameSite"] = serde_json::json!(same_site);
}
self.client
.send_command("Network.setCookie", params)
.await?;
Ok(())
}
pub async fn delete_cookies(&self, name: &str, url: Option<&str>, domain: Option<&str>, path: Option<&str>) -> Result<()> {
let mut params = serde_json::json!({ "name": name });
if let Some(url) = url {
params["url"] = serde_json::json!(url);
}
if let Some(domain) = domain {
params["domain"] = serde_json::json!(domain);
}
if let Some(path) = path {
params["path"] = serde_json::json!(path);
}
self.client
.send_command("Network.deleteCookies", params)
.await?;
Ok(())
}
pub async fn clear_cookies(&self) -> Result<()> {
self.client
.send_command("Network.clearBrowserCookies", serde_json::json!({}))
.await?;
Ok(())
}
}
fn parse_cookie(value: &Value) -> Result<Cookie> {
let name = value
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let cookie_value = value
.get("value")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let domain = value
.get("domain")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let path = value
.get("path")
.and_then(|v| v.as_str())
.unwrap_or("/")
.to_string();
let secure = value
.get("secure")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let http_only = value
.get("httpOnly")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let expires = value.get("expires").and_then(|v| v.as_f64());
let same_site = value
.get("sameSite")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
Ok(Cookie {
name,
value: cookie_value,
domain,
path,
secure,
http_only,
expires,
same_site,
size: None,
third_party: None,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_cookie() {
let json = serde_json::json!({
"name": "session_id",
"value": "abc123",
"domain": ".example.com",
"path": "/",
"secure": true,
"httpOnly": true,
"expires": 1893456000.0,
"sameSite": "Lax"
});
let cookie = parse_cookie(&json).unwrap();
assert_eq!(cookie.name, "session_id");
assert_eq!(cookie.value, "abc123");
assert_eq!(cookie.domain, ".example.com");
assert_eq!(cookie.path, "/");
assert!(cookie.secure);
assert!(cookie.http_only);
assert_eq!(cookie.expires, Some(1893456000.0));
assert_eq!(cookie.same_site, Some("Lax".to_string()));
}
#[test]
fn test_parse_cookie_minimal() {
let json = serde_json::json!({
"name": "test",
"value": "val"
});
let cookie = parse_cookie(&json).unwrap();
assert_eq!(cookie.name, "test");
assert_eq!(cookie.value, "val");
assert_eq!(cookie.domain, "");
assert_eq!(cookie.path, "/");
assert!(!cookie.secure);
assert!(!cookie.http_only);
assert!(cookie.expires.is_none());
assert!(cookie.same_site.is_none());
}
#[test]
fn test_cookie_param_default() {
let param = CookieParam {
name: "foo".to_string(),
value: "bar".to_string(),
..Default::default()
};
assert_eq!(param.name, "foo");
assert_eq!(param.value, "bar");
assert!(param.domain.is_none());
assert!(param.path.is_none());
}
}