Add CookieStore trait and expose default Jar (#1203)
				
					
				
			This adds a new trait, `CookieStore`, which allows for custom implementations of storage for a client's cookies. After implementing, you can call `ClientBuilder::cookie_provider` to use it over the default storage. The default store is exposed as `Jar`, to ease the most common use case which is to add a few cookies to the store when creating a client. Co-authored-by: Patrick Fernie <patrick.fernie@gmail.com>
This commit is contained in:
		| @@ -3,8 +3,6 @@ use std::any::Any; | ||||
| use std::convert::TryInto; | ||||
| use std::net::IpAddr; | ||||
| use std::sync::Arc; | ||||
| #[cfg(feature = "cookies")] | ||||
| use std::sync::RwLock; | ||||
| use std::time::Duration; | ||||
| use std::{fmt, str}; | ||||
|  | ||||
| @@ -105,7 +103,7 @@ struct Config { | ||||
|     local_address: Option<IpAddr>, | ||||
|     nodelay: bool, | ||||
|     #[cfg(feature = "cookies")] | ||||
|     cookie_store: Option<cookie::CookieStore>, | ||||
|     cookie_store: Option<Arc<dyn cookie::CookieStore>>, | ||||
|     trust_dns: bool, | ||||
|     error: Option<crate::Error>, | ||||
|     https_only: bool, | ||||
| @@ -350,7 +348,7 @@ impl ClientBuilder { | ||||
|             inner: Arc::new(ClientRef { | ||||
|                 accepts: config.accepts, | ||||
|                 #[cfg(feature = "cookies")] | ||||
|                 cookie_store: config.cookie_store.map(RwLock::new), | ||||
|                 cookie_store: config.cookie_store, | ||||
|                 hyper: hyper_client, | ||||
|                 headers: config.headers, | ||||
|                 redirect_policy: config.redirect_policy, | ||||
| @@ -464,11 +462,31 @@ impl ClientBuilder { | ||||
|     #[cfg(feature = "cookies")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))] | ||||
|     pub fn cookie_store(mut self, enable: bool) -> ClientBuilder { | ||||
|         self.config.cookie_store = if enable { | ||||
|             Some(cookie::CookieStore::default()) | ||||
|         if enable { | ||||
|             self.cookie_provider(Arc::new(cookie::Jar::default())) | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
|             self.config.cookie_store = None; | ||||
|             self | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Set the persistent cookie store for the client. | ||||
|     /// | ||||
|     /// Cookies received in responses will be passed to this store, and | ||||
|     /// additional requests will query this store for cookies. | ||||
|     /// | ||||
|     /// By default, no cookie store is used. | ||||
|     /// | ||||
|     /// # Optional | ||||
|     /// | ||||
|     /// This requires the optional `cookies` feature to be enabled. | ||||
|     #[cfg(feature = "cookies")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))] | ||||
|     pub fn cookie_provider<C: cookie::CookieStore + 'static>( | ||||
|         mut self, | ||||
|         cookie_store: Arc<C>, | ||||
|     ) -> ClientBuilder { | ||||
|         self.config.cookie_store = Some(cookie_store as _); | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -1109,10 +1127,9 @@ impl Client { | ||||
|         // Add cookies from the cookie store. | ||||
|         #[cfg(feature = "cookies")] | ||||
|         { | ||||
|             if let Some(cookie_store_wrapper) = self.inner.cookie_store.as_ref() { | ||||
|             if let Some(cookie_store) = self.inner.cookie_store.as_ref() { | ||||
|                 if headers.get(crate::header::COOKIE).is_none() { | ||||
|                     let cookie_store = cookie_store_wrapper.read().unwrap(); | ||||
|                     add_cookie_header(&mut headers, &cookie_store, &url); | ||||
|                     add_cookie_header(&mut headers, &**cookie_store, &url); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -1289,7 +1306,7 @@ impl Config { | ||||
| struct ClientRef { | ||||
|     accepts: Accepts, | ||||
|     #[cfg(feature = "cookies")] | ||||
|     cookie_store: Option<RwLock<cookie::CookieStore>>, | ||||
|     cookie_store: Option<Arc<dyn cookie::CookieStore>>, | ||||
|     headers: HeaderMap, | ||||
|     hyper: HyperClient, | ||||
|     redirect_policy: redirect::Policy, | ||||
| @@ -1431,14 +1448,11 @@ impl Future for PendingRequest { | ||||
|  | ||||
|             #[cfg(feature = "cookies")] | ||||
|             { | ||||
|                 if let Some(store_wrapper) = self.client.cookie_store.as_ref() { | ||||
|                     let mut cookies = cookie::extract_response_cookies(&res.headers()) | ||||
|                         .filter_map(|res| res.ok()) | ||||
|                         .map(|cookie| cookie.into_inner().into_owned()) | ||||
|                         .peekable(); | ||||
|                 if let Some(ref cookie_store) = self.client.cookie_store { | ||||
|                     let mut cookies = | ||||
|                         cookie::extract_response_cookie_headers(&res.headers()).peekable(); | ||||
|                     if cookies.peek().is_some() { | ||||
|                         let mut store = store_wrapper.write().unwrap(); | ||||
|                         store.0.store_response_cookies(cookies, &self.url); | ||||
|                         cookie_store.set_cookies(&mut cookies, &self.url); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -1531,11 +1545,8 @@ impl Future for PendingRequest { | ||||
|                             // Add cookies from the cookie store. | ||||
|                             #[cfg(feature = "cookies")] | ||||
|                             { | ||||
|                                 if let Some(cookie_store_wrapper) = | ||||
|                                     self.client.cookie_store.as_ref() | ||||
|                                 { | ||||
|                                     let cookie_store = cookie_store_wrapper.read().unwrap(); | ||||
|                                     add_cookie_header(&mut headers, &cookie_store, &self.url); | ||||
|                                 if let Some(ref cookie_store) = self.client.cookie_store { | ||||
|                                     add_cookie_header(&mut headers, &**cookie_store, &self.url); | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
| @@ -1592,18 +1603,9 @@ fn make_referer(next: &Url, previous: &Url) -> Option<HeaderValue> { | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "cookies")] | ||||
| fn add_cookie_header(headers: &mut HeaderMap, cookie_store: &cookie::CookieStore, url: &Url) { | ||||
|     let header = cookie_store | ||||
|         .0 | ||||
|         .get_request_cookies(url) | ||||
|         .map(|c| format!("{}={}", c.name(), c.value())) | ||||
|         .collect::<Vec<_>>() | ||||
|         .join("; "); | ||||
|     if !header.is_empty() { | ||||
|         headers.insert( | ||||
|             crate::header::COOKIE, | ||||
|             HeaderValue::from_bytes(header.as_bytes()).unwrap(), | ||||
|         ); | ||||
| fn add_cookie_header(headers: &mut HeaderMap, cookie_store: &dyn cookie::CookieStore, url: &Url) { | ||||
|     if let Some(header) = cookie_store.cookies(url) { | ||||
|         headers.insert(crate::header::COOKIE, header); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user