feat(lib): update Tokio, bytes, http, h2, and http-body

This commit is contained in:
Sean McArthur
2019-12-03 14:36:20 -08:00
parent 131962c86a
commit cb3f39c2dc
51 changed files with 985 additions and 1305 deletions

View File

@@ -30,6 +30,7 @@ use std::net::{
};
use std::str::FromStr;
use tokio::task::JoinHandle;
use tower_service::Service;
use crate::common::{Future, Pin, Poll, task};
@@ -54,7 +55,7 @@ pub struct GaiAddrs {
/// A future to resolve a name returned by `GaiResolver`.
pub struct GaiFuture {
inner: tokio_executor::blocking::Blocking<Result<IpAddrs, io::Error>>,
inner: JoinHandle<Result<IpAddrs, io::Error>>,
}
impl Name {
@@ -123,7 +124,7 @@ impl Service<Name> for GaiResolver {
}
fn call(&mut self, name: Name) -> Self::Future {
let blocking = tokio_executor::blocking::run(move || {
let blocking = tokio::task::spawn_blocking(move || {
debug!("resolving host={:?}", name.host);
(&*name.host, 0).to_socket_addrs()
.map(|i| IpAddrs { iter: i })
@@ -146,8 +147,9 @@ impl Future for GaiFuture {
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.inner).poll(cx).map(|res| match res {
Ok(addrs) => Ok(GaiAddrs { inner: addrs }),
Err(err) => Err(err),
Ok(Ok(addrs)) => Ok(GaiAddrs { inner: addrs }),
Ok(Err(err)) => Err(err),
Err(join_err) => panic!("gai background task failed: {:?}", join_err),
})
}
}
@@ -232,6 +234,7 @@ impl Iterator for IpAddrs {
}
}
/*
/// A resolver using `getaddrinfo` calls via the `tokio_executor::threadpool::blocking` API.
///
/// Unlike the `GaiResolver` this will not spawn dedicated threads, but only works when running on the
@@ -286,6 +289,7 @@ impl Future for TokioThreadpoolGaiFuture {
}
}
}
*/
mod sealed {
use tower_service::Service;

View File

@@ -7,17 +7,16 @@ use std::sync::Arc;
use std::time::Duration;
use http::uri::{Scheme, Uri};
use futures_util::{TryFutureExt, FutureExt};
use futures_util::{TryFutureExt};
use net2::TcpBuilder;
use pin_project::{pin_project, project};
use tokio_net::driver::Handle;
use tokio_net::tcp::TcpStream;
use tokio_timer::{Delay, Timeout};
use tokio::net::TcpStream;
use tokio::time::Delay;
use crate::common::{Future, Pin, Poll, task};
use super::{Connected, Destination};
use super::dns::{self, GaiResolver, Resolve};
#[cfg(feature = "runtime")] use super::dns::TokioThreadpoolGaiResolver;
//#[cfg(feature = "runtime")] use super::dns::TokioThreadpoolGaiResolver;
// TODO: unbox me?
type ConnectFuture = Pin<Box<dyn Future<Output = io::Result<TcpStream>> + Send>>;
@@ -73,7 +72,6 @@ pub struct HttpInfo {
struct Config {
connect_timeout: Option<Duration>,
enforce_http: bool,
handle: Option<Handle>,
happy_eyeballs_timeout: Option<Duration>,
keep_alive_timeout: Option<Duration>,
local_address: Option<IpAddr>,
@@ -92,6 +90,7 @@ impl HttpConnector {
}
}
/*
#[cfg(feature = "runtime")]
impl HttpConnector<TokioThreadpoolGaiResolver> {
/// Construct a new HttpConnector using the `TokioThreadpoolGaiResolver`.
@@ -101,6 +100,7 @@ impl HttpConnector<TokioThreadpoolGaiResolver> {
HttpConnector::new_with_resolver(TokioThreadpoolGaiResolver::new())
}
}
*/
impl<R> HttpConnector<R> {
@@ -112,7 +112,6 @@ impl<R> HttpConnector<R> {
config: Arc::new(Config {
connect_timeout: None,
enforce_http: true,
handle: None,
happy_eyeballs_timeout: Some(Duration::from_millis(300)),
keep_alive_timeout: None,
local_address: None,
@@ -133,14 +132,6 @@ impl<R> HttpConnector<R> {
self.config_mut().enforce_http = is_enforced;
}
/// Set a handle to a `Reactor` to register connections to.
///
/// If `None`, the implicit default reactor will be used.
#[inline]
pub fn set_reactor(&mut self, handle: Option<Handle>) {
self.config_mut().handle = handle;
}
/// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
///
/// If `None`, the option will not be set.
@@ -276,10 +267,10 @@ where
);
if self.config.enforce_http {
if dst.uri.scheme_part() != Some(&Scheme::HTTP) {
if dst.uri.scheme() != Some(&Scheme::HTTP) {
return self.invalid_url(INVALID_NOT_HTTP);
}
} else if dst.uri.scheme_part().is_none() {
} else if dst.uri.scheme().is_none() {
return self.invalid_url(INVALID_MISSING_SCHEME);
}
@@ -287,9 +278,9 @@ where
Some(s) => s,
None => return self.invalid_url(INVALID_MISSING_HOST),
};
let port = match dst.uri.port_part() {
let port = match dst.uri.port() {
Some(port) => port.as_u16(),
None => if dst.uri.scheme_part() == Some(&Scheme::HTTPS) { 443 } else { 80 },
None => if dst.uri.scheme() == Some(&Scheme::HTTPS) { 443 } else { 80 },
};
HttpConnecting {
@@ -314,10 +305,7 @@ where
}
fn call(&mut self, uri: Uri) -> Self::Future {
self
.call(Destination { uri })
.map_ok(|(s, _)| s)
.boxed()
Box::pin(self.call(Destination { uri }).map_ok(|(s, _)| s))
}
}
@@ -447,7 +435,7 @@ impl<R: Resolve> Future for HttpConnecting<R> {
config.local_address, addrs, config.connect_timeout, config.happy_eyeballs_timeout, config.reuse_address));
},
State::Connecting(ref mut c) => {
let sock = ready!(c.poll(cx, &config.handle))
let sock = ready!(c.poll(cx))
.map_err(ConnectError::m("tcp connect error"))?;
if let Some(dur) = config.keep_alive_timeout {
@@ -515,7 +503,7 @@ impl ConnectingTcp {
local_addr,
preferred: ConnectingTcpRemote::new(preferred_addrs, connect_timeout),
fallback: Some(ConnectingTcpFallback {
delay: tokio_timer::delay_for(fallback_timeout),
delay: tokio::time::delay_for(fallback_timeout),
remote: ConnectingTcpRemote::new(fallback_addrs, connect_timeout),
}),
reuse_address,
@@ -555,12 +543,10 @@ impl ConnectingTcpRemote {
}
impl ConnectingTcpRemote {
// not a Future, since passing a &Handle to poll
fn poll(
&mut self,
cx: &mut task::Context<'_>,
local_addr: &Option<IpAddr>,
handle: &Option<Handle>,
reuse_address: bool,
) -> Poll<io::Result<TcpStream>> {
let mut err = None;
@@ -577,14 +563,14 @@ impl ConnectingTcpRemote {
err = Some(e);
if let Some(addr) = self.addrs.next() {
debug!("connecting to {}", addr);
*current = connect(&addr, local_addr, handle, reuse_address, self.connect_timeout)?;
*current = connect(&addr, local_addr, reuse_address, self.connect_timeout)?;
continue;
}
}
}
} else if let Some(addr) = self.addrs.next() {
debug!("connecting to {}", addr);
self.current = Some(connect(&addr, local_addr, handle, reuse_address, self.connect_timeout)?);
self.current = Some(connect(&addr, local_addr, reuse_address, self.connect_timeout)?);
continue;
}
@@ -596,7 +582,6 @@ impl ConnectingTcpRemote {
fn connect(
addr: &SocketAddr,
local_addr: &Option<IpAddr>,
handle: &Option<Handle>,
reuse_address: bool,
connect_timeout: Option<Duration>,
) -> io::Result<ConnectFuture> {
@@ -625,18 +610,14 @@ fn connect(
builder.bind(any)?;
}
let handle = match *handle {
Some(ref handle) => handle.clone(),
None => Handle::default(),
};
let addr = *addr;
let std_tcp = builder.to_tcp_stream()?;
Ok(Box::pin(async move {
let connect = TcpStream::connect_std(std_tcp, &addr, &handle);
let connect = TcpStream::connect_std(std_tcp, &addr);
match connect_timeout {
Some(timeout) => match Timeout::new(connect, timeout).await {
Some(dur) => match tokio::time::timeout(dur, connect).await {
Ok(Ok(s)) => Ok(s),
Ok(Err(e)) => Err(e),
Err(e) => Err(io::Error::new(io::ErrorKind::TimedOut, e)),
@@ -647,16 +628,16 @@ fn connect(
}
impl ConnectingTcp {
fn poll(&mut self, cx: &mut task::Context<'_>, handle: &Option<Handle>) -> Poll<io::Result<TcpStream>> {
fn poll(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<TcpStream>> {
match self.fallback.take() {
None => self.preferred.poll(cx, &self.local_addr, handle, self.reuse_address),
Some(mut fallback) => match self.preferred.poll(cx, &self.local_addr, handle, self.reuse_address) {
None => self.preferred.poll(cx, &self.local_addr, self.reuse_address),
Some(mut fallback) => match self.preferred.poll(cx, &self.local_addr, self.reuse_address) {
Poll::Ready(Ok(stream)) => {
// Preferred successful - drop fallback.
Poll::Ready(Ok(stream))
}
Poll::Pending => match Pin::new(&mut fallback.delay).poll(cx) {
Poll::Ready(()) => match fallback.remote.poll(cx, &self.local_addr, handle, self.reuse_address) {
Poll::Ready(()) => match fallback.remote.poll(cx, &self.local_addr, self.reuse_address) {
Poll::Ready(Ok(stream)) => {
// Fallback successful - drop current preferred,
// but keep fallback as new preferred.
@@ -682,7 +663,7 @@ impl ConnectingTcp {
Poll::Ready(Err(_)) => {
// Preferred failed - use fallback as new preferred.
self.preferred = fallback.remote;
self.preferred.poll(cx, &self.local_addr, handle, self.reuse_address)
self.preferred.poll(cx, &self.local_addr, self.reuse_address)
}
}
}
@@ -693,8 +674,6 @@ impl ConnectingTcp {
mod tests {
use std::io;
use tokio_net::driver::Handle;
use super::{Connected, Destination, HttpConnector};
use super::super::sealed::Connect;
@@ -738,8 +717,6 @@ mod tests {
use std::task::Poll;
use std::time::{Duration, Instant};
use tokio::runtime::current_thread::Runtime;
use crate::common::{Pin, task};
use super::dns;
use super::ConnectingTcp;
@@ -748,7 +725,12 @@ mod tests {
let server4 = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = server4.local_addr().unwrap();
let _server6 = TcpListener::bind(&format!("[::1]:{}", addr.port())).unwrap();
let mut rt = Runtime::new().unwrap();
let mut rt = tokio::runtime::Builder::new()
.enable_io()
.enable_time()
.basic_scheduler()
.build()
.unwrap();
let local_timeout = Duration::default();
let unreachable_v4_timeout = measure_connect(unreachable_ipv4_addr()).1;
@@ -804,12 +786,13 @@ mod tests {
}
let addrs = hosts.iter().map(|host| (host.clone(), addr.port()).into()).collect();
let connecting_tcp = ConnectingTcp::new(None, dns::IpAddrs::new(addrs), None, Some(fallback_timeout), false);
let fut = ConnectingTcpFuture(connecting_tcp);
let start = Instant::now();
let res = rt.block_on(fut).unwrap();
let duration = start.elapsed();
let (res, duration) = rt.block_on(async move {
let connecting_tcp = ConnectingTcp::new(None, dns::IpAddrs::new(addrs), None, Some(fallback_timeout), false);
let fut = ConnectingTcpFuture(connecting_tcp);
let start = Instant::now();
let res = fut.await.unwrap();
(res, start.elapsed())
});
// Allow actual duration to be +/- 150ms off.
let min_duration = if timeout >= Duration::from_millis(150) {
@@ -830,7 +813,7 @@ mod tests {
type Output = Result<u8, std::io::Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match self.0.poll(cx,&Some(Handle::default())) {
match self.0.poll(cx) {
Poll::Ready(Ok(stream)) => Poll::Ready(Ok(
if stream.peer_addr().unwrap().is_ipv4() { 4 } else { 6 }
)),

View File

@@ -50,8 +50,8 @@ impl Destination {
/// Returns an error if the uri contains no authority or
/// no scheme.
pub fn try_from_uri(uri: Uri) -> crate::Result<Self> {
uri.authority_part().ok_or(crate::error::Parse::Uri)?;
uri.scheme_part().ok_or(crate::error::Parse::Uri)?;
uri.authority().ok_or(crate::error::Parse::Uri)?;
uri.scheme().ok_or(crate::error::Parse::Uri)?;
Ok(Destination { uri })
}
@@ -131,11 +131,11 @@ impl Destination {
}
let auth = if let Some(port) = self.port() {
let bytes = Bytes::from(format!("{}:{}", host, port));
uri::Authority::from_shared(bytes)
uri::Authority::from_maybe_shared(bytes)
.map_err(crate::error::Parse::from)?
} else {
let auth = host.parse::<uri::Authority>().map_err(crate::error::Parse::from)?;
if auth.port_part().is_some() { // std::uri::Authority::Uri
if auth.port().is_some() { // std::uri::Authority::Uri
return Err(crate::error::Parse::Uri.into());
}
auth
@@ -186,7 +186,7 @@ impl Destination {
write!(buf, "{}", port)
.expect("should have space for 5 digits");
uri::Authority::from_shared(buf.freeze())
uri::Authority::from_maybe_shared(buf.freeze())
.expect("valid host + :port should be valid authority")
} else {
self.host().parse()
@@ -372,7 +372,7 @@ where
pub(super) mod sealed {
use std::error::Error as StdError;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::common::{Future, Unpin};
use super::{Connected, Destination};