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