use std::sync::{Mutex, MutexGuard};
use cookie::{Cookie, CookieJar as RawCookieJar};
use http::{HeaderValue, header, request::Parts};
use topcoat_core::context::{Cx, request_context};
use crate::Cookies;
#[derive(Debug)]
pub struct CookieJar {
jar: Mutex<RawCookieJar>,
}
impl CookieJar {
pub(crate) fn from_request(cx: &Cx) -> Self {
let mut jar = RawCookieJar::new();
let parts = request_context::<Parts>(cx);
for value in parts.headers.get_all(header::COOKIE) {
let Ok(raw) = value.to_str() else { continue };
for cookie in Cookie::split_parse_encoded(raw.to_owned()).flatten() {
jar.add_original(cookie);
}
}
Self {
jar: Mutex::new(jar),
}
}
fn lock(&self) -> MutexGuard<'_, RawCookieJar> {
self.jar
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
pub(crate) fn delta_headers(&self) -> Vec<HeaderValue> {
self.lock()
.delta()
.filter_map(|cookie| HeaderValue::from_str(&cookie.encoded().to_string()).ok())
.collect()
}
}
impl Cookies for &CookieJar {
fn get(&self, name: &str) -> Option<Cookie<'static>> {
self.lock().get(name).cloned()
}
fn add<C: Into<Cookie<'static>>>(&self, cookie: C) {
self.lock().add(cookie.into());
}
fn remove<C: Into<Cookie<'static>>>(&self, cookie: C) {
self.lock().remove(cookie.into());
}
}