mod jar;
mod store;
use std::{convert::TryInto, fmt, sync::Arc, time::SystemTime};
use cookie::{Cookie as RawCookie, Expiration, SameSite};
use http::{Uri, Version};
pub use self::jar::Jar;
use crate::{error::Error, header::HeaderValue};
#[derive(Debug, Clone)]
pub struct Cookie<'a>(RawCookie<'a>);
impl<'a> Cookie<'a> {
pub(crate) fn parse(value: &'a HeaderValue) -> crate::Result<Cookie<'a>> {
std::str::from_utf8(value.as_bytes())
.map_err(cookie::ParseError::from)
.and_then(cookie::Cookie::parse)
.map_err(Error::decode)
.map(Cookie)
}
#[inline]
pub fn name(&self) -> &str {
self.0.name()
}
#[inline]
pub fn value(&self) -> &str {
self.0.value()
}
#[inline]
pub fn http_only(&self) -> bool {
self.0.http_only().unwrap_or(false)
}
#[inline]
pub fn secure(&self) -> bool {
self.0.secure().unwrap_or(false)
}
#[inline]
pub fn same_site_lax(&self) -> bool {
self.0.same_site() == Some(SameSite::Lax)
}
#[inline]
pub fn same_site_strict(&self) -> bool {
self.0.same_site() == Some(SameSite::Strict)
}
#[inline]
pub fn path(&self) -> Option<&str> {
self.0.path()
}
#[inline]
pub fn domain(&self) -> Option<&str> {
self.0.domain()
}
#[inline]
pub fn max_age(&self) -> Option<std::time::Duration> {
self.0.max_age().and_then(|d| d.try_into().ok())
}
#[inline]
pub fn expires(&self) -> Option<SystemTime> {
match self.0.expires() {
Some(Expiration::DateTime(offset)) => Some(SystemTime::from(offset)),
None | Some(Expiration::Session) => None,
}
}
#[inline]
pub fn into_owned(self) -> Cookie<'static> {
Cookie(self.0.into_owned())
}
}
impl fmt::Display for Cookie<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'c> From<RawCookie<'c>> for Cookie<'c> {
#[inline]
fn from(cookie: RawCookie<'c>) -> Cookie<'c> {
Cookie(cookie)
}
}
impl<'c> From<Cookie<'c>> for RawCookie<'c> {
#[inline]
fn from(cookie: Cookie<'c>) -> RawCookie<'c> {
cookie.0
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Cookies {
Compressed(HeaderValue),
Uncompressed(Vec<HeaderValue>),
Empty,
}
pub trait CookieStore: Send + Sync {
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, uri: &Uri);
fn cookies(&self, uri: &Uri, version: Version) -> Cookies;
}
pub trait IntoCookieStore {
fn into_shared(self) -> Arc<dyn CookieStore>;
}
impl IntoCookieStore for Arc<dyn CookieStore> {
#[inline]
fn into_shared(self) -> Arc<dyn CookieStore> {
self
}
}
impl<S: CookieStore + 'static> IntoCookieStore for Arc<S> {
#[inline]
fn into_shared(self) -> Arc<dyn CookieStore> {
self
}
}
impl<S: CookieStore + 'static> IntoCookieStore for S {
#[inline]
fn into_shared(self) -> Arc<dyn CookieStore> {
Arc::new(self)
}
}
impl_request_config_value!(Arc<dyn CookieStore>);
pub trait IntoCookie {
fn into_cookie(self) -> Option<Cookie<'static>>;
}
impl IntoCookie for Cookie<'_> {
#[inline]
fn into_cookie(self) -> Option<Cookie<'static>> {
Some(self.into_owned())
}
}
impl IntoCookie for cookie::Cookie<'_> {
#[inline]
fn into_cookie(self) -> Option<Cookie<'static>> {
Some(Cookie::from(self.into_owned()))
}
}
impl IntoCookie for &str {
#[inline]
fn into_cookie(self) -> Option<Cookie<'static>> {
cookie::Cookie::parse(self)
.map(|cookie| Cookie::from(cookie.into_owned()))
.ok()
}
}
impl IntoCookie for String {
#[inline]
fn into_cookie(self) -> Option<Cookie<'static>> {
cookie::Cookie::parse(self).map(Cookie::from).ok()
}
}