Skip to main content

browser_automation_cli/native/
cookies.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Cookie read/write helpers over CDP Network domain.
3//!
4//! # Workload
5//!
6//! **I/O-bound single session:** list/set/clear are one CDP command each
7//! (batch set via `Network.setCookies`). No multi-item fan-out; cookie vectors
8//! are owned by one browser session (sequential_justified N-138).
9#![allow(missing_docs)]
10use serde::{Deserialize, Serialize};
11use serde_json::{json, Value};
12
13use super::cdp::client::CdpClient;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct Cookie {
18    pub name: String,
19    pub value: String,
20    pub domain: String,
21    pub path: String,
22    #[serde(default)]
23    pub expires: f64,
24    #[serde(default)]
25    pub size: i64,
26    #[serde(default)]
27    pub http_only: bool,
28    #[serde(default)]
29    pub secure: bool,
30    #[serde(default)]
31    pub session: bool,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub same_site: Option<String>,
34}
35
36pub async fn get_all_cookies(client: &CdpClient, session_id: &str) -> Result<Vec<Cookie>, String> {
37    let result = client
38        .send_command_no_params("Network.getAllCookies", Some(session_id))
39        .await?;
40
41    let cookies: Vec<Cookie> = result
42        .get("cookies")
43        .and_then(|v| serde_json::from_value(v.clone()).ok())
44        .unwrap_or_default();
45
46    Ok(cookies)
47}
48
49pub async fn get_cookies(
50    client: &CdpClient,
51    session_id: &str,
52    urls: Option<Vec<String>>,
53) -> Result<Vec<Cookie>, String> {
54    let params = match urls {
55        Some(ref u) if !u.is_empty() => json!({ "urls": u }),
56        _ => json!({}),
57    };
58
59    let result = client
60        .send_command("Network.getCookies", Some(params), Some(session_id))
61        .await?;
62
63    let cookies: Vec<Cookie> = result
64        .get("cookies")
65        .and_then(|v| serde_json::from_value(v.clone()).ok())
66        .unwrap_or_default();
67
68    Ok(cookies)
69}
70
71pub async fn set_cookies(
72    client: &CdpClient,
73    session_id: &str,
74    cookies: Vec<Value>,
75    current_url: Option<&str>,
76) -> Result<(), String> {
77    let cookies: Vec<Value> = cookies
78        .into_iter()
79        .map(|mut c| {
80            // Auto-fill url if no domain/path/url provided
81            if c.get("url").is_none() && c.get("domain").is_none() {
82                if let Some(url) = current_url {
83                    if let Some(m) = c.as_object_mut() {
84                        m.insert("url".to_string(), Value::String(url.to_string()));
85                    }
86                }
87            }
88            c
89        })
90        .collect();
91
92    client
93        .send_command(
94            "Network.setCookies",
95            Some(json!({ "cookies": cookies })),
96            Some(session_id),
97        )
98        .await?;
99
100    Ok(())
101}
102
103pub async fn clear_cookies(client: &CdpClient, session_id: &str) -> Result<(), String> {
104    client
105        .send_command_no_params("Network.clearBrowserCookies", Some(session_id))
106        .await?;
107    Ok(())
108}