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