use std::sync::Arc;
use reqwest::cookie::{CookieStore, Jar};
use reqwest::header::HeaderValue;
use tracing::debug;
use crate::context::Cookie;
pub fn sync_to_jar(cookies: &[Cookie], jar: &Arc<Jar>) {
for cookie in cookies {
let url = cookie_to_url(cookie);
if let Ok(parsed_url) = url::Url::parse(&url) {
let cookie_str = cookie_to_string(cookie);
if let Ok(header_value) = HeaderValue::from_str(&cookie_str) {
let headers = [header_value];
jar.set_cookies(&mut headers.iter(), &parsed_url);
debug!("Synced cookie {} to API jar for {}", cookie.name, url);
}
}
}
}
fn cookie_to_url(cookie: &Cookie) -> String {
if let Some(ref url) = cookie.url {
return url.clone();
}
let scheme = if cookie.secure.unwrap_or(false) {
"https"
} else {
"http"
};
let domain = cookie.domain.as_deref().unwrap_or("localhost");
let domain = domain.trim_start_matches('.');
let path = cookie.path.as_deref().unwrap_or("/");
format!("{scheme}://{domain}{path}")
}
fn cookie_to_string(cookie: &Cookie) -> String {
let mut parts = vec![format!("{}={}", cookie.name, cookie.value)];
if let Some(ref domain) = cookie.domain {
parts.push(format!("Domain={domain}"));
}
if let Some(ref path) = cookie.path {
parts.push(format!("Path={path}"));
}
if cookie.secure.unwrap_or(false) {
parts.push("Secure".to_string());
}
if cookie.http_only.unwrap_or(false) {
parts.push("HttpOnly".to_string());
}
if let Some(same_site) = &cookie.same_site {
parts.push(format!(
"SameSite={}",
match same_site {
crate::context::SameSite::Strict => "Strict",
crate::context::SameSite::Lax => "Lax",
crate::context::SameSite::None => "None",
}
));
}
if let Some(expires) = cookie.expires {
if let Some(dt) = chrono::DateTime::from_timestamp(expires as i64, 0) {
parts.push(format!(
"Expires={}",
dt.format("%a, %d %b %Y %H:%M:%S GMT")
));
}
}
parts.join("; ")
}
pub fn extract_from_jar(jar: &Arc<Jar>, url: &str) -> Vec<Cookie> {
let mut cookies = Vec::new();
if let Ok(parsed_url) = url::Url::parse(url) {
if let Some(cookie_header) = jar.cookies(&parsed_url) {
let header_str = cookie_header.to_str().unwrap_or("");
for cookie_str in header_str.split("; ") {
if let Some((name, value)) = cookie_str.split_once('=') {
cookies.push(Cookie {
name: name.to_string(),
value: value.to_string(),
domain: parsed_url.host_str().map(String::from),
path: Some(parsed_url.path().to_string()),
url: Some(url.to_string()),
expires: None,
http_only: None,
secure: Some(parsed_url.scheme() == "https"),
same_site: None,
});
}
}
}
}
cookies
}
#[cfg(test)]
mod tests;