refactor all to async/await (#617)

Co-authored-by: Danny Browning <danny.browning@protectwise.com>
Co-authored-by: Daniel Eades <danieleades@hotmail.com>
This commit is contained in:
Sean McArthur
2019-09-06 17:22:56 -07:00
committed by GitHub
parent d7fcd8ac2e
commit ba7b2a754e
30 changed files with 1106 additions and 1430 deletions

View File

@@ -8,12 +8,14 @@ use crate::header::{
CONTENT_TYPE, LOCATION, PROXY_AUTHORIZATION, RANGE, REFERER, TRANSFER_ENCODING, USER_AGENT,
};
use bytes::Bytes;
use futures::{Async, Future, Poll};
use http::Uri;
use hyper::client::ResponseFuture;
use mime;
#[cfg(feature = "default-tls")]
use native_tls::TlsConnector;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::{clock, timer::Delay};
use log::debug;
@@ -540,7 +542,10 @@ impl Client {
///
/// This method fails if there was an error while sending request,
/// redirect loop was detected or redirect limit was exhausted.
pub fn execute(&self, request: Request) -> impl Future<Item = Response, Error = crate::Error> {
pub fn execute(
&self,
request: Request,
) -> impl Future<Output = Result<Response, crate::Error>> {
self.execute_request(request)
}
@@ -593,7 +598,7 @@ impl Client {
let timeout = self
.inner
.request_timeout
.map(|dur| Delay::new(clock::now() + dur));
.map(|dur| tokio::timer::delay(clock::now() + dur));
Pending {
inner: PendingInner::Request(PendingRequest {
@@ -691,43 +696,65 @@ struct PendingRequest {
timeout: Option<Delay>,
}
impl PendingRequest {
fn in_flight(self: Pin<&mut Self>) -> Pin<&mut ResponseFuture> {
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.in_flight) }
}
fn timeout(self: Pin<&mut Self>) -> Pin<&mut Option<Delay>> {
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.timeout) }
}
fn urls(self: Pin<&mut Self>) -> &mut Vec<Url> {
unsafe { &mut Pin::get_unchecked_mut(self).urls }
}
fn headers(self: Pin<&mut Self>) -> &mut HeaderMap {
unsafe { &mut Pin::get_unchecked_mut(self).headers }
}
}
impl Pending {
pub(super) fn new_err(err: crate::Error) -> Pending {
Pending {
inner: PendingInner::Error(Some(err)),
}
}
fn inner(self: Pin<&mut Self>) -> Pin<&mut PendingInner> {
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.inner) }
}
}
impl Future for Pending {
type Item = Response;
type Error = crate::Error;
type Output = Result<Response, crate::Error>;
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"))
}
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let inner = self.inner();
match inner.get_mut() {
PendingInner::Request(ref mut req) => Pin::new(req).poll(cx),
PendingInner::Error(ref mut err) => Poll::Ready(Err(err
.take()
.expect("Pending error polled more than once"))),
}
}
}
impl Future for PendingRequest {
type Item = Response;
type Error = crate::Error;
type Output = Result<Response, crate::Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(ref mut delay) = self.timeout {
if let Async::Ready(()) = try_!(delay.poll(), &self.url) {
return Err(crate::error::timedout(Some(self.url.clone())));
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(delay) = self.as_mut().timeout().as_mut().as_pin_mut() {
if let Poll::Ready(()) = delay.poll(cx) {
return Poll::Ready(Err(crate::error::timedout(Some(self.url.clone()))));
}
}
loop {
let res = match try_!(self.in_flight.poll(), &self.url) {
Async::Ready(res) => res,
Async::NotReady => return Ok(Async::NotReady),
let res = match self.as_mut().in_flight().as_mut().poll(cx) {
Poll::Ready(Err(e)) => return Poll::Ready(url_error!(e, &self.url)),
Poll::Ready(Ok(res)) => res,
Poll::Pending => return Poll::Pending,
};
if let Some(store_wrapper) = self.client.cookie_store.as_ref() {
let mut store = store_wrapper.write().unwrap();
@@ -795,7 +822,8 @@ impl Future for PendingRequest {
self.headers.insert(REFERER, referer);
}
}
self.urls.push(self.url.clone());
let url = self.url.clone();
self.as_mut().urls().push(url);
let action = self
.client
.redirect_policy
@@ -805,7 +833,10 @@ impl Future for PendingRequest {
redirect::Action::Follow => {
self.url = loc;
remove_sensitive_headers(&mut self.headers, &self.url, &self.urls);
let mut headers =
std::mem::replace(self.as_mut().headers(), HeaderMap::new());
remove_sensitive_headers(&mut headers, &self.url, &self.urls);
debug!("redirecting to {:?} '{}'", self.method, self.url);
let uri = expect_uri(&self.url);
let body = match self.body {
@@ -821,27 +852,30 @@ impl Future for PendingRequest {
// Add cookies from the cookie store.
if let Some(cookie_store_wrapper) = self.client.cookie_store.as_ref() {
let cookie_store = cookie_store_wrapper.read().unwrap();
add_cookie_header(&mut self.headers, &cookie_store, &self.url);
add_cookie_header(&mut headers, &cookie_store, &self.url);
}
*req.headers_mut() = self.headers.clone();
self.in_flight = self.client.hyper.request(req);
*req.headers_mut() = headers.clone();
std::mem::swap(self.as_mut().headers(), &mut headers);
*self.as_mut().in_flight().get_mut() = 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()));
return Poll::Ready(Err(crate::error::loop_detected(self.url.clone())));
}
redirect::Action::TooManyRedirects => {
return Err(crate::error::too_many_redirects(self.url.clone()));
return Poll::Ready(Err(crate::error::too_many_redirects(
self.url.clone(),
)));
}
}
}
}
let res = Response::new(res, self.url.clone(), self.client.gzip, self.timeout.take());
return Ok(Async::Ready(res));
return Poll::Ready(Ok(res));
}
}
}