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:
parent
5c4e4edda4
commit
38afc93304
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user