Refactor gzip and brotli bools into an Accepts struct
This commit is contained in:
		| @@ -28,6 +28,7 @@ use tokio::time::Delay; | ||||
|  | ||||
| use log::debug; | ||||
|  | ||||
| use super::decoder::Accepts; | ||||
| use super::request::{Request, RequestBuilder}; | ||||
| use super::response::Response; | ||||
| use super::Body; | ||||
| @@ -62,8 +63,7 @@ pub struct ClientBuilder { | ||||
|  | ||||
| struct Config { | ||||
|     // NOTE: When adding a new field, update `fmt::Debug for ClientBuilder` | ||||
|     gzip: bool, | ||||
|     brotli: bool, | ||||
|     accepts: Accepts, | ||||
|     headers: HeaderMap, | ||||
|     #[cfg(feature = "native-tls")] | ||||
|     hostname_verification: bool, | ||||
| @@ -112,8 +112,7 @@ impl ClientBuilder { | ||||
|         ClientBuilder { | ||||
|             config: Config { | ||||
|                 error: None, | ||||
|                 gzip: cfg!(feature = "gzip"), | ||||
|                 brotli: cfg!(feature = "brotli"), | ||||
|                 accepts: Accepts::default(), | ||||
|                 headers, | ||||
|                 #[cfg(feature = "native-tls")] | ||||
|                 hostname_verification: true, | ||||
| @@ -312,10 +311,9 @@ impl ClientBuilder { | ||||
|  | ||||
|         Ok(Client { | ||||
|             inner: Arc::new(ClientRef { | ||||
|                 accepts: config.accepts, | ||||
|                 #[cfg(feature = "cookies")] | ||||
|                 cookie_store: config.cookie_store.map(RwLock::new), | ||||
|                 gzip: config.gzip, | ||||
|                 brotli: config.brotli, | ||||
|                 hyper: hyper_client, | ||||
|                 headers: config.headers, | ||||
|                 redirect_policy: config.redirect_policy, | ||||
| @@ -448,7 +446,7 @@ impl ClientBuilder { | ||||
|     /// This requires the optional `gzip` feature to be enabled | ||||
|     #[cfg(feature = "gzip")] | ||||
|     pub fn gzip(mut self, enable: bool) -> ClientBuilder { | ||||
|         self.config.gzip = enable; | ||||
|         self.config.accepts.gzip = enable; | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -470,7 +468,7 @@ impl ClientBuilder { | ||||
|     /// This requires the optional `brotli` feature to be enabled | ||||
|     #[cfg(feature = "brotli")] | ||||
|     pub fn brotli(mut self, enable: bool) -> ClientBuilder { | ||||
|         self.config.brotli = enable; | ||||
|         self.config.accepts.brotli = enable; | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -976,12 +974,7 @@ impl Client { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         let accept_encoding = match (self.inner.gzip, self.inner.brotli) { | ||||
|             (true, true) => Some("gzip, br"), | ||||
|             (true, false) => Some("gzip"), | ||||
|             (false, true) => Some("br"), | ||||
|             _ => None, | ||||
|         }; | ||||
|         let accept_encoding = self.inner.accepts.as_str(); | ||||
|  | ||||
|         if accept_encoding.is_some() | ||||
|             && !headers.contains_key(ACCEPT_ENCODING) | ||||
| @@ -1092,8 +1085,7 @@ impl Config { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         f.field("gzip", &self.gzip); | ||||
|         f.field("brotli", &self.brotli); | ||||
|         f.field("accepts", &self.accepts); | ||||
|  | ||||
|         if !self.proxies.is_empty() { | ||||
|             f.field("proxies", &self.proxies); | ||||
| @@ -1155,10 +1147,9 @@ impl Config { | ||||
| } | ||||
|  | ||||
| struct ClientRef { | ||||
|     accepts: Accepts, | ||||
|     #[cfg(feature = "cookies")] | ||||
|     cookie_store: Option<RwLock<cookie::CookieStore>>, | ||||
|     gzip: bool, | ||||
|     brotli: bool, | ||||
|     headers: HeaderMap, | ||||
|     hyper: HyperClient, | ||||
|     redirect_policy: redirect::Policy, | ||||
| @@ -1180,8 +1171,7 @@ impl ClientRef { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         f.field("gzip", &self.gzip); | ||||
|         f.field("brotli", &self.brotli); | ||||
|         f.field("accepts", &self.accepts); | ||||
|  | ||||
|         if !self.proxies.is_empty() { | ||||
|             f.field("proxies", &self.proxies); | ||||
| @@ -1417,8 +1407,7 @@ impl Future for PendingRequest { | ||||
|             let res = Response::new( | ||||
|                 res, | ||||
|                 self.url.clone(), | ||||
|                 self.client.gzip, | ||||
|                 self.client.brotli, | ||||
|                 self.client.accepts, | ||||
|                 self.timeout.take(), | ||||
|             ); | ||||
|             return Poll::Ready(Ok(res)); | ||||
|   | ||||
| @@ -18,6 +18,14 @@ use hyper::body::HttpBody; | ||||
| use super::super::Body; | ||||
| use crate::error; | ||||
|  | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| pub(super) struct Accepts { | ||||
|     #[cfg(feature = "gzip")] | ||||
|     pub(super) gzip: bool, | ||||
|     #[cfg(feature = "brotli")] | ||||
|     pub(super) brotli: bool, | ||||
| } | ||||
|  | ||||
| /// A response decompressor over a non-blocking stream of chunks. | ||||
| /// | ||||
| /// The inner decoder may be constructed asynchronously. | ||||
| @@ -25,13 +33,6 @@ pub(crate) struct Decoder { | ||||
|     inner: Inner, | ||||
| } | ||||
|  | ||||
| enum DecoderType { | ||||
|     #[cfg(feature = "gzip")] | ||||
|     Gzip, | ||||
|     #[cfg(feature = "brotli")] | ||||
|     Brotli, | ||||
| } | ||||
|  | ||||
| enum Inner { | ||||
|     /// A `PlainText` decoder just returns the response content as is. | ||||
|     PlainText(super::body::ImplStream), | ||||
| @@ -54,6 +55,13 @@ struct Pending(Peekable<IoStream>, DecoderType); | ||||
|  | ||||
| struct IoStream(super::body::ImplStream); | ||||
|  | ||||
| enum DecoderType { | ||||
|     #[cfg(feature = "gzip")] | ||||
|     Gzip, | ||||
|     #[cfg(feature = "brotli")] | ||||
|     Brotli, | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Decoder { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("Decoder").finish() | ||||
| @@ -177,26 +185,21 @@ impl Decoder { | ||||
|     /// how to decode the content body of the request. | ||||
|     /// | ||||
|     /// Uses the correct variant by inspecting the Content-Encoding header. | ||||
|     pub(crate) fn detect( | ||||
|     pub(super) fn detect( | ||||
|         _headers: &mut HeaderMap, | ||||
|         body: Body, | ||||
|         check_gzip: bool, | ||||
|         check_brotli: bool, | ||||
|         _accepts: Accepts, | ||||
|     ) -> Decoder { | ||||
|         if !check_gzip && !check_brotli { | ||||
|             return Decoder::plain_text(body); | ||||
|         } | ||||
|  | ||||
|         #[cfg(feature = "gzip")] | ||||
|         { | ||||
|             if Decoder::detect_gzip(_headers) { | ||||
|             if _accepts.gzip && Decoder::detect_gzip(_headers) { | ||||
|                 return Decoder::gzip(body); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         #[cfg(feature = "brotli")] | ||||
|         { | ||||
|             if Decoder::detect_brotli(_headers) { | ||||
|             if _accepts.brotli && Decoder::detect_brotli(_headers) { | ||||
|                 return Decoder::brotli(body); | ||||
|             } | ||||
|         } | ||||
| @@ -317,3 +320,60 @@ impl Stream for IoStream { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl Accepts ===== | ||||
|  | ||||
| impl Accepts { | ||||
|     pub(super) fn none() -> Self { | ||||
|         Accepts { | ||||
|             #[cfg(feature = "gzip")] | ||||
|             gzip: false, | ||||
|             #[cfg(feature = "brotli")] | ||||
|             brotli: false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub(super) fn as_str(&self) -> Option<&'static str> { | ||||
|         match (self.is_gzip(), self.is_brotli()) { | ||||
|             (true, true) => Some("gzip, br"), | ||||
|             (true, false) => Some("gzip"), | ||||
|             (false, true) => Some("br"), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn is_gzip(&self) -> bool { | ||||
|         #[cfg(feature = "gzip")] | ||||
|         { | ||||
|             self.gzip | ||||
|         } | ||||
|  | ||||
|         #[cfg(not(feature = "gzip"))] | ||||
|         { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn is_brotli(&self) -> bool { | ||||
|         #[cfg(feature = "brotli")] | ||||
|         { | ||||
|             self.brotli | ||||
|         } | ||||
|  | ||||
|         #[cfg(not(feature = "brotli"))] | ||||
|         { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Default for Accepts { | ||||
|     fn default() -> Accepts { | ||||
|         Accepts { | ||||
|             #[cfg(feature = "gzip")] | ||||
|             gzip: true, | ||||
|             #[cfg(feature = "brotli")] | ||||
|             brotli: true, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,11 @@ | ||||
| pub use self::body::Body; | ||||
| pub use self::client::{Client, ClientBuilder}; | ||||
| pub(crate) use self::decoder::Decoder; | ||||
| pub use self::request::{Request, RequestBuilder}; | ||||
| pub use self::response::{Response, ResponseBuilderExt}; | ||||
|  | ||||
| #[cfg(feature = "blocking")] | ||||
| pub(crate) use self::decoder::Decoder; | ||||
|  | ||||
| pub mod body; | ||||
| pub mod client; | ||||
| pub mod decoder; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ use tokio::time::Delay; | ||||
| use url::Url; | ||||
|  | ||||
| use super::body::Body; | ||||
| use super::Decoder; | ||||
| use super::decoder::{Accepts, Decoder}; | ||||
| #[cfg(feature = "cookies")] | ||||
| use crate::cookie; | ||||
|  | ||||
| @@ -37,8 +37,7 @@ impl Response { | ||||
|     pub(super) fn new( | ||||
|         res: hyper::Response<hyper::Body>, | ||||
|         url: Url, | ||||
|         gzip: bool, | ||||
|         brotli: bool, | ||||
|         accepts: Accepts, | ||||
|         timeout: Option<Delay>, | ||||
|     ) -> Response { | ||||
|         let (parts, body) = res.into_parts(); | ||||
| @@ -47,7 +46,7 @@ impl Response { | ||||
|         let extensions = parts.extensions; | ||||
|  | ||||
|         let mut headers = parts.headers; | ||||
|         let decoder = Decoder::detect(&mut headers, Body::response(body, timeout), gzip, brotli); | ||||
|         let decoder = Decoder::detect(&mut headers, Body::response(body, timeout), accepts); | ||||
|  | ||||
|         Response { | ||||
|             status, | ||||
| @@ -400,7 +399,7 @@ impl<T: Into<Body>> From<http::Response<T>> for Response { | ||||
|     fn from(r: http::Response<T>) -> Response { | ||||
|         let (mut parts, body) = r.into_parts(); | ||||
|         let body = body.into(); | ||||
|         let body = Decoder::detect(&mut parts.headers, body, false, false); | ||||
|         let body = Decoder::detect(&mut parts.headers, body, Accepts::none()); | ||||
|         let url = parts | ||||
|             .extensions | ||||
|             .remove::<ResponseUrl>() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user