1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 01:32:57 +01:00

Use non-consuming builder pattern for ClientRequest

This commit is contained in:
Nikolay Kim 2019-04-01 15:19:34 -07:00
parent 5c4e4edda4
commit 38afc93304
3 changed files with 161 additions and 126 deletions

View File

@ -14,6 +14,8 @@
### Changed ### Changed
* Use non-consuming builder pattern for `ClientRequest`.
* `ClientResponse::body()` does not consume response object. * `ClientResponse::body()` does not consume response object.

View File

@ -105,7 +105,7 @@ impl Client {
let mut req = ClientRequest::new(method, url, self.0.clone()); let mut req = ClientRequest::new(method, url, self.0.clone());
for (key, value) in &self.0.headers { for (key, value) in &self.0.headers {
req.head.headers.insert(key.clone(), value.clone()); req.set_header_if_none(key.clone(), value.clone());
} }
req req
} }
@ -120,7 +120,7 @@ impl Client {
{ {
let mut req = self.request(head.method.clone(), url); let mut req = self.request(head.method.clone(), url);
for (key, value) in &head.headers { for (key, value) in &head.headers {
req.head.headers.insert(key.clone(), value.clone()); req.set_header_if_none(key.clone(), value.clone());
} }
req req
} }

View File

@ -58,7 +58,7 @@ const HTTPS_ENCODING: &str = "gzip, deflate";
/// } /// }
/// ``` /// ```
pub struct ClientRequest { pub struct ClientRequest {
pub(crate) head: RequestHead, pub(crate) head: Option<RequestHead>,
err: Option<HttpError>, err: Option<HttpError>,
cookies: Option<CookieJar>, cookies: Option<CookieJar>,
default_headers: bool, default_headers: bool,
@ -73,36 +73,40 @@ impl ClientRequest {
where where
Uri: HttpTryFrom<U>, Uri: HttpTryFrom<U>,
{ {
ClientRequest { let mut req = ClientRequest {
config, config,
head: RequestHead::default(), head: Some(RequestHead::default()),
err: None, err: None,
cookies: None, cookies: None,
timeout: None, timeout: None,
default_headers: true, default_headers: true,
response_decompress: true, response_decompress: true,
} };
.method(method) req.method(method).uri(uri);
.uri(uri) req
} }
/// Set HTTP URI of request. /// Set HTTP URI of request.
#[inline] #[inline]
pub fn uri<U>(mut self, uri: U) -> Self pub fn uri<U>(&mut self, uri: U) -> &mut Self
where where
Uri: HttpTryFrom<U>, Uri: HttpTryFrom<U>,
{ {
if let Some(head) = parts(&mut self.head, &self.err) {
match Uri::try_from(uri) { match Uri::try_from(uri) {
Ok(uri) => self.head.uri = uri, Ok(uri) => head.uri = uri,
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
}
self self
} }
/// Set HTTP method of this request. /// Set HTTP method of this request.
#[inline] #[inline]
pub fn method(mut self, method: Method) -> Self { pub fn method(&mut self, method: Method) -> &mut Self {
self.head.method = method; if let Some(head) = parts(&mut self.head, &self.err) {
head.method = method;
}
self self
} }
@ -111,8 +115,10 @@ impl ClientRequest {
/// ///
/// By default requests's HTTP version depends on network stream /// By default requests's HTTP version depends on network stream
#[inline] #[inline]
pub fn version(mut self, version: Version) -> Self { pub fn version(&mut self, version: Version) -> &mut Self {
self.head.version = version; if let Some(head) = parts(&mut self.head, &self.err) {
head.version = version;
}
self self
} }
@ -129,13 +135,15 @@ impl ClientRequest {
/// # })); /// # }));
/// } /// }
/// ``` /// ```
pub fn set<H: Header>(mut self, hdr: H) -> Self { pub fn set<H: Header>(&mut self, hdr: H) -> &mut Self {
if let Some(head) = parts(&mut self.head, &self.err) {
match hdr.try_into() { match hdr.try_into() {
Ok(value) => { Ok(value) => {
self.head.headers.insert(H::name(), value); head.headers.insert(H::name(), value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
}
self self
} }
@ -157,53 +165,58 @@ impl ClientRequest {
/// # })); /// # }));
/// } /// }
/// ``` /// ```
pub fn header<K, V>(mut self, key: K, value: V) -> Self pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
where where
HeaderName: HttpTryFrom<K>, HeaderName: HttpTryFrom<K>,
V: IntoHeaderValue, V: IntoHeaderValue,
{ {
if let Some(head) = parts(&mut self.head, &self.err) {
match HeaderName::try_from(key) { match HeaderName::try_from(key) {
Ok(key) => match value.try_into() { Ok(key) => match value.try_into() {
Ok(value) => { Ok(value) => {
self.head.headers.append(key, value); head.headers.append(key, value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
}, },
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
}
self self
} }
/// Insert a header, replaces existing header. /// Insert a header, replaces existing header.
pub fn set_header<K, V>(mut self, key: K, value: V) -> Self pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
where where
HeaderName: HttpTryFrom<K>, HeaderName: HttpTryFrom<K>,
V: IntoHeaderValue, V: IntoHeaderValue,
{ {
if let Some(head) = parts(&mut self.head, &self.err) {
match HeaderName::try_from(key) { match HeaderName::try_from(key) {
Ok(key) => match value.try_into() { Ok(key) => match value.try_into() {
Ok(value) => { Ok(value) => {
self.head.headers.insert(key, value); head.headers.insert(key, value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
}, },
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
}
self self
} }
/// Insert a header only if it is not yet set. /// Insert a header only if it is not yet set.
pub fn set_header_if_none<K, V>(mut self, key: K, value: V) -> Self pub fn set_header_if_none<K, V>(&mut self, key: K, value: V) -> &mut Self
where where
HeaderName: HttpTryFrom<K>, HeaderName: HttpTryFrom<K>,
V: IntoHeaderValue, V: IntoHeaderValue,
{ {
if let Some(head) = parts(&mut self.head, &self.err) {
match HeaderName::try_from(key) { match HeaderName::try_from(key) {
Ok(key) => { Ok(key) => {
if !self.head.headers.contains_key(&key) { if !head.headers.contains_key(&key) {
match value.try_into() { match value.try_into() {
Ok(value) => { Ok(value) => {
self.head.headers.insert(key, value); head.headers.insert(key, value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
@ -211,41 +224,47 @@ impl ClientRequest {
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
}
self self
} }
/// Close connection /// Close connection instead of returning it back to connections pool.
/// This setting affect only http/1 connections.
#[inline] #[inline]
pub fn close_connection(mut self) -> Self { pub fn close_connection(&mut self) -> &mut Self {
self.head.set_connection_type(ConnectionType::Close); if let Some(head) = parts(&mut self.head, &self.err) {
head.set_connection_type(ConnectionType::Close);
}
self self
} }
/// Set request's content type /// Set request's content type
#[inline] #[inline]
pub fn content_type<V>(mut self, value: V) -> Self pub fn content_type<V>(&mut self, value: V) -> &mut Self
where where
HeaderValue: HttpTryFrom<V>, HeaderValue: HttpTryFrom<V>,
{ {
if let Some(head) = parts(&mut self.head, &self.err) {
match HeaderValue::try_from(value) { match HeaderValue::try_from(value) {
Ok(value) => { Ok(value) => {
let _ = self.head.headers.insert(header::CONTENT_TYPE, value); let _ = head.headers.insert(header::CONTENT_TYPE, value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
}
self self
} }
/// Set content length /// Set content length
#[inline] #[inline]
pub fn content_length(self, len: u64) -> Self { pub fn content_length(&mut self, len: u64) -> &mut Self {
let mut wrt = BytesMut::new().writer(); let mut wrt = BytesMut::new().writer();
let _ = write!(wrt, "{}", len); let _ = write!(wrt, "{}", len);
self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze()) self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze())
} }
/// Set HTTP basic authorization header /// Set HTTP basic authorization header
pub fn basic_auth<U>(self, username: U, password: Option<&str>) -> Self pub fn basic_auth<U>(&mut self, username: U, password: Option<&str>) -> &mut Self
where where
U: fmt::Display, U: fmt::Display,
{ {
@ -260,7 +279,7 @@ impl ClientRequest {
} }
/// Set HTTP bearer authentication header /// Set HTTP bearer authentication header
pub fn bearer_auth<T>(self, token: T) -> Self pub fn bearer_auth<T>(&mut self, token: T) -> &mut Self
where where
T: fmt::Display, T: fmt::Display,
{ {
@ -292,7 +311,7 @@ impl ClientRequest {
/// })); /// }));
/// } /// }
/// ``` /// ```
pub fn cookie<'c>(mut self, cookie: Cookie<'c>) -> Self { pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
if self.cookies.is_none() { if self.cookies.is_none() {
let mut jar = CookieJar::new(); let mut jar = CookieJar::new();
jar.add(cookie.into_owned()); jar.add(cookie.into_owned());
@ -305,13 +324,13 @@ impl ClientRequest {
/// Do not add default request headers. /// Do not add default request headers.
/// By default `Date` and `User-Agent` headers are set. /// By default `Date` and `User-Agent` headers are set.
pub fn no_default_headers(mut self) -> Self { pub fn no_default_headers(&mut self) -> &mut Self {
self.default_headers = false; self.default_headers = false;
self self
} }
/// Disable automatic decompress of response's body /// Disable automatic decompress of response's body
pub fn no_decompress(mut self) -> Self { pub fn no_decompress(&mut self) -> &mut Self {
self.response_decompress = false; self.response_decompress = false;
self self
} }
@ -320,38 +339,38 @@ impl ClientRequest {
/// ///
/// Request timeout is the total time before a response must be received. /// Request timeout is the total time before a response must be received.
/// Default value is 5 seconds. /// Default value is 5 seconds.
pub fn timeout(mut self, timeout: Duration) -> Self { pub fn timeout(&mut self, timeout: Duration) -> &mut Self {
self.timeout = Some(timeout); self.timeout = Some(timeout);
self self
} }
/// This method calls provided closure with builder reference if /// This method calls provided closure with builder reference if
/// value is `true`. /// value is `true`.
pub fn if_true<F>(mut self, value: bool, f: F) -> Self pub fn if_true<F>(&mut self, value: bool, f: F) -> &mut Self
where where
F: FnOnce(&mut ClientRequest), F: FnOnce(&mut ClientRequest),
{ {
if value { if value {
f(&mut self); f(self);
} }
self self
} }
/// This method calls provided closure with builder reference if /// This method calls provided closure with builder reference if
/// value is `Some`. /// value is `Some`.
pub fn if_some<T, F>(mut self, value: Option<T>, f: F) -> Self pub fn if_some<T, F>(&mut self, value: Option<T>, f: F) -> &mut Self
where where
F: FnOnce(T, &mut ClientRequest), F: FnOnce(T, &mut ClientRequest),
{ {
if let Some(val) = value { if let Some(val) = value {
f(val, &mut self); f(val, self);
} }
self self
} }
/// Complete request construction and send body. /// Complete request construction and send body.
pub fn send_body<B>( pub fn send_body<B>(
mut self, &mut self,
body: B, body: B,
) -> impl Future< ) -> impl Future<
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>, Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
@ -364,8 +383,10 @@ impl ClientRequest {
return Either::A(err(e.into())); return Either::A(err(e.into()));
} }
let mut head = self.head.take().expect("cannot reuse response builder");
// validate uri // validate uri
let uri = &self.head.uri; let uri = &head.uri;
if uri.host().is_none() { if uri.host().is_none() {
return Either::A(err(InvalidUrl::MissingHost.into())); return Either::A(err(InvalidUrl::MissingHost.into()));
} else if uri.scheme_part().is_none() { } else if uri.scheme_part().is_none() {
@ -380,20 +401,20 @@ impl ClientRequest {
} }
// set default headers // set default headers
let slf = if self.default_headers { if self.default_headers {
// set request host header // set request host header
if let Some(host) = self.head.uri.host() { if let Some(host) = head.uri.host() {
if !self.head.headers.contains_key(header::HOST) { if !head.headers.contains_key(header::HOST) {
let mut wrt = BytesMut::with_capacity(host.len() + 5).writer(); let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
let _ = match self.head.uri.port_u16() { let _ = match head.uri.port_u16() {
None | Some(80) | Some(443) => write!(wrt, "{}", host), None | Some(80) | Some(443) => write!(wrt, "{}", host),
Some(port) => write!(wrt, "{}:{}", host, port), Some(port) => write!(wrt, "{}:{}", host, port),
}; };
match wrt.get_mut().take().freeze().try_into() { match wrt.get_mut().take().freeze().try_into() {
Ok(value) => { Ok(value) => {
self.head.headers.insert(header::HOST, value); head.headers.insert(header::HOST, value);
} }
Err(e) => return Either::A(err(HttpError::from(e).into())), Err(e) => return Either::A(err(HttpError::from(e).into())),
} }
@ -404,14 +425,11 @@ impl ClientRequest {
self.set_header_if_none( self.set_header_if_none(
header::USER_AGENT, header::USER_AGENT,
concat!("awc/", env!("CARGO_PKG_VERSION")), concat!("awc/", env!("CARGO_PKG_VERSION")),
) );
} else { }
self
};
// enable br only for https // enable br only for https
let https = slf let https = head
.head
.uri .uri
.scheme_part() .scheme_part()
.map(|s| s == &uri::Scheme::HTTPS) .map(|s| s == &uri::Scheme::HTTPS)
@ -422,23 +440,19 @@ impl ClientRequest {
feature = "flate2-zlib", feature = "flate2-zlib",
feature = "flate2-rust" feature = "flate2-rust"
))] ))]
let mut slf = { {
if https { if https {
slf.set_header_if_none(header::ACCEPT_ENCODING, HTTPS_ENCODING) self.set_header_if_none(header::ACCEPT_ENCODING, HTTPS_ENCODING);
} else { } else {
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))] #[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
{ {
slf.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate") self.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate");
}
} }
#[cfg(not(any(feature = "flate2-zlib", feature = "flate2-rust")))]
slf
} }
};
let mut head = slf.head;
// set cookies // set cookies
if let Some(ref mut jar) = slf.cookies { if let Some(ref mut jar) = self.cookies {
let mut cookie = String::new(); let mut cookie = String::new();
for c in jar.delta() { for c in jar.delta() {
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET); let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
@ -451,8 +465,8 @@ impl ClientRequest {
); );
} }
let config = slf.config; let config = self.config.as_ref();
let response_decompress = slf.response_decompress; let response_decompress = self.response_decompress;
let fut = config let fut = config
.connector .connector
@ -469,7 +483,7 @@ impl ClientRequest {
}); });
// set request timeout // set request timeout
if let Some(timeout) = slf.timeout.or_else(|| config.timeout.clone()) { if let Some(timeout) = self.timeout.or_else(|| config.timeout.clone()) {
Either::B(Either::A(Timeout::new(fut, timeout).map_err(|e| { Either::B(Either::A(Timeout::new(fut, timeout).map_err(|e| {
if let Some(e) = e.into_inner() { if let Some(e) = e.into_inner() {
e e
@ -484,7 +498,7 @@ impl ClientRequest {
/// Set a JSON body and generate `ClientRequest` /// Set a JSON body and generate `ClientRequest`
pub fn send_json<T: Serialize>( pub fn send_json<T: Serialize>(
self, &mut self,
value: T, value: T,
) -> impl Future< ) -> impl Future<
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>, Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
@ -494,21 +508,18 @@ impl ClientRequest {
Ok(body) => body, Ok(body) => body,
Err(e) => return Either::A(err(Error::from(e).into())), Err(e) => return Either::A(err(Error::from(e).into())),
}; };
// set content-type
let slf = if !self.head.headers.contains_key(header::CONTENT_TYPE) {
self.header(header::CONTENT_TYPE, "application/json")
} else {
self
};
Either::B(slf.send_body(Body::Bytes(Bytes::from(body)))) // set content-type
self.set_header_if_none(header::CONTENT_TYPE, "application/json");
Either::B(self.send_body(Body::Bytes(Bytes::from(body))))
} }
/// Set a urlencoded body and generate `ClientRequest` /// Set a urlencoded body and generate `ClientRequest`
/// ///
/// `ClientRequestBuilder` can not be used after this call. /// `ClientRequestBuilder` can not be used after this call.
pub fn send_form<T: Serialize>( pub fn send_form<T: Serialize>(
self, &mut self,
value: T, value: T,
) -> impl Future< ) -> impl Future<
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>, Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
@ -519,18 +530,18 @@ impl ClientRequest {
Err(e) => return Either::A(err(Error::from(e).into())), Err(e) => return Either::A(err(Error::from(e).into())),
}; };
let slf = if !self.head.headers.contains_key(header::CONTENT_TYPE) { // set content-type
self.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded") self.set_header_if_none(
} else { header::CONTENT_TYPE,
self "application/x-www-form-urlencoded",
}; );
Either::B(slf.send_body(Body::Bytes(Bytes::from(body)))) Either::B(self.send_body(Body::Bytes(Bytes::from(body))))
} }
/// Set an streaming body and generate `ClientRequest`. /// Set an streaming body and generate `ClientRequest`.
pub fn send_stream<S, E>( pub fn send_stream<S, E>(
self, &mut self,
stream: S, stream: S,
) -> impl Future< ) -> impl Future<
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>, Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
@ -545,7 +556,7 @@ impl ClientRequest {
/// Set an empty body and generate `ClientRequest`. /// Set an empty body and generate `ClientRequest`.
pub fn send( pub fn send(
self, &mut self,
) -> impl Future< ) -> impl Future<
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>, Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
Error = SendRequestError, Error = SendRequestError,
@ -558,31 +569,44 @@ impl std::ops::Deref for ClientRequest {
type Target = RequestHead; type Target = RequestHead;
fn deref(&self) -> &RequestHead { fn deref(&self) -> &RequestHead {
&self.head self.head.as_ref().expect("cannot reuse response builder")
} }
} }
impl std::ops::DerefMut for ClientRequest { impl std::ops::DerefMut for ClientRequest {
fn deref_mut(&mut self) -> &mut RequestHead { fn deref_mut(&mut self) -> &mut RequestHead {
&mut self.head self.head.as_mut().expect("cannot reuse response builder")
} }
} }
impl fmt::Debug for ClientRequest { impl fmt::Debug for ClientRequest {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let head = self.head.as_ref().expect("cannot reuse response builder");
writeln!( writeln!(
f, f,
"\nClientRequest {:?} {}:{}", "\nClientRequest {:?} {}:{}",
self.head.version, self.head.method, self.head.uri head.version, head.method, head.uri
)?; )?;
writeln!(f, " headers:")?; writeln!(f, " headers:")?;
for (key, val) in self.head.headers.iter() { for (key, val) in head.headers.iter() {
writeln!(f, " {:?}: {:?}", key, val)?; writeln!(f, " {:?}: {:?}", key, val)?;
} }
Ok(()) Ok(())
} }
} }
#[inline]
fn parts<'a>(
parts: &'a mut Option<RequestHead>,
err: &Option<HttpError>,
) -> Option<&'a mut RequestHead> {
if err.is_some() {
return None;
}
parts.as_mut()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -591,7 +615,8 @@ mod tests {
#[test] #[test]
fn test_debug() { fn test_debug() {
test::run_on(|| { test::run_on(|| {
let request = Client::new().get("/").header("x-test", "111"); let mut request = Client::new().get("/");
request.header("x-test", "111");
let repr = format!("{:?}", request); let repr = format!("{:?}", request);
assert!(repr.contains("ClientRequest")); assert!(repr.contains("ClientRequest"));
assert!(repr.contains("x-test")); assert!(repr.contains("x-test"));
@ -608,6 +633,8 @@ mod tests {
assert_eq!( assert_eq!(
req.head req.head
.as_ref()
.unwrap()
.headers .headers
.get(header::CONTENT_TYPE) .get(header::CONTENT_TYPE)
.unwrap() .unwrap()
@ -621,14 +648,16 @@ mod tests {
#[test] #[test]
fn test_client_header_override() { fn test_client_header_override() {
test::run_on(|| { test::run_on(|| {
let req = Client::build() let mut req = Client::build()
.header(header::CONTENT_TYPE, "111") .header(header::CONTENT_TYPE, "111")
.finish() .finish()
.get("/") .get("/");
.set_header(header::CONTENT_TYPE, "222"); req.set_header(header::CONTENT_TYPE, "222");
assert_eq!( assert_eq!(
req.head req.head
.as_ref()
.unwrap()
.headers .headers
.get(header::CONTENT_TYPE) .get(header::CONTENT_TYPE)
.unwrap() .unwrap()
@ -642,12 +671,12 @@ mod tests {
#[test] #[test]
fn client_basic_auth() { fn client_basic_auth() {
test::run_on(|| { test::run_on(|| {
let client = Client::new() let mut req = Client::new().get("/");
.get("/") req.basic_auth("username", Some("password"));
.basic_auth("username", Some("password"));
assert_eq!( assert_eq!(
client req.head
.head .as_ref()
.unwrap()
.headers .headers
.get(header::AUTHORIZATION) .get(header::AUTHORIZATION)
.unwrap() .unwrap()
@ -656,10 +685,12 @@ mod tests {
"Basic dXNlcm5hbWU6cGFzc3dvcmQ=" "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
); );
let client = Client::new().get("/").basic_auth("username", None); let mut req = Client::new().get("/");
req.basic_auth("username", None);
assert_eq!( assert_eq!(
client req.head
.head .as_ref()
.unwrap()
.headers .headers
.get(header::AUTHORIZATION) .get(header::AUTHORIZATION)
.unwrap() .unwrap()
@ -673,10 +704,12 @@ mod tests {
#[test] #[test]
fn client_bearer_auth() { fn client_bearer_auth() {
test::run_on(|| { test::run_on(|| {
let client = Client::new().get("/").bearer_auth("someS3cr3tAutht0k3n"); let mut req = Client::new().get("/");
req.bearer_auth("someS3cr3tAutht0k3n");
assert_eq!( assert_eq!(
client req.head
.head .as_ref()
.unwrap()
.headers .headers
.get(header::AUTHORIZATION) .get(header::AUTHORIZATION)
.unwrap() .unwrap()