#![allow(unused_imports)]
#![deny(warnings, missing_debug_implementations, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::{
ops::Deref,
sync::{LockResult, Mutex, MutexGuard, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use bytes::Bytes;
pub use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
use reqwest::header::HeaderValue;
#[cfg(feature = "serde")]
use serde_derive::{Deserialize, Serialize};
use url;
fn set_cookies(
cookie_store: &mut CookieStore,
cookie_headers: &mut dyn Iterator<Item = &HeaderValue>,
url: &url::Url,
) {
let cookies = cookie_headers.filter_map(|val| {
std::str::from_utf8(val.as_bytes())
.map_err(RawCookieParseError::from)
.and_then(RawCookie::parse)
.map(|c| c.into_owned())
.ok()
});
cookie_store.store_response_cookies(cookies, url);
}
fn cookies(cookie_store: &CookieStore, url: &url::Url) -> Option<HeaderValue> {
let s = cookie_store
.get_request_values(url)
.map(|(name, value)| format!("{}={}", name, value))
.collect::<Vec<_>>()
.join("; ");
if s.is_empty() {
return None;
}
HeaderValue::from_maybe_shared(Bytes::from(s)).ok()
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CookieStoreMutex(Mutex<CookieStore>);
impl Default for CookieStoreMutex {
fn default() -> Self {
CookieStoreMutex::new(CookieStore::default())
}
}
impl CookieStoreMutex {
pub const fn new(cookie_store: CookieStore) -> CookieStoreMutex {
CookieStoreMutex(Mutex::new(cookie_store))
}
pub fn lock(
&self,
) -> Result<MutexGuard<'_, CookieStore>, PoisonError<MutexGuard<'_, CookieStore>>> {
self.0.lock()
}
pub fn into_inner(self) -> LockResult<CookieStore> {
self.0.into_inner()
}
}
impl reqwest::cookie::CookieStore for CookieStoreMutex {
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) {
let mut store = self.0.lock().unwrap();
set_cookies(&mut store, cookie_headers, url);
}
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> {
let store = self.0.lock().unwrap();
cookies(&store, url)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CookieStoreRwLock(RwLock<CookieStore>);
impl Default for CookieStoreRwLock {
fn default() -> Self {
CookieStoreRwLock::new(CookieStore::default())
}
}
impl CookieStoreRwLock {
pub const fn new(cookie_store: CookieStore) -> CookieStoreRwLock {
CookieStoreRwLock(RwLock::new(cookie_store))
}
pub fn read(
&self,
) -> Result<RwLockReadGuard<'_, CookieStore>, PoisonError<RwLockReadGuard<'_, CookieStore>>>
{
self.0.read()
}
pub fn write(
&self,
) -> Result<RwLockWriteGuard<'_, CookieStore>, PoisonError<RwLockWriteGuard<'_, CookieStore>>>
{
self.0.write()
}
pub fn into_inner(self) -> LockResult<CookieStore> {
self.0.into_inner()
}
}
impl reqwest::cookie::CookieStore for CookieStoreRwLock {
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) {
let mut write = self.0.write().unwrap();
set_cookies(&mut write, cookie_headers, url);
}
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> {
let read = self.0.read().unwrap();
cookies(&read, url)
}
}