#![allow(clippy::tabs_in_doc_comments)]
pub mod error;
use crate::error::Error;
pub use cookie::{Cookie, CookieJar};
use error::ParseError;
use std::{
fs::File,
io::{BufRead, BufReader},
path::Path,
};
pub use time::OffsetDateTime;
#[derive(Debug, Default)]
pub struct CookieJarBuilder {
jar: CookieJar,
}
impl CookieJarBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_jar(jar: CookieJar) -> Self {
Self { jar }
}
pub fn open(self, path: impl AsRef<Path>) -> Result<Self, Error> {
self.parse_buffer(BufReader::new(File::open(path)?))
}
pub fn parse_buffer(self, mut buf: impl BufRead) -> Result<Self, Error> {
let mut s = String::new();
buf.read_to_string(&mut s)?;
self.parse(&s)
}
pub fn parse(mut self, s: &str) -> Result<Self, Error> {
for c in s.lines().map(|s| s.trim()).filter(|s| !s.is_empty()) {
let (http_only, mut fileds) = if c.starts_with('#') {
if c.starts_with("#HttpOnly_") {
(true, c.trim_start_matches("#HttpOnly_").split('\t'))
} else {
continue;
}
} else {
(false, c.split('\t'))
};
let domain = fileds.next().ok_or(ParseError::TooFewFileds)?;
let _ = fileds.next(); let path = fileds.next().ok_or(ParseError::TooFewFileds)?;
let secure = match fileds.next().ok_or(ParseError::TooFewFileds)? {
"TRUE" => true,
"FALSE" => false,
value => return Err(ParseError::InvaildValue(value.to_owned()).into()),
};
let expiration: i64 = match fileds.next() {
Some(value) => match value.parse() {
Ok(v) => v,
Err(_) => return Err(ParseError::InvaildValue(value.to_owned()).into()),
},
_ => return Err(ParseError::TooFewFileds.into()),
};
let name = fileds.next().ok_or(ParseError::TooFewFileds)?;
let value = fileds.next().ok_or(ParseError::TooFewFileds)?;
let cookie = Cookie::build(name, value)
.domain(domain)
.path(path)
.secure(secure)
.expires(match expiration {
0 => None,
exp => Some(OffsetDateTime::from_unix_timestamp(exp)),
});
let cookie = if http_only {
cookie.http_only(true).finish()
} else {
cookie.finish()
};
self.jar.add(cookie.into_owned());
}
Ok(self)
}
pub fn finish(self) -> CookieJar {
self.jar
}
}
#[inline]
pub fn open(path: impl AsRef<Path>) -> Result<CookieJar, Error> {
CookieJarBuilder::new().open(path).map(|jar| jar.finish())
}
#[inline]
pub fn parse_buffer(buf: impl BufRead) -> Result<CookieJar, Error> {
CookieJarBuilder::new()
.parse_buffer(buf)
.map(|jar| jar.finish())
}
#[inline]
pub fn parse(s: &str) -> Result<CookieJar, Error> {
CookieJarBuilder::new().parse(s).map(|jar| jar.finish())
}