cargo fmt (#604)

Run rustfmt and setup CI to check for it.
This commit is contained in:
danieleades
2019-08-29 17:52:39 +01:00
committed by Sean McArthur
parent 81e0f1ff2a
commit cf8944a0f0
41 changed files with 1399 additions and 1378 deletions

View File

@@ -1,7 +1,7 @@
use std::fmt;
use futures::{Future, Stream, Poll, Async, try_ready};
use bytes::{Buf, Bytes};
use futures::{try_ready, Async, Future, Poll, Stream};
use hyper::body::Payload;
use tokio::timer::Delay;
@@ -15,7 +15,7 @@ enum Inner {
Hyper {
body: hyper::Body,
timeout: Option<Delay>,
}
},
}
impl Body {
@@ -29,10 +29,7 @@ impl Body {
#[inline]
pub(crate) fn response(body: hyper::Body, timeout: Option<Delay>) -> Body {
Body {
inner: Inner::Hyper {
body,
timeout,
},
inner: Inner::Hyper { body, timeout },
}
}
@@ -65,7 +62,7 @@ impl Body {
Inner::Hyper { body, timeout } => {
debug_assert!(timeout.is_none());
(None, body)
},
}
}
}
}
@@ -77,14 +74,17 @@ impl Stream for Body {
#[inline]
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let opt = match self.inner {
Inner::Hyper { ref mut body, ref mut timeout } => {
Inner::Hyper {
ref mut body,
ref mut timeout,
} => {
if let Some(ref mut timeout) = timeout {
if let Async::Ready(()) = try_!(timeout.poll()) {
return Err(crate::error::timedout(None));
}
}
try_ready!(body.poll_data().map_err(crate::error::from))
},
}
Inner::Reusable(ref mut bytes) => {
return if bytes.is_empty() {
Ok(Async::Ready(None))
@@ -93,12 +93,10 @@ impl Stream for Body {
*bytes = Bytes::new();
Ok(Async::Ready(Some(chunk)))
};
},
}
};
Ok(Async::Ready(opt.map(|chunk| Chunk {
inner: chunk,
})))
Ok(Async::Ready(opt.map(|chunk| Chunk { inner: chunk })))
}
}
@@ -161,7 +159,7 @@ impl Chunk {
#[inline]
pub(crate) fn from_chunk(chunk: Bytes) -> Chunk {
Chunk {
inner: hyper::Chunk::from(chunk)
inner: hyper::Chunk::from(chunk),
}
}
}
@@ -197,7 +195,9 @@ impl std::ops::Deref for Chunk {
impl Extend<u8> for Chunk {
fn extend<T>(&mut self, iter: T)
where T: IntoIterator<Item=u8> {
where
T: IntoIterator<Item = u8>,
{
self.inner.extend(iter)
}
}
@@ -219,7 +219,9 @@ impl From<Vec<u8>> for Chunk {
impl From<&'static [u8]> for Chunk {
fn from(slice: &'static [u8]) -> Chunk {
Chunk { inner: slice.into() }
Chunk {
inner: slice.into(),
}
}
}
@@ -231,13 +233,17 @@ impl From<String> for Chunk {
impl From<&'static str> for Chunk {
fn from(slice: &'static str) -> Chunk {
Chunk { inner: slice.into() }
Chunk {
inner: slice.into(),
}
}
}
impl From<Bytes> for Chunk {
fn from(bytes: Bytes) -> Chunk {
Chunk { inner: bytes.into() }
Chunk {
inner: bytes.into(),
}
}
}
@@ -249,8 +255,7 @@ impl From<Chunk> for hyper::Chunk {
impl fmt::Debug for Body {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Body")
.finish()
f.debug_struct("Body").finish()
}
}

View File

@@ -1,26 +1,14 @@
use std::{fmt, str};
use std::net::IpAddr;
use std::sync::{Arc, RwLock};
use std::time::Duration;
use std::net::IpAddr;
use std::{fmt, str};
use crate::header::{
Entry, HeaderMap, HeaderValue, ACCEPT, ACCEPT_ENCODING, CONTENT_ENCODING, CONTENT_LENGTH,
CONTENT_TYPE, LOCATION, PROXY_AUTHORIZATION, RANGE, REFERER, TRANSFER_ENCODING, USER_AGENT,
};
use bytes::Bytes;
use futures::{Async, Future, Poll};
use crate::header::{
Entry,
HeaderMap,
HeaderValue,
ACCEPT,
ACCEPT_ENCODING,
CONTENT_LENGTH,
CONTENT_ENCODING,
CONTENT_TYPE,
LOCATION,
PROXY_AUTHORIZATION,
RANGE,
REFERER,
TRANSFER_ENCODING,
USER_AGENT,
};
use http::Uri;
use hyper::client::ResponseFuture;
use mime;
@@ -28,24 +16,22 @@ use mime;
use native_tls::TlsConnector;
use tokio::{clock, timer::Delay};
use log::{debug};
use log::debug;
use super::request::{Request, RequestBuilder};
use super::response::Response;
use crate::connect::Connector;
use crate::into_url::{expect_uri, try_uri};
use crate::cookie;
use crate::redirect::{self, RedirectPolicy, remove_sensitive_headers};
use crate::{IntoUrl, Method, Proxy, StatusCode, Url};
use crate::into_url::{expect_uri, try_uri};
use crate::proxy::get_proxies;
#[cfg(feature = "tls")]
use crate::{Certificate, Identity};
use crate::redirect::{self, remove_sensitive_headers, RedirectPolicy};
#[cfg(feature = "tls")]
use crate::tls::TlsBackend;
#[cfg(feature = "tls")]
use crate::{Certificate, Identity};
use crate::{IntoUrl, Method, Proxy, StatusCode, Url};
static DEFAULT_USER_AGENT: &str =
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
/// An asynchronous `Client` to make Requests with.
///
@@ -98,7 +84,10 @@ impl ClientBuilder {
pub fn new() -> ClientBuilder {
let mut headers: HeaderMap<HeaderValue> = HeaderMap::with_capacity(2);
headers.insert(USER_AGENT, HeaderValue::from_static(DEFAULT_USER_AGENT));
headers.insert(ACCEPT, HeaderValue::from_str(mime::STAR_STAR.as_ref()).expect("unable to parse mime"));
headers.insert(
ACCEPT,
HeaderValue::from_str(mime::STAR_STAR.as_ref()).expect("unable to parse mime"),
);
ClientBuilder {
config: Config {
@@ -156,8 +145,13 @@ impl ClientBuilder {
id.add_to_native_tls(&mut tls)?;
}
Connector::new_default_tls(tls, proxies.clone(), config.local_address, config.nodelay)?
},
Connector::new_default_tls(
tls,
proxies.clone(),
config.local_address,
config.nodelay,
)?
}
#[cfg(feature = "rustls-tls")]
TlsBackend::Rustls => {
use crate::tls::NoVerifier;
@@ -166,15 +160,14 @@ impl ClientBuilder {
if config.http2_only {
tls.set_protocols(&["h2".into()]);
} else {
tls.set_protocols(&[
"h2".into(),
"http/1.1".into(),
]);
tls.set_protocols(&["h2".into(), "http/1.1".into()]);
}
tls.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
tls.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
if !config.certs_verification {
tls.dangerous().set_certificate_verifier(Arc::new(NoVerifier));
tls.dangerous()
.set_certificate_verifier(Arc::new(NoVerifier));
}
for cert in config.root_certs {
@@ -185,7 +178,12 @@ impl ClientBuilder {
id.add_to_rustls(&mut tls)?;
}
Connector::new_rustls_tls(tls, proxies.clone(), config.local_address, config.nodelay)?
Connector::new_rustls_tls(
tls,
proxies.clone(),
config.local_address,
config.nodelay,
)?
}
}
@@ -208,9 +206,7 @@ impl ClientBuilder {
let hyper_client = builder.build(connector);
let proxies_maybe_http_auth = proxies
.iter()
.any(|p| p.maybe_has_http_auth());
let proxies_maybe_http_auth = proxies.iter().any(|p| p.maybe_has_http_auth());
let cookie_store = config.cookie_store.map(RwLock::new);
@@ -277,7 +273,10 @@ impl ClientBuilder {
/// site will be trusted for use from any other. This introduces a
/// significant vulnerability to man-in-the-middle attacks.
#[cfg(feature = "default-tls")]
pub fn danger_accept_invalid_hostnames(mut self, accept_invalid_hostname: bool) -> ClientBuilder {
pub fn danger_accept_invalid_hostnames(
mut self,
accept_invalid_hostname: bool,
) -> ClientBuilder {
self.config.hostname_verification = !accept_invalid_hostname;
self
}
@@ -299,7 +298,6 @@ impl ClientBuilder {
self
}
/// Sets the default headers for every request.
pub fn default_headers(mut self, headers: HeaderMap) -> ClientBuilder {
for (key, value) in headers.iter() {
@@ -349,7 +347,6 @@ impl ClientBuilder {
self
}
/// Set a `RedirectPolicy` for this client.
///
/// Default will follow redirects up to a maximum of 10.
@@ -454,9 +451,7 @@ impl Client {
/// Use `Client::builder()` if you wish to handle the failure as an `Error`
/// instead of panicking.
pub fn new() -> Client {
ClientBuilder::new()
.build()
.expect("Client::new()")
ClientBuilder::new().build().expect("Client::new()")
}
/// Creates a `ClientBuilder` to configure a `Client`.
@@ -529,9 +524,7 @@ impl Client {
///
/// This method fails whenever supplied `Url` cannot be parsed.
pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
let req = url
.into_url()
.map(move |url| Request::new(method, url));
let req = url.into_url().map(move |url| Request::new(method, url));
RequestBuilder::new(self.clone(), req)
}
@@ -551,14 +544,8 @@ impl Client {
self.execute_request(request)
}
pub(super) fn execute_request(&self, req: Request) -> Pending {
let (
method,
url,
mut headers,
body
) = req.pieces();
let (method, url, mut headers, body) = req.pieces();
// insert default headers in the request headers
// without overwriting already appended headers.
@@ -576,9 +563,8 @@ impl Client {
}
}
if self.inner.gzip &&
!headers.contains_key(ACCEPT_ENCODING) &&
!headers.contains_key(RANGE) {
if self.inner.gzip && !headers.contains_key(ACCEPT_ENCODING) && !headers.contains_key(RANGE)
{
headers.insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));
}
@@ -588,10 +574,8 @@ impl Client {
Some(body) => {
let (reusable, body) = body.into_hyper();
(Some(reusable), body)
},
None => {
(None, hyper::Body::empty())
}
None => (None, hyper::Body::empty()),
};
self.proxy_auth(&uri, &mut headers);
@@ -606,9 +590,10 @@ impl Client {
let in_flight = self.inner.hyper.request(req);
let timeout = self.inner.request_timeout.map(|dur| {
Delay::new(clock::now() + dur)
});
let timeout = self
.inner
.request_timeout
.map(|dur| Delay::new(clock::now() + dur));
Pending {
inner: PendingInner::Request(PendingRequest {
@@ -643,14 +628,10 @@ impl Client {
return;
}
for proxy in self.inner.proxies.iter() {
if proxy.is_match(dst) {
if let Some(header) = proxy.http_basic_auth(dst) {
headers.insert(
PROXY_AUTHORIZATION,
header,
);
headers.insert(PROXY_AUTHORIZATION, header);
}
break;
@@ -671,8 +652,7 @@ impl fmt::Debug for Client {
impl fmt::Debug for ClientBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ClientBuilder")
.finish()
f.debug_struct("ClientBuilder").finish()
}
}
@@ -726,7 +706,9 @@ impl Future for Pending {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.inner {
PendingInner::Request(ref mut req) => req.poll(),
PendingInner::Error(ref mut err) => Err(err.take().expect("Pending error polled more than once")),
PendingInner::Error(ref mut err) => {
Err(err.take().expect("Pending error polled more than once"))
}
}
}
}
@@ -755,56 +737,58 @@ impl Future for PendingRequest {
store.0.store_response_cookies(cookies, &self.url);
}
let should_redirect = match res.status() {
StatusCode::MOVED_PERMANENTLY |
StatusCode::FOUND |
StatusCode::SEE_OTHER => {
StatusCode::MOVED_PERMANENTLY | StatusCode::FOUND | StatusCode::SEE_OTHER => {
self.body = None;
for header in &[TRANSFER_ENCODING, CONTENT_ENCODING, CONTENT_TYPE, CONTENT_LENGTH] {
for header in &[
TRANSFER_ENCODING,
CONTENT_ENCODING,
CONTENT_TYPE,
CONTENT_LENGTH,
] {
self.headers.remove(header);
}
match self.method {
Method::GET | Method::HEAD => {},
Method::GET | Method::HEAD => {}
_ => {
self.method = Method::GET;
}
}
true
},
StatusCode::TEMPORARY_REDIRECT |
StatusCode::PERMANENT_REDIRECT => match self.body {
Some(Some(_)) | None => true,
Some(None) => false,
},
}
StatusCode::TEMPORARY_REDIRECT | StatusCode::PERMANENT_REDIRECT => {
match self.body {
Some(Some(_)) | None => true,
Some(None) => false,
}
}
_ => false,
};
if should_redirect {
let loc = res.headers()
.get(LOCATION)
.and_then(|val| {
let loc = (|| -> Option<Url> {
// Some sites may send a utf-8 Location header,
// even though we're supposed to treat those bytes
// as opaque, we'll check specifically for utf8.
self.url.join(str::from_utf8(val.as_bytes()).ok()?).ok()
})();
let loc = res.headers().get(LOCATION).and_then(|val| {
let loc = (|| -> Option<Url> {
// Some sites may send a utf-8 Location header,
// even though we're supposed to treat those bytes
// as opaque, we'll check specifically for utf8.
self.url.join(str::from_utf8(val.as_bytes()).ok()?).ok()
})();
// Check that the `url` is also a valid `http::Uri`.
//
// If not, just log it and skip the redirect.
let loc = loc.and_then(|url| {
if try_uri(&url).is_some() {
Some(url)
} else {
None
}
});
if loc.is_none() {
debug!("Location header had invalid URI: {:?}", val);
// Check that the `url` is also a valid `http::Uri`.
//
// If not, just log it and skip the redirect.
let loc = loc.and_then(|url| {
if try_uri(&url).is_some() {
Some(url)
} else {
None
}
loc
});
if loc.is_none() {
debug!("Location header had invalid URI: {:?}", val);
}
loc
});
if let Some(loc) = loc {
if self.client.referer {
if let Some(referer) = make_referer(&loc, &self.url) {
@@ -812,11 +796,10 @@ impl Future for PendingRequest {
}
}
self.urls.push(self.url.clone());
let action = self.client.redirect_policy.check(
res.status(),
&loc,
&self.urls,
);
let action = self
.client
.redirect_policy
.check(res.status(), &loc, &self.urls);
match action {
redirect::Action::Follow => {
@@ -844,13 +827,13 @@ impl Future for PendingRequest {
*req.headers_mut() = self.headers.clone();
self.in_flight = self.client.hyper.request(req);
continue;
},
}
redirect::Action::Stop => {
debug!("redirect_policy disallowed redirection to '{}'", loc);
},
}
redirect::Action::LoopDetected => {
return Err(crate::error::loop_detected(self.url.clone()));
},
}
redirect::Action::TooManyRedirects => {
return Err(crate::error::too_many_redirects(self.url.clone()));
}
@@ -866,17 +849,12 @@ impl Future for PendingRequest {
impl fmt::Debug for Pending {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.inner {
PendingInner::Request(ref req) => {
f.debug_struct("Pending")
.field("method", &req.method)
.field("url", &req.url)
.finish()
},
PendingInner::Error(ref err) => {
f.debug_struct("Pending")
.field("error", err)
.finish()
}
PendingInner::Request(ref req) => f
.debug_struct("Pending")
.field("method", &req.method)
.field("url", &req.url)
.finish(),
PendingInner::Error(ref err) => f.debug_struct("Pending").field("error", err).finish(),
}
}
}
@@ -903,7 +881,7 @@ fn add_cookie_header(headers: &mut HeaderMap, cookie_store: &cookie::CookieStore
if !header.is_empty() {
headers.insert(
crate::header::COOKIE,
HeaderValue::from_bytes(header.as_bytes()).unwrap()
HeaderValue::from_bytes(header.as_bytes()).unwrap(),
);
}
}

View File

@@ -20,18 +20,18 @@ The following types directly support the gzip compression case:
- `Pending` is a non-blocking constructor for a `Decoder` in case the body needs to be checked for EOF
*/
use std::fmt;
use std::mem;
use std::cmp;
use std::fmt;
use std::io::{self, Read};
use std::mem;
use bytes::{Buf, BufMut, BytesMut};
use flate2::read::GzDecoder;
use futures::{Async, Future, Poll, Stream};
use hyper::{HeaderMap};
use hyper::header::{CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING};
use hyper::HeaderMap;
use log::{warn};
use log::warn;
use super::{Body, Chunk};
use crate::error;
@@ -42,7 +42,7 @@ const INIT_BUFFER_SIZE: usize = 8192;
///
/// The inner decoder may be constructed asynchronously.
pub struct Decoder {
inner: Inner
inner: Inner,
}
enum Inner {
@@ -51,7 +51,7 @@ enum Inner {
/// A `Gzip` decoder will uncompress the gzipped response content before returning it.
Gzip(Gzip),
/// A decoder that doesn't have a value yet.
Pending(Pending)
Pending(Pending),
}
/// A future attempt to poll the response body for EOF so we know whether to use gzip or not.
@@ -68,8 +68,7 @@ struct Gzip {
impl fmt::Debug for Decoder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Decoder")
.finish()
f.debug_struct("Decoder").finish()
}
}
@@ -80,7 +79,7 @@ impl Decoder {
#[inline]
pub fn empty() -> Decoder {
Decoder {
inner: Inner::PlainText(Body::empty())
inner: Inner::PlainText(Body::empty()),
}
}
@@ -90,7 +89,7 @@ impl Decoder {
#[inline]
fn plain_text(body: Body) -> Decoder {
Decoder {
inner: Inner::PlainText(body)
inner: Inner::PlainText(body),
}
}
@@ -100,7 +99,9 @@ impl Decoder {
#[inline]
fn gzip(body: Body) -> Decoder {
Decoder {
inner: Inner::Pending(Pending { body: ReadableChunks::new(body) })
inner: Inner::Pending(Pending {
body: ReadableChunks::new(body),
}),
}
}
@@ -120,11 +121,11 @@ impl Decoder {
.get_all(CONTENT_ENCODING)
.iter()
.any(|enc| enc == "gzip");
content_encoding_gzip ||
headers
.get_all(TRANSFER_ENCODING)
.iter()
.any(|enc| enc == "gzip")
content_encoding_gzip
|| headers
.get_all(TRANSFER_ENCODING)
.iter()
.any(|enc| enc == "gzip")
};
if is_gzip {
if let Some(content_length) = headers.get(CONTENT_LENGTH) {
@@ -153,15 +154,13 @@ impl Stream for Decoder {
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// Do a read or poll for a pendidng decoder value.
let new_value = match self.inner {
Inner::Pending(ref mut future) => {
match future.poll() {
Ok(Async::Ready(inner)) => inner,
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => return Err(e)
}
Inner::Pending(ref mut future) => match future.poll() {
Ok(Async::Ready(inner)) => inner,
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => return Err(e),
},
Inner::PlainText(ref mut body) => return body.poll(),
Inner::Gzip(ref mut decoder) => return decoder.poll()
Inner::Gzip(ref mut decoder) => return decoder.poll(),
};
self.inner = new_value;
@@ -177,13 +176,13 @@ impl Future for Pending {
let body_state = match self.body.poll_stream() {
Ok(Async::Ready(state)) => state,
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => return Err(e)
Err(e) => return Err(e),
};
let body = mem::replace(&mut self.body, ReadableChunks::new(Body::empty()));
match body_state {
StreamState::Eof => Ok(Async::Ready(Inner::PlainText(Body::empty()))),
StreamState::HasMore => Ok(Async::Ready(Inner::Gzip(Gzip::new(body))))
StreamState::HasMore => Ok(Async::Ready(Inner::Gzip(Gzip::new(body)))),
}
}
}
@@ -258,7 +257,7 @@ enum StreamState {
/// More bytes can be read from the stream.
HasMore,
/// No more bytes can be read from the stream.
Eof
Eof,
}
impl<S> ReadableChunks<S> {
@@ -273,8 +272,7 @@ impl<S> ReadableChunks<S> {
impl<S> fmt::Debug for ReadableChunks<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ReadableChunks")
.finish()
f.debug_struct("ReadableChunks").finish()
}
}
@@ -296,20 +294,12 @@ where
} else {
return Ok(len);
}
},
ReadState::NotReady => {
match self.poll_stream() {
Ok(Async::Ready(StreamState::HasMore)) => continue,
Ok(Async::Ready(StreamState::Eof)) => {
return Ok(0)
},
Ok(Async::NotReady) => {
return Err(io::ErrorKind::WouldBlock.into())
},
Err(e) => {
return Err(error::into_io(e))
}
}
}
ReadState::NotReady => match self.poll_stream() {
Ok(Async::Ready(StreamState::HasMore)) => continue,
Ok(Async::Ready(StreamState::Eof)) => return Ok(0),
Ok(Async::NotReady) => return Err(io::ErrorKind::WouldBlock.into()),
Err(e) => return Err(error::into_io(e)),
},
ReadState::Eof => return Ok(0),
}
@@ -320,7 +310,8 @@ where
}
impl<S> ReadableChunks<S>
where S: Stream<Item = Chunk, Error = error::Error>
where
S: Stream<Item = Chunk, Error = error::Error>,
{
/// Poll the readiness of the inner reader.
///
@@ -332,16 +323,14 @@ impl<S> ReadableChunks<S>
self.state = ReadState::Ready(chunk);
Ok(Async::Ready(StreamState::HasMore))
},
}
Ok(Async::Ready(None)) => {
self.state = ReadState::Eof;
Ok(Async::Ready(StreamState::Eof))
},
Ok(Async::NotReady) => {
Ok(Async::NotReady)
},
Err(e) => Err(e)
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(e) => Err(e),
}
}
}

View File

@@ -2,10 +2,10 @@
use std::borrow::Cow;
use std::fmt;
use http::HeaderMap;
use mime_guess::Mime;
use url::percent_encoding::{self, EncodeSet, PATH_SEGMENT_ENCODE_SET};
use uuid::Uuid;
use http::HeaderMap;
use futures::Stream;
@@ -98,7 +98,7 @@ impl Form {
/// Consume this instance and transform into an instance of hyper::Body for use in a request.
pub(crate) fn stream(mut self) -> hyper::Body {
if self.inner.fields.is_empty(){
if self.inner.fields.is_empty() {
return hyper::Body::empty();
}
@@ -117,7 +117,7 @@ impl Form {
hyper::Body::wrap_stream(stream.chain(last))
}
/// Generate a hyper::Body stream for a single Part instance of a Form request.
/// Generate a hyper::Body stream for a single Part instance of a Form request.
pub(crate) fn part_stream<T>(&mut self, name: T, part: Part) -> hyper::Body
where
T: Into<Cow<'static, str>>,
@@ -126,12 +126,20 @@ impl Form {
let boundary = hyper::Body::from(format!("--{}\r\n", self.boundary()));
// append headers
let header = hyper::Body::from({
let mut h = self.inner.percent_encoding.encode_headers(&name.into(), &part.meta);
let mut h = self
.inner
.percent_encoding
.encode_headers(&name.into(), &part.meta);
h.extend_from_slice(b"\r\n\r\n");
h
});
// then append form data followed by terminating CRLF
hyper::Body::wrap_stream(boundary.chain(header).chain(hyper::Body::wrap_stream(part.value)).chain(hyper::Body::from("\r\n".to_owned())))
hyper::Body::wrap_stream(
boundary
.chain(header)
.chain(hyper::Body::wrap_stream(part.value))
.chain(hyper::Body::from("\r\n".to_owned())),
)
}
pub(crate) fn compute_length(&mut self) -> Option<u64> {
@@ -188,7 +196,9 @@ impl Part {
T::Item: Into<Chunk>,
T::Error: std::error::Error + Send + Sync,
{
Part::new(Body::wrap(hyper::Body::wrap_stream(value.map(|chunk| chunk.into()))))
Part::new(Body::wrap(hyper::Body::wrap_stream(
value.map(|chunk| chunk.into()),
)))
}
fn new(value: Body) -> Part {
@@ -306,7 +316,13 @@ impl<P: PartProps> FormParts<P> {
// in Reader. Not the cleanest solution because if that format string is
// ever changed then this formula needs to be changed too which is not an
// obvious dependency in the code.
length += 2 + self.boundary().len() as u64 + 2 + header_length as u64 + 4 + value_length + 2
length += 2
+ self.boundary().len() as u64
+ 2
+ header_length as u64
+ 4
+ value_length
+ 2
}
_ => return None,
}
@@ -340,7 +356,7 @@ impl PartMetadata {
PartMetadata {
mime: None,
file_name: None,
headers: HeaderMap::default()
headers: HeaderMap::default(),
}
}
@@ -358,11 +374,10 @@ impl PartMetadata {
}
}
impl PartMetadata {
pub(crate) fn fmt_fields<'f, 'fa, 'fb>(
&self,
debug_struct: &'f mut fmt::DebugStruct<'fa, 'fb>
debug_struct: &'f mut fmt::DebugStruct<'fa, 'fb>,
) -> &'f mut fmt::DebugStruct<'fa, 'fb> {
debug_struct
.field("mime", &self.mime)
@@ -377,22 +392,24 @@ pub(crate) struct AttrCharEncodeSet;
impl EncodeSet for AttrCharEncodeSet {
fn contains(&self, ch: u8) -> bool {
match ch as char {
'!' => false,
'#' => false,
'$' => false,
'&' => false,
'+' => false,
'-' => false,
'.' => false,
'^' => false,
'_' => false,
'`' => false,
'|' => false,
'~' => false,
_ => {
let is_alpha_numeric = ch >= 0x41 && ch <= 0x5a || ch >= 0x61 && ch <= 0x7a || ch >= 0x30 && ch <= 0x39;
!is_alpha_numeric
}
'!' => false,
'#' => false,
'$' => false,
'&' => false,
'+' => false,
'-' => false,
'.' => false,
'^' => false,
'_' => false,
'`' => false,
'|' => false,
'~' => false,
_ => {
let is_alpha_numeric = ch >= 0x41 && ch <= 0x5a
|| ch >= 0x61 && ch <= 0x7a
|| ch >= 0x30 && ch <= 0x39;
!is_alpha_numeric
}
}
}
}
@@ -417,36 +434,38 @@ impl PercentEncoding {
None => "".to_string(),
},
);
field.headers.iter().fold(s.into_bytes(), |mut header, (k,v)| {
header.extend_from_slice(b"\r\n");
header.extend_from_slice(k.as_str().as_bytes());
header.extend_from_slice(b": ");
header.extend_from_slice(v.as_bytes());
header
})
field
.headers
.iter()
.fold(s.into_bytes(), |mut header, (k, v)| {
header.extend_from_slice(b"\r\n");
header.extend_from_slice(k.as_str().as_bytes());
header.extend_from_slice(b": ");
header.extend_from_slice(v.as_bytes());
header
})
}
// According to RFC7578 Section 4.2, `filename*=` syntax is invalid.
// See https://github.com/seanmonstar/reqwest/issues/419.
fn format_filename(&self, filename: &str) -> String {
let legal_filename = filename.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\r", "\\\r")
.replace("\n", "\\\n");
let legal_filename = filename
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\r", "\\\r")
.replace("\n", "\\\n");
format!("filename=\"{}\"", legal_filename)
}
fn format_parameter(&self, name: &str, value: &str) -> String {
let legal_value = match *self {
PercentEncoding::PathSegment => {
percent_encoding::utf8_percent_encode(value, PATH_SEGMENT_ENCODE_SET)
.to_string()
},
percent_encoding::utf8_percent_encode(value, PATH_SEGMENT_ENCODE_SET).to_string()
}
PercentEncoding::AttrChar => {
percent_encoding::utf8_percent_encode(value, AttrCharEncodeSet)
.to_string()
},
PercentEncoding::NoOp => { value.to_string() },
percent_encoding::utf8_percent_encode(value, AttrCharEncodeSet).to_string()
}
PercentEncoding::NoOp => value.to_string(),
};
if value.len() == legal_value.len() {
// nothing has been percent encoded
@@ -477,38 +496,45 @@ mod tests {
#[test]
fn stream_to_end() {
let mut form = Form::new()
.part("reader1", Part::stream(futures::stream::once::<_, hyper::Error>(Ok(Chunk::from("part1".to_owned())))))
.part("key1", Part::text("value1"))
.part(
"key2",
Part::text("value2").mime(mime::IMAGE_BMP),
"reader1",
Part::stream(futures::stream::once::<_, hyper::Error>(Ok(Chunk::from(
"part1".to_owned(),
)))),
)
.part("reader2", Part::stream(futures::stream::once::<_, hyper::Error>(Ok(Chunk::from("part2".to_owned())))))
.part("key1", Part::text("value1"))
.part("key2", Part::text("value2").mime(mime::IMAGE_BMP))
.part(
"key3",
Part::text("value3").file_name("filename"),
);
"reader2",
Part::stream(futures::stream::once::<_, hyper::Error>(Ok(Chunk::from(
"part2".to_owned(),
)))),
)
.part("key3", Part::text("value3").file_name("filename"));
form.inner.boundary = "boundary".to_string();
let expected = "--boundary\r\n\
Content-Disposition: form-data; name=\"reader1\"\r\n\r\n\
part1\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
value1\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"key2\"\r\n\
Content-Type: image/bmp\r\n\r\n\
value2\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"reader2\"\r\n\r\n\
part2\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"key3\"; filename=\"filename\"\r\n\r\n\
value3\r\n--boundary--\r\n";
let expected =
"--boundary\r\n\
Content-Disposition: form-data; name=\"reader1\"\r\n\r\n\
part1\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
value1\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"key2\"\r\n\
Content-Type: image/bmp\r\n\r\n\
value2\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"reader2\"\r\n\r\n\
part2\r\n\
--boundary\r\n\
Content-Disposition: form-data; name=\"key3\"; filename=\"filename\"\r\n\r\n\
value3\r\n--boundary--\r\n";
let mut rt = tokio::runtime::current_thread::Runtime::new().expect("new rt");
let body_ft = form.stream();
let out = rt.block_on(body_ft.map(|c| c.into_bytes()).concat2()).unwrap();
let out = rt
.block_on(body_ft.map(|c| c.into_bytes()).concat2())
.unwrap();
// These prints are for debug purposes in case the test fails
println!(
"START REAL\n{}\nEND REAL",
@@ -534,7 +560,9 @@ mod tests {
let mut rt = tokio::runtime::current_thread::Runtime::new().expect("new rt");
let body_ft = form.stream();
let out = rt.block_on(body_ft.map(|c| c.into_bytes()).concat2()).unwrap();
let out = rt
.block_on(body_ft.map(|c| c.into_bytes()).concat2())
.unwrap();
// These prints are for debug purposes in case the test fails
println!(
"START REAL\n{}\nEND REAL",

View File

@@ -1,18 +1,18 @@
use std::fmt;
use base64::{encode};
use base64::encode;
use futures::Future;
use serde::Serialize;
use serde_json;
use serde_urlencoded;
use super::body::{Body};
use super::body::Body;
use super::client::{Client, Pending};
use super::multipart;
use super::response::Response;
use crate::header::{CONTENT_LENGTH, CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue};
use http::HttpTryFrom;
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_LENGTH, CONTENT_TYPE};
use crate::{Method, Url};
use http::HttpTryFrom;
/// A request which can be executed with `Client::execute()`.
pub struct Request {
@@ -95,10 +95,7 @@ impl Request {
impl RequestBuilder {
pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
RequestBuilder {
client,
request,
}
RequestBuilder { client, request }
}
/// Add a `Header` to this Request.
@@ -110,11 +107,11 @@ impl RequestBuilder {
let mut error = None;
if let Ok(ref mut req) = self.request {
match <HeaderName as HttpTryFrom<K>>::try_from(key) {
Ok(key) => {
match <HeaderValue as HttpTryFrom<V>>::try_from(value) {
Ok(value) => { req.headers_mut().append(key, value); }
Err(e) => error = Some(crate::error::from(e.into())),
Ok(key) => match <HeaderValue as HttpTryFrom<V>>::try_from(value) {
Ok(value) => {
req.headers_mut().append(key, value);
}
Err(e) => error = Some(crate::error::from(e.into())),
},
Err(e) => error = Some(crate::error::from(e.into())),
};
@@ -168,7 +165,7 @@ impl RequestBuilder {
{
let auth = match password {
Some(password) => format!("{}:{}", username, password),
None => format!("{}:", username)
None => format!("{}:", username),
};
let header_value = format!("Basic {}", encode(&auth));
self.header(crate::header::AUTHORIZATION, &*header_value)
@@ -221,10 +218,7 @@ impl RequestBuilder {
pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
let mut builder = self.header(
CONTENT_TYPE,
format!(
"multipart/form-data; boundary={}",
multipart.boundary()
).as_str()
format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
);
builder = match multipart.compute_length() {
@@ -286,10 +280,10 @@ impl RequestBuilder {
Ok(body) => {
req.headers_mut().insert(
CONTENT_TYPE,
HeaderValue::from_static("application/x-www-form-urlencoded")
HeaderValue::from_static("application/x-www-form-urlencoded"),
);
*req.body_mut() = Some(body.into());
},
}
Err(err) => error = Some(crate::error::from(err)),
}
}
@@ -310,12 +304,10 @@ impl RequestBuilder {
if let Ok(ref mut req) = self.request {
match serde_json::to_vec(json) {
Ok(body) => {
req.headers_mut().insert(
CONTENT_TYPE,
HeaderValue::from_static("application/json")
);
req.headers_mut()
.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
*req.body_mut() = Some(body.into());
},
}
Err(err) => error = Some(crate::error::from(err)),
}
}
@@ -368,8 +360,7 @@ impl RequestBuilder {
impl fmt::Debug for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_request_fields(&mut f.debug_struct("Request"), self)
.finish()
fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
}
}
@@ -377,27 +368,22 @@ impl fmt::Debug for RequestBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut builder = f.debug_struct("RequestBuilder");
match self.request {
Ok(ref req) => {
fmt_request_fields(&mut builder, req)
.finish()
},
Err(ref err) => {
builder
.field("error", err)
.finish()
}
Ok(ref req) => fmt_request_fields(&mut builder, req).finish(),
Err(ref err) => builder.field("error", err).finish(),
}
}
}
fn fmt_request_fields<'a, 'b>(f: &'a mut fmt::DebugStruct<'a, 'b>, req: &Request) -> &'a mut fmt::DebugStruct<'a, 'b> {
fn fmt_request_fields<'a, 'b>(
f: &'a mut fmt::DebugStruct<'a, 'b>,
req: &Request,
) -> &'a mut fmt::DebugStruct<'a, 'b> {
f.field("method", &req.method)
.field("url", &req.url)
.field("headers", &req.headers)
}
pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
// IntoIter of HeaderMap yields (Option<HeaderName>, HeaderValue).
// The first time a name is yielded, it will be Some(name), and if
// there are more values with the same name, the next yield will be
@@ -413,11 +399,11 @@ pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
Some(key) => {
dst.insert(key.clone(), value);
prev_name = Some(key);
},
}
None => match prev_name {
Some(ref key) => {
dst.append(key.clone(), value);
},
}
None => unreachable!("HeaderMap::into_iter yielded None first"),
},
}
@@ -427,8 +413,8 @@ pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
#[cfg(test)]
mod tests {
use super::Client;
use std::collections::BTreeMap;
use serde::Serialize;
use std::collections::BTreeMap;
#[test]
fn add_query_append() {
@@ -467,7 +453,10 @@ mod tests {
let some_url = "https://google.com/";
let r = client.get(some_url);
let params = Params { foo: "bar".into(), qux: 3 };
let params = Params {
foo: "bar".into(),
qux: 3,
};
let r = r.query(&params);
@@ -510,11 +499,7 @@ mod tests {
assert_eq!(req.headers()["im-a"], "keeper");
let foo = req
.headers()
.get_all("foo")
.iter()
.collect::<Vec<_>>();
let foo = req.headers().get_all("foo").iter().collect::<Vec<_>>();
assert_eq!(foo.len(), 2);
assert_eq!(foo[0], "bar");
assert_eq!(foo[1], "baz");

View File

@@ -1,28 +1,26 @@
use std::fmt;
use std::mem;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::net::SocketAddr;
use encoding_rs::{Encoding, UTF_8};
use futures::{Async, Future, Poll, Stream, try_ready};
use futures::stream::Concat2;
use futures::{try_ready, Async, Future, Poll, Stream};
use http;
use hyper::{HeaderMap, StatusCode, Version};
use hyper::client::connect::HttpInfo;
use hyper::header::{CONTENT_LENGTH};
use hyper::header::CONTENT_LENGTH;
use hyper::{HeaderMap, StatusCode, Version};
use log::debug;
use mime::Mime;
use tokio::timer::Delay;
use serde::de::DeserializeOwned;
use serde_json;
use tokio::timer::Delay;
use url::Url;
use log::{debug};
use crate::cookie;
use super::Decoder;
use super::body::Body;
use super::Decoder;
use crate::cookie;
/// A Response to a submitted `Request`.
pub struct Response {
@@ -37,7 +35,12 @@ pub struct Response {
}
impl Response {
pub(super) fn new(res: hyper::Response<hyper::Body>, url: Url, gzip: bool, timeout: Option<Delay>) -> Response {
pub(super) fn new(
res: hyper::Response<hyper::Body>,
url: Url,
gzip: bool,
timeout: Option<Delay>,
) -> Response {
let (parts, body) = res.into_parts();
let status = parts.status;
let version = parts.version;
@@ -57,7 +60,6 @@ impl Response {
}
}
/// Get the `StatusCode` of this `Response`.
#[inline]
pub fn status(&self) -> StatusCode {
@@ -77,11 +79,10 @@ impl Response {
}
/// Retrieve the cookies contained in the response.
///
///
/// Note that invalid 'Set-Cookie' headers will be ignored.
pub fn cookies<'a>(&'a self) -> impl Iterator<Item = cookie::Cookie<'a>> + 'a {
cookie::extract_response_cookies(&self.headers)
.filter_map(Result::ok)
cookie::extract_response_cookies(&self.headers).filter_map(Result::ok)
}
/// Get the final `Url` of this `Response`.
@@ -92,8 +93,7 @@ impl Response {
/// Get the remote address used to get this `Response`.
pub fn remote_addr(&self) -> Option<SocketAddr> {
self
.extensions
self.extensions
.get::<HttpInfo>()
.map(|info| info.remote_addr())
}
@@ -106,8 +106,7 @@ impl Response {
/// - The response is gzipped and automatically decoded (thus changing
/// the actual decoded length).
pub fn content_length(&self) -> Option<u64> {
self
.headers()
self.headers()
.get(CONTENT_LENGTH)
.and_then(|ct_len| ct_len.to_str().ok())
.and_then(|ct_len| ct_len.parse().ok())
@@ -145,27 +144,24 @@ impl Response {
}
/// Get the response text given a specific encoding
pub fn text_with_charset(&mut self, default_encoding: &str) -> impl Future<Item = String, Error = crate::Error> {
pub fn text_with_charset(
&mut self,
default_encoding: &str,
) -> impl Future<Item = String, Error = crate::Error> {
let body = mem::replace(&mut self.body, Decoder::empty());
let content_type = self.headers.get(crate::header::CONTENT_TYPE)
.and_then(|value| {
value.to_str().ok()
})
.and_then(|value| {
value.parse::<Mime>().ok()
});
let content_type = self
.headers
.get(crate::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse::<Mime>().ok());
let encoding_name = content_type
.as_ref()
.and_then(|mime| {
mime
.get_param("charset")
.map(|charset| charset.as_str())
})
.and_then(|mime| mime.get_param("charset").map(|charset| charset.as_str()))
.unwrap_or(default_encoding);
let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
Text {
concat: body.concat2(),
encoding
encoding,
}
}
@@ -256,7 +252,8 @@ impl<T: Into<Body>> From<http::Response<T>> for Response {
let (mut parts, body) = r.into_parts();
let body = body.into();
let body = Decoder::detect(&mut parts.headers, body, false);
let url = parts.extensions
let url = parts
.extensions
.remove::<ResponseUrl>()
.unwrap_or_else(|| ResponseUrl(Url::parse("http://no.url.provided.local").unwrap()));
let url = url.0;
@@ -289,8 +286,7 @@ impl<T: DeserializeOwned> Future for Json<T> {
impl<T> fmt::Debug for Json<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Json")
.finish()
f.debug_struct("Json").finish()
}
}
@@ -308,7 +304,9 @@ impl Future for Text {
// a block because of borrow checker
{
let (text, _, _) = self.encoding.decode(&bytes);
if let Cow::Owned(s) = text { return Ok(Async::Ready(s)) }
if let Cow::Owned(s) = text {
return Ok(Async::Ready(s));
}
}
unsafe {
// decoding returned Cow::Borrowed, meaning these bytes
@@ -357,9 +355,9 @@ impl ResponseBuilderExt for http::response::Builder {
#[cfg(test)]
mod tests {
use url::Url;
use super::{Response, ResponseBuilderExt, ResponseUrl};
use http::response::Builder;
use super::{Response, ResponseUrl, ResponseBuilderExt};
use url::Url;
#[test]
fn test_response_builder_ext() {
@@ -370,7 +368,10 @@ mod tests {
.body(())
.unwrap();
assert_eq!(response.extensions().get::<ResponseUrl>(), Some(&ResponseUrl(url)));
assert_eq!(
response.extensions().get::<ResponseUrl>(),
Some(&ResponseUrl(url))
);
}
#[test]