feat(lib): update to std::future::Future

BREAKING CHANGE: All usage of async traits (`Future`, `Stream`,
`AsyncRead`, `AsyncWrite`, etc) are updated to newer versions.
This commit is contained in:
Sean McArthur
2019-07-09 15:37:43 -07:00
parent da9b0319ef
commit 8f4b05ae78
37 changed files with 1526 additions and 1548 deletions

View File

@@ -1,32 +1,34 @@
language: rust language: rust
sudo: true # Required for functional IPv6 (forces VM instead of Docker). #sudo: true # Required for functional IPv6 (forces VM instead of Docker).
dist: trusty dist: trusty
matrix: matrix:
fast_finish: true fast_finish: true
include: include:
- rust: nightly - rust: nightly
env: FEATURES="--no-default-features --features runtime,nightly" env: FEATURES="--no-default-features --features runtime,nightly"
- rust: beta # Dependencies may be using the unstable `async_await` feature for now...
env: FEATURES="--no-default-features --features runtime,__internal_happy_eyeballs_tests" #- rust: beta
- rust: stable # env: FEATURES="--no-default-features --features runtime,__internal_happy_eyeballs_tests"
env: FEATURES="--no-default-features --features runtime,__internal_happy_eyeballs_tests" #- rust: stable
- rust: stable # env: FEATURES="--no-default-features --features runtime,__internal_happy_eyeballs_tests"
env: FEATURES="--no-default-features" #- rust: stable
# env: FEATURES="--no-default-features"
# Minimum Supported Rust Version # Minimum Supported Rust Version
- rust: 1.31.0 #- rust: 1.36.0
env: FEATURES="--no-default-features --features runtime" BUILD_ONLY="1" # env: FEATURES="--no-default-features --features runtime" BUILD_ONLY="1"
before_script: #before_script:
# Add an IPv6 config - see the corresponding Travis issue # Add an IPv6 config - see the corresponding Travis issue
# https://github.com/travis-ci/travis-ci/issues/8361 # https://github.com/travis-ci/travis-ci/issues/83
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then #- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'; # sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6';
fi # fi
script: script:
- cargo build $FEATURES - cargo build $FEATURES
- 'if [ "$BUILD_ONLY" != "1" ]; then cargo test $FEATURES -- --test-threads=1; fi' # Disable tests temporarily
- 'if [ $TRAVIS_RUST_VERSION = nightly ]; then for f in ./benches/*.rs; do cargo test --bench $(basename $f .rs) $FEATURES; done; fi' # - 'if [ "$BUILD_ONLY" != "1" ]; then cargo test $FEATURES -- --test-threads=1; fi'
# - 'if [ $TRAVIS_RUST_VERSION = nightly ]; then for f in ./benches/*.rs; do cargo test --bench $(basename $f .rs) $FEATURES; done; fi'
env: env:
global: global:

View File

@@ -23,8 +23,9 @@ include = [
[dependencies] [dependencies]
bytes = "0.4.4" bytes = "0.4.4"
futures = "0.1.21" futures-core-preview = { version = "0.3.0-alpha.16" }
futures-cpupool = { version = "0.1.6", optional = true } futures-channel-preview = { version = "0.3.0-alpha.16" }
futures-util-preview = { version = "0.3.0-alpha.16" }
http = "0.1.15" http = "0.1.15"
http-body = "0.1" http-body = "0.1"
httparse = "1.0" httparse = "1.0"
@@ -33,28 +34,30 @@ iovec = "0.1"
itoa = "0.4.1" itoa = "0.4.1"
log = "0.4" log = "0.4"
net2 = { version = "0.2.32", optional = true } net2 = { version = "0.2.32", optional = true }
pin-utils = "0.1.0-alpha.4"
time = "0.1" time = "0.1"
tokio = { version = "0.1.14", optional = true, default-features = false, features = ["rt-full"] } tokio = { git = "https://github.com/tokio-rs/tokio", optional = true, default-features = false, features = ["rt-full"] }
tokio-buf = "0.1" tokio-buf = "0.1"
tokio-executor = { version = "0.1.0", optional = true } tokio-executor = { git = "https://github.com/tokio-rs/tokio", optional = true }
tokio-io = "0.1" tokio-io = { git = "https://github.com/tokio-rs/tokio" }
tokio-reactor = { version = "0.1", optional = true } tokio-reactor = { git = "https://github.com/tokio-rs/tokio", optional = true }
tokio-tcp = { version = "0.1", optional = true } tokio-sync = { git = "https://github.com/tokio-rs/tokio" }
tokio-threadpool = { version = "0.1.3", optional = true } tokio-tcp = { git = "https://github.com/tokio-rs/tokio", optional = true }
tokio-timer = { version = "0.2", optional = true } tokio-threadpool = { git = "https://github.com/tokio-rs/tokio", optional = true }
want = "0.2" tokio-timer = { git = "https://github.com/tokio-rs/tokio", optional = true }
want = { git = "https://github.com/seanmonstar/want", branch = "std-future" }
[build-dependencies] [build-dependencies]
rustc_version = "0.2" rustc_version = "0.2"
[dev-dependencies] [dev-dependencies]
futures-timer = "0.1" #futures-timer = "0.1"
num_cpus = "1.0" num_cpus = "1.0"
pretty_env_logger = "0.3" pretty_env_logger = "0.3"
spmc = "0.2" spmc = "0.2"
url = "1.0" url = "1.0"
tokio-fs = "0.1" #tokio-fs = "0.1"
tokio-mockstream = "1.1.0" #tokio-mockstream = "1.1.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"
@@ -65,7 +68,6 @@ default = [
"runtime", "runtime",
] ]
runtime = [ runtime = [
"futures-cpupool",
"net2", "net2",
"tokio", "tokio",
"tokio-executor", "tokio-executor",

View File

@@ -1,3 +1,4 @@
#![feature(async_await)]
#![deny(warnings)] #![deny(warnings)]
extern crate hyper; extern crate hyper;
extern crate pretty_env_logger; extern crate pretty_env_logger;
@@ -6,7 +7,7 @@ use std::env;
use std::io::{self, Write}; use std::io::{self, Write};
use hyper::Client; use hyper::Client;
use hyper::rt::{self, Future, Stream}; use hyper::rt;
fn main() { fn main() {
pretty_env_logger::init(); pretty_env_logger::init();
@@ -35,31 +36,34 @@ fn main() {
rt::run(fetch_url(url)); rt::run(fetch_url(url));
} }
fn fetch_url(url: hyper::Uri) -> impl Future<Item=(), Error=()> { async fn fetch_url(url: hyper::Uri) {
let client = Client::new(); let client = Client::new();
client let res = match client.get(url).await {
// Fetch the url... Ok(res) => res,
.get(url) Err(err) => {
// And then, if we get a response back... eprintln!("Response Error: {}", err);
.and_then(|res| { return;
println!("Response: {}", res.status()); }
println!("Headers: {:#?}", res.headers()); };
// The body is a stream, and for_each returns a new Future println!("Response: {}", res.status());
// when the stream is finished, and calls the closure on println!("Headers: {:#?}\n", res.headers());
// each chunk of the body...
res.into_body().for_each(|chunk| { let mut body = res.into_body();
while let Some(next) = body.next().await {
match next {
Ok(chunk) => {
io::stdout().write_all(&chunk) io::stdout().write_all(&chunk)
.map_err(|e| panic!("example expects stdout is open, error={}", e)) .expect("example expects stdout is open");
}) },
}) Err(err) => {
// If all good, just tell the user... eprintln!("Body Error: {}", err);
.map(|_| { return;
println!("\n\nDone."); }
}) }
// If there was an error, let the user know... }
.map_err(|err| {
eprintln!("Error {}", err); println!("\n\nDone!");
})
} }

View File

@@ -1,27 +1,38 @@
#![feature(async_await)]
#![deny(warnings)] #![deny(warnings)]
extern crate hyper; extern crate hyper;
extern crate pretty_env_logger; extern crate pretty_env_logger;
use hyper::{Body, Request, Response, Server}; use hyper::{Body, Request, Response, Server};
use hyper::service::service_fn_ok; use hyper::service::{make_service_fn, service_fn};
use hyper::rt::{self, Future}; use hyper::rt;
fn main() { async fn hello(_: Request<Body>) -> Result<Response<Body>, hyper::Error> {
pretty_env_logger::init(); Ok(Response::new(Body::from("Hello World!")))
}
async fn serve() {
let addr = ([127, 0, 0, 1], 3000).into(); let addr = ([127, 0, 0, 1], 3000).into();
let server = Server::bind(&addr) let server = Server::bind(&addr)
.serve(|| { .serve(make_service_fn(|_| {
// This is the `Service` that will handle the connection. // This is the `Service` that will handle the connection.
// `service_fn_ok` is a helper to convert a function that // `service_fn_ok` is a helper to convert a function that
// returns a Response into a `Service`. // returns a Response into a `Service`.
service_fn_ok(move |_: Request<Body>| { async {
Response::new(Body::from("Hello World!")) Ok::<_, hyper::Error>(service_fn(hello))
}) }
}) }));
.map_err(|e| eprintln!("server error: {}", e));
println!("Listening on http://{}", addr); println!("Listening on http://{}", addr);
rt::run(server); if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}
fn main() {
pretty_env_logger::init();
rt::run(serve());
} }

View File

@@ -3,13 +3,13 @@ use std::error::Error as StdError;
use std::fmt; use std::fmt;
use bytes::Bytes; use bytes::Bytes;
use futures::sync::{mpsc, oneshot}; use futures_core::Stream;
use futures::{Async, Future, Poll, Stream, Sink, AsyncSink, StartSend}; use futures_channel::{mpsc, oneshot};
use tokio_buf::SizeHint; use tokio_buf::SizeHint;
use h2; use h2;
use http::HeaderMap; use http::HeaderMap;
use crate::common::Never; use crate::common::{Future, Never, Pin, Poll, task};
use super::internal::{FullDataArg, FullDataRet}; use super::internal::{FullDataArg, FullDataRet};
use super::{Chunk, Payload}; use super::{Chunk, Payload};
use crate::upgrade::OnUpgrade; use crate::upgrade::OnUpgrade;
@@ -40,7 +40,7 @@ enum Kind {
content_length: Option<u64>, content_length: Option<u64>,
recv: h2::RecvStream, recv: h2::RecvStream,
}, },
Wrapped(Box<dyn Stream<Item = Chunk, Error = Box<dyn StdError + Send + Sync>> + Send>), Wrapped(Pin<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send>>),
} }
struct Extra { struct Extra {
@@ -119,6 +119,7 @@ impl Body {
(tx, rx) (tx, rx)
} }
/*
/// Wrap a futures `Stream` in a box inside `Body`. /// Wrap a futures `Stream` in a box inside `Body`.
/// ///
/// # Example /// # Example
@@ -148,6 +149,12 @@ impl Body {
let mapped = stream.map(Chunk::from).map_err(Into::into); let mapped = stream.map(Chunk::from).map_err(Into::into);
Body::new(Kind::Wrapped(Box::new(mapped))) Body::new(Kind::Wrapped(Box::new(mapped)))
} }
*/
/// dox
pub async fn next(&mut self) -> Option<crate::Result<Chunk>> {
futures_util::future::poll_fn(|cx| self.poll_eof(cx)).await
}
/// Converts this `Body` into a `Future` of a pending HTTP upgrade. /// Converts this `Body` into a `Future` of a pending HTTP upgrade.
/// ///
@@ -200,83 +207,91 @@ impl Body {
})) }))
} }
fn poll_eof(&mut self) -> Poll<Option<Chunk>, crate::Error> { fn poll_eof(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Chunk>>> {
match self.take_delayed_eof() { match self.take_delayed_eof() {
Some(DelayEof::NotEof(mut delay)) => { Some(DelayEof::NotEof(mut delay)) => {
match self.poll_inner() { match self.poll_inner(cx) {
ok @ Ok(Async::Ready(Some(..))) | ok @ Poll::Ready(Some(Ok(..))) |
ok @ Ok(Async::NotReady) => { ok @ Poll::Pending => {
self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay)); self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay));
ok ok
}, },
Ok(Async::Ready(None)) => match delay.poll() { Poll::Ready(None) => match Pin::new(&mut delay).poll(cx) {
Ok(Async::Ready(never)) => match never {}, Poll::Ready(Ok(never)) => match never {},
Ok(Async::NotReady) => { Poll::Pending => {
self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
Ok(Async::NotReady) Poll::Pending
}, },
Err(_done) => { Poll::Ready(Err(_done)) => {
Ok(Async::Ready(None)) Poll::Ready(None)
}, },
}, },
Err(e) => Err(e), Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
} }
}, },
Some(DelayEof::Eof(mut delay)) => { Some(DelayEof::Eof(mut delay)) => {
match delay.poll() { match Pin::new(&mut delay).poll(cx) {
Ok(Async::Ready(never)) => match never {}, Poll::Ready(Ok(never)) => match never {},
Ok(Async::NotReady) => { Poll::Pending => {
self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
Ok(Async::NotReady) Poll::Pending
}, },
Err(_done) => { Poll::Ready(Err(_done)) => {
Ok(Async::Ready(None)) Poll::Ready(None)
}, },
} }
}, },
None => self.poll_inner(), None => self.poll_inner(cx),
} }
} }
fn poll_inner(&mut self) -> Poll<Option<Chunk>, crate::Error> { fn poll_inner(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Chunk>>> {
match self.kind { match self.kind {
Kind::Once(ref mut val) => Ok(Async::Ready(val.take())), Kind::Once(ref mut val) => Poll::Ready(val.take().map(Ok)),
Kind::Chan { Kind::Chan {
content_length: ref mut len, content_length: ref mut len,
ref mut rx, ref mut rx,
ref mut abort_rx, ref mut abort_rx,
} => { } => {
if let Ok(Async::Ready(())) = abort_rx.poll() { if let Poll::Ready(Ok(())) = Pin::new(abort_rx).poll(cx) {
return Err(crate::Error::new_body_write("body write aborted")); return Poll::Ready(Some(Err(crate::Error::new_body_write("body write aborted"))));
} }
match rx.poll().expect("mpsc cannot error") { match ready!(Pin::new(rx).poll_next(cx)?) {
Async::Ready(Some(Ok(chunk))) => { Some(chunk) => {
if let Some(ref mut len) = *len { if let Some(ref mut len) = *len {
debug_assert!(*len >= chunk.len() as u64); debug_assert!(*len >= chunk.len() as u64);
*len = *len - chunk.len() as u64; *len = *len - chunk.len() as u64;
} }
Ok(Async::Ready(Some(chunk))) Poll::Ready(Some(Ok(chunk)))
} }
Async::Ready(Some(Err(err))) => Err(err), None => Poll::Ready(None),
Async::Ready(None) => Ok(Async::Ready(None)),
Async::NotReady => Ok(Async::NotReady),
} }
} }
Kind::H2 { Kind::H2 {
recv: ref mut h2, .. /*recv: ref mut h2,*/ ..
} => h2 } => {
.poll() unimplemented!("h2.poll_inner");
.map(|r#async| { /*
r#async.map(|opt| { h2
opt.map(|bytes| { .poll()
let _ = h2.release_capacity().release_capacity(bytes.len()); .map(|r#async| {
Chunk::from(bytes) r#async.map(|opt| {
opt.map(|bytes| {
let _ = h2.release_capacity().release_capacity(bytes.len());
Chunk::from(bytes)
})
}) })
}) })
}) .map_err(crate::Error::new_body)
.map_err(crate::Error::new_body), */
Kind::Wrapped(ref mut s) => s.poll().map_err(crate::Error::new_body), }
Kind::Wrapped(ref mut s) => {
match ready!(s.as_mut().poll_next(cx)) {
Some(res) => Poll::Ready(Some(res.map_err(crate::Error::new_body))),
None => Poll::Ready(None),
}
}
} }
} }
} }
@@ -293,16 +308,17 @@ impl Payload for Body {
type Data = Chunk; type Data = Chunk;
type Error = crate::Error; type Error = crate::Error;
fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> { fn poll_data(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> {
self.poll_eof() self.poll_eof(cx)
} }
fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> { fn poll_trailers(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<HeaderMap, Self::Error>>> {
match self.kind { match self.kind {
Kind::H2 { Kind::H2 { /*recv: ref mut h2,*/ .. } => {
recv: ref mut h2, .. unimplemented!("h2.poll_trailers");
} => h2.poll_trailers().map_err(crate::Error::new_h2), //h2.poll_trailers().map_err(crate::Error::new_h2)
_ => Ok(Async::Ready(None)), },
_ => Poll::Ready(None),
} }
} }
@@ -334,6 +350,27 @@ impl Payload for Body {
} }
} }
impl fmt::Debug for Body {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[derive(Debug)]
struct Streaming;
#[derive(Debug)]
struct Empty;
#[derive(Debug)]
struct Once<'a>(&'a Chunk);
let mut builder = f.debug_tuple("Body");
match self.kind {
Kind::Once(None) => builder.field(&Empty),
Kind::Once(Some(ref chunk)) => builder.field(&Once(chunk)),
_ => builder.field(&Streaming),
};
builder.finish()
}
}
/*
impl ::http_body::Body for Body { impl ::http_body::Body for Body {
type Data = Chunk; type Data = Chunk;
type Error = crate::Error; type Error = crate::Error;
@@ -363,86 +400,28 @@ impl ::http_body::Body for Body {
hint hint
} }
} }
*/
impl Stream for Body { impl Stream for Body {
type Item = Chunk; type Item = crate::Result<Chunk>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
self.poll_data() self.poll_data(cx)
} }
} }
impl fmt::Debug for Body {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[derive(Debug)]
struct Streaming;
#[derive(Debug)]
struct Empty;
#[derive(Debug)]
struct Once<'a>(&'a Chunk);
let mut builder = f.debug_tuple("Body"); impl
match self.kind { From<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send>>
Kind::Once(None) => builder.field(&Empty), for Body
Kind::Once(Some(ref chunk)) => builder.field(&Once(chunk)), {
_ => builder.field(&Streaming), #[inline]
}; fn from(
stream: Box<
builder.finish() dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send,
} >,
} ) -> Body {
Body::new(Kind::Wrapped(stream.into()))
impl Sender {
/// Check to see if this `Sender` can send more data.
pub fn poll_ready(&mut self) -> Poll<(), crate::Error> {
match self.abort_tx.poll_cancel() {
Ok(Async::Ready(())) | Err(_) => return Err(crate::Error::new_closed()),
Ok(Async::NotReady) => (),
}
self.tx.poll_ready().map_err(|_| crate::Error::new_closed())
}
/// Sends data on this channel.
///
/// This should be called after `poll_ready` indicated the channel
/// could accept another `Chunk`.
///
/// Returns `Err(Chunk)` if the channel could not (currently) accept
/// another `Chunk`.
pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> {
self.tx
.try_send(Ok(chunk))
.map_err(|err| err.into_inner().expect("just sent Ok"))
}
/// Aborts the body in an abnormal fashion.
pub fn abort(self) {
let _ = self.abort_tx.send(());
}
pub(crate) fn send_error(&mut self, err: crate::Error) {
let _ = self.tx.try_send(Err(err));
}
}
impl Sink for Sender {
type SinkItem = Chunk;
type SinkError = crate::Error;
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
Ok(Async::Ready(()))
}
fn start_send(&mut self, msg: Chunk) -> StartSend<Self::SinkItem, Self::SinkError> {
match self.poll_ready()? {
Async::Ready(_) => {
self.send_data(msg).map_err(|_| crate::Error::new_closed())?;
Ok(AsyncSink::Ready)
}
Async::NotReady => Ok(AsyncSink::NotReady(msg)),
}
} }
} }
@@ -457,20 +436,6 @@ impl From<Chunk> for Body {
} }
} }
impl
From<Box<dyn Stream<Item = Chunk, Error = Box<dyn StdError + Send + Sync>> + Send + 'static>>
for Body
{
#[inline]
fn from(
stream: Box<
dyn Stream<Item = Chunk, Error = Box<dyn StdError + Send + Sync>> + Send + 'static,
>,
) -> Body {
Body::new(Kind::Wrapped(stream))
}
}
impl From<Bytes> for Body { impl From<Bytes> for Body {
#[inline] #[inline]
fn from(bytes: Bytes) -> Body { fn from(bytes: Bytes) -> Body {
@@ -526,6 +491,61 @@ impl From<Cow<'static, str>> for Body {
} }
} }
impl Sender {
/// Check to see if this `Sender` can send more data.
pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
match self.abort_tx.poll_cancel(cx) {
Poll::Ready(()) => return Poll::Ready(Err(crate::Error::new_closed())),
Poll::Pending => (), // fallthrough
}
self.tx.poll_ready(cx).map_err(|_| crate::Error::new_closed())
}
/// Sends data on this channel.
///
/// This should be called after `poll_ready` indicated the channel
/// could accept another `Chunk`.
///
/// Returns `Err(Chunk)` if the channel could not (currently) accept
/// another `Chunk`.
pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> {
self.tx
.try_send(Ok(chunk))
.map_err(|err| err.into_inner().expect("just sent Ok"))
}
/// Aborts the body in an abnormal fashion.
pub fn abort(self) {
let _ = self.abort_tx.send(());
}
pub(crate) fn send_error(&mut self, err: crate::Error) {
let _ = self.tx.try_send(Err(err));
}
}
/*
impl Sink for Sender {
type SinkItem = Chunk;
type SinkError = crate::Error;
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
Poll::Ready(Ok(()))
}
fn start_send(&mut self, msg: Chunk) -> StartSend<Self::SinkItem, Self::SinkError> {
match self.poll_ready()? {
Async::Ready(_) => {
self.send_data(msg).map_err(|_| crate::Error::new_closed())?;
Ok(AsyncSink::Ready)
}
Async::NotReady => Ok(AsyncSink::NotReady(msg)),
}
}
}
*/
#[test] #[test]
fn test_body_stream_concat() { fn test_body_stream_concat() {
let body = Body::from("hello world"); let body = Body::from("hello world");

View File

@@ -1,9 +1,9 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use bytes::Buf; use bytes::Buf;
use futures::{Async, Poll};
use http::HeaderMap; use http::HeaderMap;
use crate::common::{Pin, Poll, task};
use super::internal::{FullDataArg, FullDataRet}; use super::internal::{FullDataArg, FullDataRet};
/// This trait represents a streaming body of a `Request` or `Response`. /// This trait represents a streaming body of a `Request` or `Response`.
@@ -21,15 +21,15 @@ pub trait Payload: Send + 'static {
/// ///
/// Similar to `Stream::poll_next`, this yields `Some(Data)` until /// Similar to `Stream::poll_next`, this yields `Some(Data)` until
/// the body ends, when it yields `None`. /// the body ends, when it yields `None`.
fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error>; fn poll_data(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>>;
/// Poll for an optional **single** `HeaderMap` of trailers. /// Poll for an optional **single** `HeaderMap` of trailers.
/// ///
/// This should **only** be called after `poll_data` has ended. /// This should **only** be called after `poll_data` has ended.
/// ///
/// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2.
fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> { fn poll_trailers(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<HeaderMap, Self::Error>>> {
Ok(Async::Ready(None)) Poll::Ready(None)
} }
/// A hint that the `Body` is complete, and doesn't need to be polled more. /// A hint that the `Body` is complete, and doesn't need to be polled more.
@@ -70,6 +70,7 @@ pub trait Payload: Send + 'static {
} }
} }
/*
impl<E: Payload> Payload for Box<E> { impl<E: Payload> Payload for Box<E> {
type Data = E::Data; type Data = E::Data;
type Error = E::Error; type Error = E::Error;
@@ -95,5 +96,6 @@ impl<E: Payload> Payload for Box<E> {
(**self).__hyper_full_data(arg) (**self).__hyper_full_data(arg)
} }
} }
*/

View File

@@ -13,13 +13,12 @@ use std::mem;
use std::sync::Arc; use std::sync::Arc;
use bytes::Bytes; use bytes::Bytes;
use futures::{Async, Future, Poll}; use futures_util::future::{self, Either, FutureExt as _};
use futures::future::{self, Either, Executor};
use h2; use h2;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::body::Payload; use crate::body::Payload;
use crate::common::Exec; use crate::common::{Exec, Future, Pin, Poll, task};
use crate::upgrade::Upgraded; use crate::upgrade::Upgraded;
use crate::proto; use crate::proto;
use super::dispatch; use super::dispatch;
@@ -41,7 +40,7 @@ type ConnEither<T, B> = Either<
/// This is a shortcut for `Builder::new().handshake(io)`. /// This is a shortcut for `Builder::new().handshake(io)`.
pub fn handshake<T>(io: T) -> Handshake<T, crate::Body> pub fn handshake<T>(io: T) -> Handshake<T, crate::Body>
where where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{ {
Builder::new() Builder::new()
.handshake(io) .handshake(io)
@@ -88,7 +87,7 @@ pub struct Builder {
pub struct Handshake<T, B> { pub struct Handshake<T, B> {
builder: Builder, builder: Builder,
io: Option<T>, io: Option<T>,
_marker: PhantomData<B>, _marker: PhantomData<fn(B)>,
} }
/// A future returned by `SendRequest::send_request`. /// A future returned by `SendRequest::send_request`.
@@ -96,9 +95,13 @@ pub struct Handshake<T, B> {
/// Yields a `Response` if successful. /// Yields a `Response` if successful.
#[must_use = "futures do nothing unless polled"] #[must_use = "futures do nothing unless polled"]
pub struct ResponseFuture { pub struct ResponseFuture {
// for now, a Box is used to hide away the internal `B` inner: ResponseFutureState
// that can be returned if canceled }
inner: Box<dyn Future<Item=Response<Body>, Error=crate::Error> + Send>,
enum ResponseFutureState {
Waiting(dispatch::Promise<Response<Body>>),
// Option is to be able to `take()` it in `poll`
Error(Option<crate::Error>),
} }
/// Deconstructed parts of a `Connection`. /// Deconstructed parts of a `Connection`.
@@ -123,14 +126,6 @@ pub struct Parts<T> {
// ========== internal client api // ========== internal client api
/// A `Future` for when `SendRequest::poll_ready()` is ready.
// FIXME: allow() required due to `impl Trait` leaking types to this lint
#[allow(missing_debug_implementations)]
#[must_use = "futures do nothing unless polled"]
pub(super) struct WhenReady<B> {
tx: Option<SendRequest<B>>,
}
// A `SendRequest` that can be cloned to send HTTP2 requests. // A `SendRequest` that can be cloned to send HTTP2 requests.
// private for now, probably not a great idea of a type... // private for now, probably not a great idea of a type...
#[must_use = "futures do nothing unless polled"] #[must_use = "futures do nothing unless polled"]
@@ -145,14 +140,16 @@ impl<B> SendRequest<B>
/// Polls to determine whether this sender can be used yet for a request. /// Polls to determine whether this sender can be used yet for a request.
/// ///
/// If the associated connection is closed, this returns an Error. /// If the associated connection is closed, this returns an Error.
pub fn poll_ready(&mut self) -> Poll<(), crate::Error> { pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
self.dispatch.poll_ready() self.dispatch.poll_ready(cx)
} }
pub(super) fn when_ready(self) -> WhenReady<B> { pub(super) fn when_ready(self) -> impl Future<Output=crate::Result<Self>> {
WhenReady { let mut me = Some(self);
tx: Some(self), future::poll_fn(move |cx| {
} ready!(me.as_mut().unwrap().poll_ready(cx))?;
Poll::Ready(Ok(me.take().unwrap()))
})
} }
pub(super) fn is_ready(&self) -> bool { pub(super) fn is_ready(&self) -> bool {
@@ -224,37 +221,30 @@ where
pub fn send_request(&mut self, req: Request<B>) -> ResponseFuture { pub fn send_request(&mut self, req: Request<B>) -> ResponseFuture {
let inner = match self.dispatch.send(req) { let inner = match self.dispatch.send(req) {
Ok(rx) => { Ok(rx) => {
Either::A(rx.then(move |res| { ResponseFutureState::Waiting(rx)
match res {
Ok(Ok(res)) => Ok(res),
Ok(Err(err)) => Err(err),
// this is definite bug if it happens, but it shouldn't happen!
Err(_) => panic!("dispatch dropped without returning error"),
}
}))
}, },
Err(_req) => { Err(_req) => {
debug!("connection was not ready"); debug!("connection was not ready");
let err = crate::Error::new_canceled().with("connection was not ready"); let err = crate::Error::new_canceled().with("connection was not ready");
Either::B(future::err(err)) ResponseFutureState::Error(Some(err))
} }
}; };
ResponseFuture { ResponseFuture {
inner: Box::new(inner), inner,
} }
} }
pub(crate) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Item = Response<Body>, Error = (crate::Error, Option<Request<B>>)> pub(crate) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> + Unpin
where where
B: Send, B: Send,
{ {
match self.dispatch.try_send(req) { match self.dispatch.try_send(req) {
Ok(rx) => { Ok(rx) => {
Either::A(rx.then(move |res| { Either::Left(rx.then(move |res| {
match res { match res {
Ok(Ok(res)) => Ok(res), Ok(Ok(res)) => future::ok(res),
Ok(Err(err)) => Err(err), Ok(Err(err)) => future::err(err),
// this is definite bug if it happens, but it shouldn't happen! // this is definite bug if it happens, but it shouldn't happen!
Err(_) => panic!("dispatch dropped without returning error"), Err(_) => panic!("dispatch dropped without returning error"),
} }
@@ -263,7 +253,7 @@ where
Err(req) => { Err(req) => {
debug!("connection was not ready"); debug!("connection was not ready");
let err = crate::Error::new_canceled().with("connection was not ready"); let err = crate::Error::new_canceled().with("connection was not ready");
Either::B(future::err((err, Some(req)))) Either::Right(future::err((err, Some(req))))
} }
} }
} }
@@ -305,16 +295,16 @@ impl<B> Http2SendRequest<B>
where where
B: Payload + 'static, B: Payload + 'static,
{ {
pub(super) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Item=Response<Body>, Error=(crate::Error, Option<Request<B>>)> pub(super) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output=Result<Response<Body>, (crate::Error, Option<Request<B>>)>>
where where
B: Send, B: Send,
{ {
match self.dispatch.try_send(req) { match self.dispatch.try_send(req) {
Ok(rx) => { Ok(rx) => {
Either::A(rx.then(move |res| { Either::Left(rx.then(move |res| {
match res { match res {
Ok(Ok(res)) => Ok(res), Ok(Ok(res)) => future::ok(res),
Ok(Err(err)) => Err(err), Ok(Err(err)) => future::err(err),
// this is definite bug if it happens, but it shouldn't happen! // this is definite bug if it happens, but it shouldn't happen!
Err(_) => panic!("dispatch dropped without returning error"), Err(_) => panic!("dispatch dropped without returning error"),
} }
@@ -323,7 +313,7 @@ where
Err(req) => { Err(req) => {
debug!("connection was not ready"); debug!("connection was not ready");
let err = crate::Error::new_canceled().with("connection was not ready"); let err = crate::Error::new_canceled().with("connection was not ready");
Either::B(future::err((err, Some(req)))) Either::Right(future::err((err, Some(req))))
} }
} }
} }
@@ -348,7 +338,7 @@ impl<B> Clone for Http2SendRequest<B> {
impl<T, B> Connection<T, B> impl<T, B> Connection<T, B>
where where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
{ {
/// Return the inner IO object, and additional information. /// Return the inner IO object, and additional information.
@@ -356,8 +346,8 @@ where
/// Only works for HTTP/1 connections. HTTP/2 connections will panic. /// Only works for HTTP/1 connections. HTTP/2 connections will panic.
pub fn into_parts(self) -> Parts<T> { pub fn into_parts(self) -> Parts<T> {
let (io, read_buf, _) = match self.inner.expect("already upgraded") { let (io, read_buf, _) = match self.inner.expect("already upgraded") {
Either::A(h1) => h1.into_inner(), Either::Left(h1) => h1.into_inner(),
Either::B(_h2) => { Either::Right(_h2) => {
panic!("http2 cannot into_inner"); panic!("http2 cannot into_inner");
} }
}; };
@@ -380,51 +370,58 @@ where
/// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html) /// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html)
/// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html) /// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html)
/// to work with this function; or use the `without_shutdown` wrapper. /// to work with this function; or use the `without_shutdown` wrapper.
pub fn poll_without_shutdown(&mut self) -> Poll<(), crate::Error> { pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>>
where
B: Unpin,
{
match self.inner.as_mut().expect("already upgraded") { match self.inner.as_mut().expect("already upgraded") {
&mut Either::A(ref mut h1) => { &mut Either::Left(ref mut h1) => {
h1.poll_without_shutdown() h1.poll_without_shutdown(cx)
}, },
&mut Either::B(ref mut h2) => { &mut Either::Right(ref mut h2) => {
unimplemented!("h2 poll_without_shutdown");
/*
h2.poll().map(|x| x.map(|_| ())) h2.poll().map(|x| x.map(|_| ()))
*/
} }
} }
} }
/// Prevent shutdown of the underlying IO object at the end of service the request, /// Prevent shutdown of the underlying IO object at the end of service the request,
/// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`. /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`.
pub fn without_shutdown(self) -> impl Future<Item=Parts<T>, Error=crate::Error> { pub fn without_shutdown(self) -> impl Future<Output=crate::Result<Parts<T>>>
where
B: Unpin,
{
let mut conn = Some(self); let mut conn = Some(self);
::futures::future::poll_fn(move || -> crate::Result<_> { future::poll_fn(move |cx| -> Poll<crate::Result<Parts<T>>> {
try_ready!(conn.as_mut().unwrap().poll_without_shutdown()); ready!(conn.as_mut().unwrap().poll_without_shutdown(cx))?;
Ok(conn.take().unwrap().into_parts().into()) Poll::Ready(Ok(conn.take().unwrap().into_parts()))
}) })
} }
} }
impl<T, B> Future for Connection<T, B> impl<T, B> Future for Connection<T, B>
where where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
B: Payload + 'static, B: Payload + Unpin + 'static,
{ {
type Item = (); type Output = crate::Result<()>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match try_ready!(self.inner.poll()) { match ready!(Pin::new(self.inner.as_mut().unwrap()).poll(cx))? {
Some(proto::Dispatched::Shutdown) | proto::Dispatched::Shutdown => {
None => { Poll::Ready(Ok(()))
Ok(Async::Ready(()))
}, },
Some(proto::Dispatched::Upgrade(pending)) => { proto::Dispatched::Upgrade(pending) => {
let h1 = match mem::replace(&mut self.inner, None) { let h1 = match mem::replace(&mut self.inner, None) {
Some(Either::A(h1)) => h1, Some(Either::Left(h1)) => h1,
_ => unreachable!("Upgrade expects h1"), _ => unreachable!("Upgrade expects h1"),
}; };
let (io, buf, _) = h1.into_inner(); let (io, buf, _) = h1.into_inner();
pending.fulfill(Upgraded::new(Box::new(io), buf)); pending.fulfill(Upgraded::new(Box::new(io), buf));
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
} }
} }
@@ -461,6 +458,7 @@ impl Builder {
} }
} }
/*
/// Provide an executor to execute background HTTP2 tasks. /// Provide an executor to execute background HTTP2 tasks.
pub fn executor<E>(&mut self, exec: E) -> &mut Builder pub fn executor<E>(&mut self, exec: E) -> &mut Builder
where where
@@ -469,6 +467,7 @@ impl Builder {
self.exec = Exec::Executor(Arc::new(exec)); self.exec = Exec::Executor(Arc::new(exec));
self self
} }
*/
pub(super) fn h1_writev(&mut self, enabled: bool) -> &mut Builder { pub(super) fn h1_writev(&mut self, enabled: bool) -> &mut Builder {
self.h1_writev = enabled; self.h1_writev = enabled;
@@ -532,7 +531,7 @@ impl Builder {
#[inline] #[inline]
pub fn handshake<T, B>(&self, io: T) -> Handshake<T, B> pub fn handshake<T, B>(&self, io: T) -> Handshake<T, B>
where where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
{ {
trace!("client handshake HTTP/{}", if self.http2 { 2 } else { 1 }); trace!("client handshake HTTP/{}", if self.http2 { 2 } else { 1 });
@@ -548,13 +547,12 @@ impl Builder {
impl<T, B> Future for Handshake<T, B> impl<T, B> Future for Handshake<T, B>
where where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
{ {
type Item = (SendRequest<B>, Connection<T, B>); type Output = crate::Result<(SendRequest<B>, Connection<T, B>)>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
let io = self.io.take().expect("polled more than once"); let io = self.io.take().expect("polled more than once");
let (tx, rx) = dispatch::channel(); let (tx, rx) = dispatch::channel();
let either = if !self.builder.http2 { let either = if !self.builder.http2 {
@@ -573,13 +571,13 @@ where
} }
let cd = proto::h1::dispatch::Client::new(rx); let cd = proto::h1::dispatch::Client::new(rx);
let dispatch = proto::h1::Dispatcher::new(cd, conn); let dispatch = proto::h1::Dispatcher::new(cd, conn);
Either::A(dispatch) Either::Left(dispatch)
} else { } else {
let h2 = proto::h2::Client::new(io, rx, &self.builder.h2_builder, self.builder.exec.clone()); let h2 = proto::h2::Client::new(io, rx, &self.builder.h2_builder, self.builder.exec.clone());
Either::B(h2) Either::Right(h2)
}; };
Ok(Async::Ready(( Poll::Ready(Ok((
SendRequest { SendRequest {
dispatch: tx, dispatch: tx,
}, },
@@ -600,12 +598,22 @@ impl<T, B> fmt::Debug for Handshake<T, B> {
// ===== impl ResponseFuture // ===== impl ResponseFuture
impl Future for ResponseFuture { impl Future for ResponseFuture {
type Item = Response<Body>; type Output = crate::Result<Response<Body>>;
type Error = crate::Error;
#[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { match self.inner {
self.inner.poll() ResponseFutureState::Waiting(ref mut rx) => {
Pin::new(rx).poll(cx).map(|res| match res {
Ok(Ok(resp)) => Ok(resp),
Ok(Err(err)) => Err(err),
// this is definite bug if it happens, but it shouldn't happen!
Err(_canceled) => panic!("dispatch dropped without returning error"),
})
},
ResponseFutureState::Error(ref mut err) => {
Poll::Ready(Err(err.take().expect("polled after ready")))
}
}
} }
} }
@@ -616,24 +624,6 @@ impl fmt::Debug for ResponseFuture {
} }
} }
// ===== impl WhenReady
impl<B> Future for WhenReady<B> {
type Item = SendRequest<B>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut tx = self.tx.take().expect("polled after complete");
match tx.poll_ready()? {
Async::Ready(()) => Ok(Async::Ready(tx)),
Async::NotReady => {
self.tx = Some(tx);
Ok(Async::NotReady)
}
}
}
}
// assert trait markers // assert trait markers
trait AssertSend: Send {} trait AssertSend: Send {}

View File

@@ -16,20 +16,19 @@ use std::net::{
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use futures::{Async, Future, Poll}; use tokio_executor::TypedExecutor;
use futures::future::{Executor, ExecuteError}; use tokio_sync::oneshot;
use futures::sync::oneshot;
use futures_cpupool::{Builder as CpuPoolBuilder};
use tokio_threadpool; use tokio_threadpool;
use crate::common::{Future, Pin, Poll, Unpin, task};
use self::sealed::GaiTask; use self::sealed::GaiTask;
/// Resolve a hostname to a set of IP addresses. /// Resolve a hostname to a set of IP addresses.
pub trait Resolve { pub trait Resolve: Unpin {
/// The set of IP addresses to try to connect to. /// The set of IP addresses to try to connect to.
type Addrs: Iterator<Item=IpAddr>; type Addrs: Iterator<Item=IpAddr>;
/// A Future of the resolved set of addresses. /// A Future of the resolved set of addresses.
type Future: Future<Item=Self::Addrs, Error=io::Error>; type Future: Future<Output=Result<Self::Addrs, io::Error>> + Unpin;
/// Resolve a hostname. /// Resolve a hostname.
fn resolve(&self, name: Name) -> Self::Future; fn resolve(&self, name: Name) -> Self::Future;
} }
@@ -53,7 +52,8 @@ pub struct GaiAddrs {
/// A future to resole a name returned by `GaiResolver`. /// A future to resole a name returned by `GaiResolver`.
pub struct GaiFuture { pub struct GaiFuture {
rx: oneshot::SpawnHandle<IpAddrs, io::Error>, //rx: oneshot::SpawnHandle<IpAddrs, io::Error>,
blocking: GaiBlocking,
} }
impl Name { impl Name {
@@ -112,24 +112,36 @@ impl GaiResolver {
/// ///
/// Takes number of DNS worker threads. /// Takes number of DNS worker threads.
pub fn new(threads: usize) -> Self { pub fn new(threads: usize) -> Self {
let pool = CpuPoolBuilder::new() GaiResolver {
.name_prefix("hyper-dns") executor: GaiExecutor,
.pool_size(threads) }
.create(); /*
use tokio_threadpool::Builder;
let pool = Builder::new()
.name_prefix("hyper-dns-gai-resolver")
// not for CPU tasks, so only spawn workers
// in blocking mode
.pool_size(1)
.max_blocking(threads)
.build();
GaiResolver::new_with_executor(pool) GaiResolver::new_with_executor(pool)
*/
} }
/*
/// Construct a new `GaiResolver` with a shared thread pool executor. /// Construct a new `GaiResolver` with a shared thread pool executor.
/// ///
/// Takes an executor to run blocking `getaddrinfo` tasks on. /// Takes an executor to run blocking `getaddrinfo` tasks on.
pub fn new_with_executor<E: 'static>(executor: E) -> Self /*pub */fn new_with_executor<E: 'static>(executor: E) -> Self
where where
E: Executor<GaiTask> + Send + Sync, E: TypedExecutor<GaiTask> + Send + Sync,
{ {
GaiResolver { GaiResolver {
executor: GaiExecutor(Arc::new(executor)), executor: GaiExecutor(Arc::new(executor)),
} }
} }
*/
} }
impl Resolve for GaiResolver { impl Resolve for GaiResolver {
@@ -138,9 +150,10 @@ impl Resolve for GaiResolver {
fn resolve(&self, name: Name) -> Self::Future { fn resolve(&self, name: Name) -> Self::Future {
let blocking = GaiBlocking::new(name.host); let blocking = GaiBlocking::new(name.host);
let rx = oneshot::spawn(blocking, &self.executor); //let rx = oneshot::spawn(blocking, &self.executor);
GaiFuture { GaiFuture {
rx, //rx,
blocking,
} }
} }
} }
@@ -152,14 +165,16 @@ impl fmt::Debug for GaiResolver {
} }
impl Future for GaiFuture { impl Future for GaiFuture {
type Item = GaiAddrs; type Output = Result<GaiAddrs, io::Error>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
/*
let addrs = try_ready!(self.rx.poll()); let addrs = try_ready!(self.rx.poll());
Ok(Async::Ready(GaiAddrs { Ok(Async::Ready(GaiAddrs {
inner: addrs, inner: addrs,
})) }))
*/
Poll::Ready(self.blocking.block().map(|addrs| GaiAddrs { inner: addrs }))
} }
} }
@@ -184,14 +199,16 @@ impl fmt::Debug for GaiAddrs {
} }
#[derive(Clone)] #[derive(Clone)]
struct GaiExecutor(Arc<dyn Executor<GaiTask> + Send + Sync>); struct GaiExecutor/*(Arc<dyn Executor<GaiTask> + Send + Sync>)*/;
/*
impl Executor<oneshot::Execute<GaiBlocking>> for GaiExecutor { impl Executor<oneshot::Execute<GaiBlocking>> for GaiExecutor {
fn execute(&self, future: oneshot::Execute<GaiBlocking>) -> Result<(), ExecuteError<oneshot::Execute<GaiBlocking>>> { fn execute(&self, future: oneshot::Execute<GaiBlocking>) -> Result<(), ExecuteError<oneshot::Execute<GaiBlocking>>> {
self.0.execute(GaiTask { work: future }) self.0.execute(GaiTask { work: future })
.map_err(|err| ExecuteError::new(err.kind(), err.into_future().work)) .map_err(|err| ExecuteError::new(err.kind(), err.into_future().work))
} }
} }
*/
pub(super) struct GaiBlocking { pub(super) struct GaiBlocking {
host: String, host: String,
@@ -201,8 +218,16 @@ impl GaiBlocking {
pub(super) fn new(host: String) -> GaiBlocking { pub(super) fn new(host: String) -> GaiBlocking {
GaiBlocking { host } GaiBlocking { host }
} }
fn block(&self) -> io::Result<IpAddrs> {
debug!("resolving host={:?}", self.host);
(&*self.host, 0).to_socket_addrs()
.map(|i| IpAddrs { iter: i })
}
} }
/*
impl Future for GaiBlocking { impl Future for GaiBlocking {
type Item = IpAddrs; type Item = IpAddrs;
type Error = io::Error; type Error = io::Error;
@@ -213,6 +238,7 @@ impl Future for GaiBlocking {
.map(|i| Async::Ready(IpAddrs { iter: i })) .map(|i| Async::Ready(IpAddrs { iter: i }))
} }
} }
*/
pub(super) struct IpAddrs { pub(super) struct IpAddrs {
iter: vec::IntoIter<SocketAddr>, iter: vec::IntoIter<SocketAddr>,
@@ -276,7 +302,7 @@ pub(super) mod sealed {
use super::*; use super::*;
// Blocking task to be executed on a thread pool. // Blocking task to be executed on a thread pool.
pub struct GaiTask { pub struct GaiTask {
pub(super) work: oneshot::Execute<GaiBlocking> //pub(super) work: oneshot::Execute<GaiBlocking>
} }
impl fmt::Debug for GaiTask { impl fmt::Debug for GaiTask {
@@ -285,6 +311,7 @@ pub(super) mod sealed {
} }
} }
/*
impl Future for GaiTask { impl Future for GaiTask {
type Item = (); type Item = ();
type Error = (); type Error = ();
@@ -293,6 +320,7 @@ pub(super) mod sealed {
self.work.poll() self.work.poll()
} }
} }
*/
} }
@@ -329,15 +357,14 @@ impl Resolve for TokioThreadpoolGaiResolver {
} }
impl Future for TokioThreadpoolGaiFuture { impl Future for TokioThreadpoolGaiFuture {
type Item = GaiAddrs; type Output = Result<GaiAddrs, io::Error>;
type Error = io::Error;
fn poll(&mut self) -> Poll<GaiAddrs, io::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match tokio_threadpool::blocking(|| (self.name.as_str(), 0).to_socket_addrs()) { match ready!(tokio_threadpool::blocking(|| (self.name.as_str(), 0).to_socket_addrs())) {
Ok(Async::Ready(Ok(iter))) => Ok(Async::Ready(GaiAddrs { inner: IpAddrs { iter } })), Ok(Ok(iter)) => Poll::Ready(Ok(GaiAddrs { inner: IpAddrs { iter } })),
Ok(Async::Ready(Err(e))) => Err(e), Ok(Err(e)) => Poll::Ready(Err(e)),
Ok(Async::NotReady) => Ok(Async::NotReady), // a BlockingError, meaning not on a tokio_threadpool :(
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), Err(e) => Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))),
} }
} }
} }

View File

@@ -6,17 +6,19 @@ use std::mem;
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, SocketAddr};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use futures::{Async, Future, Poll};
use futures::future::{Executor};
use http::uri::Scheme; use http::uri::Scheme;
use net2::TcpBuilder; use net2::TcpBuilder;
use tokio_reactor::Handle; use tokio_reactor::Handle;
use tokio_tcp::{TcpStream, ConnectFuture}; use tokio_tcp::{TcpStream/*, ConnectFuture*/};
use tokio_timer::Delay; use tokio_timer::Delay;
use crate::common::{Future, Pin, Poll, task};
use super::{Connect, Connected, Destination}; use super::{Connect, Connected, Destination};
use super::dns::{self, GaiResolver, Resolve, TokioThreadpoolGaiResolver}; use super::dns::{self, GaiResolver, Resolve, TokioThreadpoolGaiResolver};
// TODO: unbox me?
type ConnectFuture = Pin<Box<dyn Future<Output = io::Result<TcpStream>> + Send>>;
/// A connector for the `http` scheme. /// A connector for the `http` scheme.
/// ///
/// Performs DNS resolution in a thread pool, and then connects over TCP. /// Performs DNS resolution in a thread pool, and then connects over TCP.
@@ -89,6 +91,7 @@ impl HttpConnector {
http http
} }
/*
/// Construct a new HttpConnector. /// Construct a new HttpConnector.
/// ///
/// Takes an executor to run blocking `getaddrinfo` tasks on. /// Takes an executor to run blocking `getaddrinfo` tasks on.
@@ -100,6 +103,7 @@ impl HttpConnector {
http.set_reactor(handle); http.set_reactor(handle);
http http
} }
*/
} }
impl HttpConnector<TokioThreadpoolGaiResolver> { impl HttpConnector<TokioThreadpoolGaiResolver> {
@@ -335,55 +339,54 @@ enum State<R: Resolve> {
Error(Option<io::Error>), Error(Option<io::Error>),
} }
impl<R: Resolve> Future for HttpConnecting<R> { impl<R: Resolve> Future for HttpConnecting<R>
type Item = (TcpStream, Connected); where
type Error = io::Error; R::Future: Unpin,
{
type Output = Result<(TcpStream, Connected), io::Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
let me = &mut *self;
loop { loop {
let state; let state;
match self.state { match me.state {
State::Lazy(ref resolver, ref mut host, local_addr) => { State::Lazy(ref resolver, ref mut host, local_addr) => {
// If the host is already an IP addr (v4 or v6), // If the host is already an IP addr (v4 or v6),
// skip resolving the dns and start connecting right away. // skip resolving the dns and start connecting right away.
if let Some(addrs) = dns::IpAddrs::try_parse(host, self.port) { if let Some(addrs) = dns::IpAddrs::try_parse(host, me.port) {
state = State::Connecting(ConnectingTcp::new( state = State::Connecting(ConnectingTcp::new(
local_addr, addrs, self.happy_eyeballs_timeout, self.reuse_address)); local_addr, addrs, me.happy_eyeballs_timeout, me.reuse_address));
} else { } else {
let name = dns::Name::new(mem::replace(host, String::new())); let name = dns::Name::new(mem::replace(host, String::new()));
state = State::Resolving(resolver.resolve(name), local_addr); state = State::Resolving(resolver.resolve(name), local_addr);
} }
}, },
State::Resolving(ref mut future, local_addr) => { State::Resolving(ref mut future, local_addr) => {
match future.poll()? { let addrs = ready!(Pin::new(future).poll(cx))?;
Async::NotReady => return Ok(Async::NotReady), let port = me.port;
Async::Ready(addrs) => { let addrs = addrs
let port = self.port; .map(|addr| SocketAddr::new(addr, port))
let addrs = addrs .collect();
.map(|addr| SocketAddr::new(addr, port)) let addrs = dns::IpAddrs::new(addrs);
.collect(); state = State::Connecting(ConnectingTcp::new(
let addrs = dns::IpAddrs::new(addrs); local_addr, addrs, me.happy_eyeballs_timeout, me.reuse_address));
state = State::Connecting(ConnectingTcp::new(
local_addr, addrs, self.happy_eyeballs_timeout, self.reuse_address));
}
};
}, },
State::Connecting(ref mut c) => { State::Connecting(ref mut c) => {
let sock = try_ready!(c.poll(&self.handle)); let sock = ready!(c.poll(cx, &me.handle))?;
if let Some(dur) = self.keep_alive_timeout { if let Some(dur) = me.keep_alive_timeout {
sock.set_keepalive(Some(dur))?; sock.set_keepalive(Some(dur))?;
} }
if let Some(size) = self.send_buffer_size { if let Some(size) = me.send_buffer_size {
sock.set_send_buffer_size(size)?; sock.set_send_buffer_size(size)?;
} }
if let Some(size) = self.recv_buffer_size { if let Some(size) = me.recv_buffer_size {
sock.set_recv_buffer_size(size)?; sock.set_recv_buffer_size(size)?;
} }
sock.set_nodelay(self.nodelay)?; sock.set_nodelay(me.nodelay)?;
let extra = HttpInfo { let extra = HttpInfo {
remote_addr: sock.peer_addr()?, remote_addr: sock.peer_addr()?,
@@ -391,11 +394,11 @@ impl<R: Resolve> Future for HttpConnecting<R> {
let connected = Connected::new() let connected = Connected::new()
.extra(extra); .extra(extra);
return Ok(Async::Ready((sock, connected))); return Poll::Ready(Ok((sock, connected)));
}, },
State::Error(ref mut e) => return Err(e.take().expect("polled more than once")), State::Error(ref mut e) => return Poll::Ready(Err(e.take().expect("polled more than once"))),
} }
self.state = state; me.state = state;
} }
} }
} }
@@ -474,20 +477,21 @@ impl ConnectingTcpRemote {
// not a Future, since passing a &Handle to poll // not a Future, since passing a &Handle to poll
fn poll( fn poll(
&mut self, &mut self,
cx: &mut task::Context<'_>,
local_addr: &Option<IpAddr>, local_addr: &Option<IpAddr>,
handle: &Option<Handle>, handle: &Option<Handle>,
reuse_address: bool, reuse_address: bool,
) -> Poll<TcpStream, io::Error> { ) -> Poll<io::Result<TcpStream>> {
let mut err = None; let mut err = None;
loop { loop {
if let Some(ref mut current) = self.current { if let Some(ref mut current) = self.current {
match current.poll() { match current.as_mut().poll(cx) {
Ok(Async::Ready(tcp)) => { Poll::Ready(Ok(tcp)) => {
debug!("connected to {:?}", tcp.peer_addr().ok()); debug!("connected to {:?}", tcp.peer_addr().ok());
return Ok(Async::Ready(tcp)); return Poll::Ready(Ok(tcp));
}, },
Ok(Async::NotReady) => return Ok(Async::NotReady), Poll::Pending => return Poll::Pending,
Err(e) => { Poll::Ready(Err(e)) => {
trace!("connect error {:?}", e); trace!("connect error {:?}", e);
err = Some(e); err = Some(e);
if let Some(addr) = self.addrs.next() { if let Some(addr) = self.addrs.next() {
@@ -503,7 +507,7 @@ impl ConnectingTcpRemote {
continue; continue;
} }
return Err(err.take().expect("missing connect error")); return Poll::Ready(Err(err.take().expect("missing connect error")));
} }
} }
} }
@@ -540,51 +544,46 @@ fn connect(addr: &SocketAddr, local_addr: &Option<IpAddr>, handle: &Option<Handl
None => Cow::Owned(Handle::default()), None => Cow::Owned(Handle::default()),
}; };
Ok(TcpStream::connect_std(builder.to_tcp_stream()?, addr, &handle)) Ok(Box::pin(TcpStream::connect_std(builder.to_tcp_stream()?, addr, &handle)))
} }
impl ConnectingTcp { impl ConnectingTcp {
// not a Future, since passing a &Handle to poll fn poll(&mut self, cx: &mut task::Context<'_>, handle: &Option<Handle>) -> Poll<io::Result<TcpStream>> {
fn poll(&mut self, handle: &Option<Handle>) -> Poll<TcpStream, io::Error> {
match self.fallback.take() { match self.fallback.take() {
None => self.preferred.poll(&self.local_addr, handle, self.reuse_address), None => self.preferred.poll(cx, &self.local_addr, handle, self.reuse_address),
Some(mut fallback) => match self.preferred.poll(&self.local_addr, handle, self.reuse_address) { Some(mut fallback) => match self.preferred.poll(cx, &self.local_addr, handle, self.reuse_address) {
Ok(Async::Ready(stream)) => { Poll::Ready(Ok(stream)) => {
// Preferred successful - drop fallback. // Preferred successful - drop fallback.
Ok(Async::Ready(stream)) Poll::Ready(Ok(stream))
} }
Ok(Async::NotReady) => match fallback.delay.poll() { Poll::Pending => match Pin::new(&mut fallback.delay).poll(cx) {
Ok(Async::Ready(_)) => match fallback.remote.poll(&self.local_addr, handle, self.reuse_address) { Poll::Ready(()) => match fallback.remote.poll(cx, &self.local_addr, handle, self.reuse_address) {
Ok(Async::Ready(stream)) => { Poll::Ready(Ok(stream)) => {
// Fallback successful - drop current preferred, // Fallback successful - drop current preferred,
// but keep fallback as new preferred. // but keep fallback as new preferred.
self.preferred = fallback.remote; self.preferred = fallback.remote;
Ok(Async::Ready(stream)) Poll::Ready(Ok(stream))
} }
Ok(Async::NotReady) => { Poll::Pending => {
// Neither preferred nor fallback are ready. // Neither preferred nor fallback are ready.
self.fallback = Some(fallback); self.fallback = Some(fallback);
Ok(Async::NotReady) Poll::Pending
} }
Err(_) => { Poll::Ready(Err(_)) => {
// Fallback failed - resume with preferred only. // Fallback failed - resume with preferred only.
Ok(Async::NotReady) Poll::Pending
} }
}, },
Ok(Async::NotReady) => { Poll::Pending => {
// Too early to attempt fallback. // Too early to attempt fallback.
self.fallback = Some(fallback); self.fallback = Some(fallback);
Ok(Async::NotReady) Poll::Pending
}
Err(_) => {
// Fallback delay failed - resume with preferred only.
Ok(Async::NotReady)
} }
} }
Err(_) => { Poll::Ready(Err(_)) => {
// Preferred failed - use fallback as new preferred. // Preferred failed - use fallback as new preferred.
self.preferred = fallback.remote; self.preferred = fallback.remote;
self.preferred.poll(&self.local_addr, handle, self.reuse_address) self.preferred.poll(cx, &self.local_addr, handle, self.reuse_address)
} }
} }
} }
@@ -734,10 +733,10 @@ mod tests {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.0.poll(&Some(Handle::default())) { match self.0.poll(&Some(Handle::default())) {
Ok(Async::Ready(stream)) => Ok(Async::Ready( Poll::Ready(Ok(stream)) => Poll::Ready(Ok(
if stream.peer_addr().unwrap().is_ipv4() { 4 } else { 6 } if stream.peer_addr().unwrap().is_ipv4() { 4 } else { 6 }
)), )),
Ok(Async::NotReady) => Ok(Async::NotReady), Poll::Pending => Poll::Pending,
Err(err) => Err(err), Err(err) => Err(err),
} }
} }

View File

@@ -10,10 +10,11 @@ use std::{fmt, mem};
#[cfg(try_from)] use std::convert::TryFrom; #[cfg(try_from)] use std::convert::TryFrom;
use bytes::{BufMut, Bytes, BytesMut}; use bytes::{BufMut, Bytes, BytesMut};
use futures::Future;
use ::http::{uri, Response, Uri}; use ::http::{uri, Response, Uri};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::common::{Future, Unpin};
#[cfg(feature = "runtime")] pub mod dns; #[cfg(feature = "runtime")] pub mod dns;
#[cfg(feature = "runtime")] mod http; #[cfg(feature = "runtime")] mod http;
#[cfg(feature = "runtime")] pub use self::http::{HttpConnector, HttpInfo}; #[cfg(feature = "runtime")] pub use self::http::{HttpConnector, HttpInfo};
@@ -25,11 +26,11 @@ use tokio_io::{AsyncRead, AsyncWrite};
/// ready connection. /// ready connection.
pub trait Connect: Send + Sync { pub trait Connect: Send + Sync {
/// The connected IO Stream. /// The connected IO Stream.
type Transport: AsyncRead + AsyncWrite + Send + 'static; type Transport: AsyncRead + AsyncWrite + Unpin + Send + 'static;
/// An error occured when trying to connect. /// An error occured when trying to connect.
type Error: Into<Box<dyn StdError + Send + Sync>>; type Error: Into<Box<dyn StdError + Send + Sync>>;
/// A Future that will resolve to the connected Transport. /// A Future that will resolve to the connected Transport.
type Future: Future<Item=(Self::Transport, Connected), Error=Self::Error> + Send; type Future: Future<Output=Result<(Self::Transport, Connected), Self::Error>> + Unpin + Send;
/// Connect to a destination. /// Connect to a destination.
fn connect(&self, dst: Destination) -> Self::Future; fn connect(&self, dst: Destination) -> Self::Future;
} }

View File

@@ -1,8 +1,9 @@
use futures::{future, Async, Future, Poll, Stream}; use futures_core::Stream;
use futures::sync::{mpsc, oneshot}; use futures_channel::{mpsc, oneshot};
use futures_util::future;
use want; use want;
use crate::common::Never; use crate::common::{Future, Never, Pin, Poll, task};
pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>; pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>;
pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>; pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;
@@ -51,8 +52,8 @@ pub struct UnboundedSender<T, U> {
} }
impl<T, U> Sender<T, U> { impl<T, U> Sender<T, U> {
pub fn poll_ready(&mut self) -> Poll<(), crate::Error> { pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
self.giver.poll_want() self.giver.poll_want(cx)
.map_err(|_| crate::Error::new_closed()) .map_err(|_| crate::Error::new_closed())
} }
@@ -136,20 +137,32 @@ pub struct Receiver<T, U> {
taker: want::Taker, taker: want::Taker,
} }
impl<T, U> Stream for Receiver<T, U> { //impl<T, U> Stream for Receiver<T, U> {
type Item = (T, Callback<T, U>); // type Item = (T, Callback<T, U>);
type Error = Never;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { impl<T, U> Receiver<T, U> {
match self.inner.poll() { pub(crate) fn poll_next(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<(T, Callback<T, U>)>> {
Ok(Async::Ready(item)) => Ok(Async::Ready(item.map(|mut env| { match Pin::new(&mut self.inner).poll_next(cx) {
Poll::Ready(item) => Poll::Ready(item.map(|mut env| {
env.0.take().expect("envelope not dropped") env.0.take().expect("envelope not dropped")
}))), })),
Ok(Async::NotReady) => { Poll::Pending => {
self.taker.want(); self.taker.want();
Ok(Async::NotReady) Poll::Pending
} },
Err(()) => unreachable!("mpsc never errors"), }
}
pub(crate) fn close(&mut self) {
self.taker.cancel();
self.inner.close();
}
pub(crate) fn try_recv(&mut self) -> Option<(T, Callback<T, U>)> {
match self.inner.try_next() {
Ok(Some(mut env)) => env.0.take(),
Ok(None) => None,
Err(_) => None,
} }
} }
} }
@@ -185,10 +198,10 @@ impl<T, U> Callback<T, U> {
} }
} }
pub(crate) fn poll_cancel(&mut self) -> Poll<(), ()> { pub(crate) fn poll_cancel(&mut self, cx: &mut task::Context<'_>) -> Poll<()> {
match *self { match *self {
Callback::Retry(ref mut tx) => tx.poll_cancel(), Callback::Retry(ref mut tx) => tx.poll_cancel(cx),
Callback::NoRetry(ref mut tx) => tx.poll_cancel(), Callback::NoRetry(ref mut tx) => tx.poll_cancel(cx),
} }
} }
@@ -205,30 +218,30 @@ impl<T, U> Callback<T, U> {
pub(crate) fn send_when( pub(crate) fn send_when(
self, self,
mut when: impl Future<Item=U, Error=(crate::Error, Option<T>)>, mut when: impl Future<Output=Result<U, (crate::Error, Option<T>)>> + Unpin,
) -> impl Future<Item=(), Error=()> { ) -> impl Future<Output=()> {
let mut cb = Some(self); let mut cb = Some(self);
// "select" on this callback being canceled, and the future completing // "select" on this callback being canceled, and the future completing
future::poll_fn(move || { future::poll_fn(move |cx| {
match when.poll() { match Pin::new(&mut when).poll(cx) {
Ok(Async::Ready(res)) => { Poll::Ready(Ok(res)) => {
cb.take() cb.take()
.expect("polled after complete") .expect("polled after complete")
.send(Ok(res)); .send(Ok(res));
Ok(().into()) Poll::Ready(())
}, },
Ok(Async::NotReady) => { Poll::Pending => {
// check if the callback is canceled // check if the callback is canceled
try_ready!(cb.as_mut().unwrap().poll_cancel()); ready!(cb.as_mut().unwrap().poll_cancel(cx));
trace!("send_when canceled"); trace!("send_when canceled");
Ok(().into()) Poll::Ready(())
}, },
Err(err) => { Poll::Ready(Err(err)) => {
cb.take() cb.take()
.expect("polled after complete") .expect("polled after complete")
.send(Err(err)); .send(Err(err));
Ok(().into()) Poll::Ready(())
} }
} }
}) })

View File

@@ -82,15 +82,15 @@ use std::mem;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use futures::{Async, Future, Poll}; use futures_channel::oneshot;
use futures::future::{self, Either, Executor}; use futures_util::future::{self, FutureExt as _, Either};
use futures::sync::oneshot; use futures_util::try_future::TryFutureExt as _;
use http::{Method, Request, Response, Uri, Version}; use http::{Method, Request, Response, Uri, Version};
use http::header::{HeaderValue, HOST}; use http::header::{HeaderValue, HOST};
use http::uri::Scheme; use http::uri::Scheme;
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::{lazy as hyper_lazy, Lazy}; use crate::common::{lazy as hyper_lazy, Lazy, Future, Pin, Poll, task};
use self::connect::{Alpn, Connect, Connected, Destination}; use self::connect::{Alpn, Connect, Connected, Destination};
use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation}; use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation};
@@ -118,6 +118,16 @@ struct Config {
ver: Ver, ver: Ver,
} }
/// A `Future` that will resolve to an HTTP Response.
///
/// This is returned by `Client::request` (and `Client::get`).
#[must_use = "futures do nothing unless polled"]
pub struct ResponseFuture {
inner: Pin<Box<dyn Future<Output=crate::Result<Response<Body>>> + Send>>,
}
// ===== impl Client =====
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
impl Client<HttpConnector, Body> { impl Client<HttpConnector, Body> {
/// Create a new Client with the default [config](Builder). /// Create a new Client with the default [config](Builder).
@@ -170,7 +180,7 @@ impl<C, B> Client<C, B>
where C: Connect + Sync + 'static, where C: Connect + Sync + 'static,
C::Transport: 'static, C::Transport: 'static,
C::Future: 'static, C::Future: 'static,
B: Payload + Send + 'static, B: Payload + Unpin + Send + 'static,
B::Data: Send, B::Data: Send,
{ {
/// Send a `GET` request to the supplied `Uri`. /// Send a `GET` request to the supplied `Uri`.
@@ -257,16 +267,15 @@ where C: Connect + Sync + 'static,
ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key))) ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key)))
} }
fn retryably_send_request(&self, req: Request<B>, pool_key: PoolKey) -> impl Future<Item=Response<Body>, Error=crate::Error> { fn retryably_send_request(&self, req: Request<B>, pool_key: PoolKey) -> impl Future<Output=crate::Result<Response<Body>>> {
let client = self.clone(); let client = self.clone();
let uri = req.uri().clone(); let uri = req.uri().clone();
let mut send_fut = client.send_request(req, pool_key.clone()); let mut send_fut = client.send_request(req, pool_key.clone());
future::poll_fn(move || loop { future::poll_fn(move |cx| loop {
match send_fut.poll() { match ready!(Pin::new(&mut send_fut).poll(cx)) {
Ok(Async::Ready(resp)) => return Ok(Async::Ready(resp)), Ok(resp) => return Poll::Ready(Ok(resp)),
Ok(Async::NotReady) => return Ok(Async::NotReady), Err(ClientError::Normal(err)) => return Poll::Ready(Err(err)),
Err(ClientError::Normal(err)) => return Err(err),
Err(ClientError::Canceled { Err(ClientError::Canceled {
connection_reused, connection_reused,
mut req, mut req,
@@ -275,7 +284,7 @@ where C: Connect + Sync + 'static,
if !client.config.retry_canceled_requests || !connection_reused { if !client.config.retry_canceled_requests || !connection_reused {
// if client disabled, don't retry // if client disabled, don't retry
// a fresh connection means we definitely can't retry // a fresh connection means we definitely can't retry
return Err(reason); return Poll::Ready(Err(reason));
} }
trace!("unstarted request canceled, trying again (reason={:?})", reason); trace!("unstarted request canceled, trying again (reason={:?})", reason);
@@ -286,7 +295,7 @@ where C: Connect + Sync + 'static,
}) })
} }
fn send_request(&self, mut req: Request<B>, pool_key: PoolKey) -> impl Future<Item=Response<Body>, Error=ClientError<B>> { fn send_request(&self, mut req: Request<B>, pool_key: PoolKey) -> impl Future<Output=Result<Response<Body>, ClientError<B>>> + Unpin {
let conn = self.connection_for(req.uri().clone(), pool_key); let conn = self.connection_for(req.uri().clone(), pool_key);
let set_host = self.config.set_host; let set_host = self.config.set_host;
@@ -320,7 +329,7 @@ where C: Connect + Sync + 'static,
}; };
} else if req.method() == &Method::CONNECT { } else if req.method() == &Method::CONNECT {
debug!("client does not support CONNECT requests over HTTP2"); debug!("client does not support CONNECT requests over HTTP2");
return Either::A(future::err(ClientError::Normal(crate::Error::new_user_unsupported_request_method()))); return Either::Left(future::err(ClientError::Normal(crate::Error::new_user_unsupported_request_method())));
} }
let fut = pooled.send_request_retryable(req) let fut = pooled.send_request_retryable(req)
@@ -328,7 +337,7 @@ where C: Connect + Sync + 'static,
// If the Connector included 'extra' info, add to Response... // If the Connector included 'extra' info, add to Response...
let extra_info = pooled.conn_info.extra.clone(); let extra_info = pooled.conn_info.extra.clone();
let fut = fut.map(move |mut res| { let fut = fut.map_ok(move |mut res| {
if let Some(extra) = extra_info { if let Some(extra) = extra_info {
extra.set(&mut res); extra.set(&mut res);
} }
@@ -343,11 +352,11 @@ where C: Connect + Sync + 'static,
// To counteract this, we must check if our senders 'want' channel // To counteract this, we must check if our senders 'want' channel
// has been closed after having tried to send. If so, error out... // has been closed after having tried to send. If so, error out...
if pooled.is_closed() { if pooled.is_closed() {
return Either::B(Either::A(fut)); return Either::Right(Either::Left(fut));
} }
Either::B(Either::B(fut Either::Right(Either::Right(fut
.and_then(move |mut res| { .map_ok(move |mut res| {
// If pooled is HTTP/2, we can toss this reference immediately. // If pooled is HTTP/2, we can toss this reference immediately.
// //
// when pooled is dropped, it will try to insert back into the // when pooled is dropped, it will try to insert back into the
@@ -363,14 +372,13 @@ where C: Connect + Sync + 'static,
} else if !res.body().is_end_stream() { } else if !res.body().is_end_stream() {
let (delayed_tx, delayed_rx) = oneshot::channel(); let (delayed_tx, delayed_rx) = oneshot::channel();
res.body_mut().delayed_eof(delayed_rx); res.body_mut().delayed_eof(delayed_rx);
let on_idle = future::poll_fn(move || { let on_idle = future::poll_fn(move |cx| {
pooled.poll_ready() pooled.poll_ready(cx)
}) })
.then(move |_| { .map(move |_| {
// At this point, `pooled` is dropped, and had a chance // At this point, `pooled` is dropped, and had a chance
// to insert into the pool (if conn was idle) // to insert into the pool (if conn was idle)
drop(delayed_tx); drop(delayed_tx);
Ok(())
}); });
if let Err(err) = executor.execute(on_idle) { if let Err(err) = executor.execute(on_idle) {
@@ -380,23 +388,23 @@ where C: Connect + Sync + 'static,
} else { } else {
// There's no body to delay, but the connection isn't // There's no body to delay, but the connection isn't
// ready yet. Only re-insert when it's ready // ready yet. Only re-insert when it's ready
let on_idle = future::poll_fn(move || { let on_idle = future::poll_fn(move |cx| {
pooled.poll_ready() pooled.poll_ready(cx)
}) })
.then(|_| Ok(())); .map(|_| ());
if let Err(err) = executor.execute(on_idle) { if let Err(err) = executor.execute(on_idle) {
// This task isn't critical, so just log and ignore. // This task isn't critical, so just log and ignore.
warn!("error spawning task to insert idle connection: {}", err); warn!("error spawning task to insert idle connection: {}", err);
} }
} }
Ok(res) res
}))) })))
}) })
} }
fn connection_for(&self, uri: Uri, pool_key: PoolKey) fn connection_for(&self, uri: Uri, pool_key: PoolKey)
-> impl Future<Item=Pooled<PoolClient<B>>, Error=ClientError<B>> -> impl Future<Output=Result<Pooled<PoolClient<B>>, ClientError<B>>>
{ {
// This actually races 2 different futures to try to get a ready // This actually races 2 different futures to try to get a ready
// connection the fastest, and to reduce connection churn. // connection the fastest, and to reduce connection churn.
@@ -415,15 +423,14 @@ where C: Connect + Sync + 'static,
let connect = self.connect_to(uri, pool_key); let connect = self.connect_to(uri, pool_key);
let executor = self.conn_builder.exec.clone(); let executor = self.conn_builder.exec.clone();
checkout // The order of the `select` is depended on below...
// The order of the `select` is depended on below... future::select(checkout, connect)
.select2(connect) .then(move |either| match either {
.map(move |either| match either {
// Checkout won, connect future may have been started or not. // Checkout won, connect future may have been started or not.
// //
// If it has, let it finish and insert back into the pool, // If it has, let it finish and insert back into the pool,
// so as to not waste the socket... // so as to not waste the socket...
Either::A((checked_out, connecting)) => { Either::Left((Ok(checked_out), connecting)) => {
// This depends on the `select` above having the correct // This depends on the `select` above having the correct
// order, such that if the checkout future were ready // order, such that if the checkout future were ready
// immediately, the connect future will never have been // immediately, the connect future will never have been
@@ -433,25 +440,23 @@ where C: Connect + Sync + 'static,
// have been started... // have been started...
if connecting.started() { if connecting.started() {
let bg = connecting let bg = connecting
.map_err(|err| {
trace!("background connect error: {}", err);
})
.map(|_pooled| { .map(|_pooled| {
// dropping here should just place it in // dropping here should just place it in
// the Pool for us... // the Pool for us...
})
.map_err(|err| {
trace!("background connect error: {}", err);
}); });
// An execute error here isn't important, we're just trying // An execute error here isn't important, we're just trying
// to prevent a waste of a socket... // to prevent a waste of a socket...
let _ = executor.execute(bg); let _ = executor.execute(bg);
} }
checked_out Either::Left(future::ok(checked_out))
}, },
// Connect won, checkout can just be dropped. // Connect won, checkout can just be dropped.
Either::B((connected, _checkout)) => { Either::Right((Ok(connected), _checkout)) => {
connected Either::Left(future::ok(connected))
}, },
})
.or_else(|either| match either {
// Either checkout or connect could get canceled: // Either checkout or connect could get canceled:
// //
// 1. Connect is canceled if this is HTTP/2 and there is // 1. Connect is canceled if this is HTTP/2 and there is
@@ -460,25 +465,25 @@ where C: Connect + Sync + 'static,
// idle connection reliably. // idle connection reliably.
// //
// In both cases, we should just wait for the other future. // In both cases, we should just wait for the other future.
Either::A((err, connecting)) => { Either::Left((Err(err), connecting)) => Either::Right(Either::Left({
if err.is_canceled() { if err.is_canceled() {
Either::A(Either::A(connecting.map_err(ClientError::Normal))) Either::Left(connecting.map_err(ClientError::Normal))
} else { } else {
Either::B(future::err(ClientError::Normal(err))) Either::Right(future::err(ClientError::Normal(err)))
} }
}, })),
Either::B((err, checkout)) => { Either::Right((Err(err), checkout)) => Either::Right(Either::Right({
if err.is_canceled() { if err.is_canceled() {
Either::A(Either::B(checkout.map_err(ClientError::Normal))) Either::Left(checkout.map_err(ClientError::Normal))
} else { } else {
Either::B(future::err(ClientError::Normal(err))) Either::Right(future::err(ClientError::Normal(err)))
} }
} })),
}) })
} }
fn connect_to(&self, uri: Uri, pool_key: PoolKey) fn connect_to(&self, uri: Uri, pool_key: PoolKey)
-> impl Lazy<Item=Pooled<PoolClient<B>>, Error=crate::Error> -> impl Lazy<Output=crate::Result<Pooled<PoolClient<B>>>> + Unpin
{ {
let executor = self.conn_builder.exec.clone(); let executor = self.conn_builder.exec.clone();
let pool = self.pool.clone(); let pool = self.pool.clone();
@@ -499,10 +504,10 @@ where C: Connect + Sync + 'static,
Some(lock) => lock, Some(lock) => lock,
None => { None => {
let canceled = crate::Error::new_canceled().with("HTTP/2 connection in progress"); let canceled = crate::Error::new_canceled().with("HTTP/2 connection in progress");
return Either::B(future::err(canceled)); return Either::Right(future::err(canceled));
} }
}; };
Either::A(connector.connect(dst) Either::Left(connector.connect(dst)
.map_err(crate::Error::new_connect) .map_err(crate::Error::new_connect)
.and_then(move |(io, connected)| { .and_then(move |(io, connected)| {
// If ALPN is h2 and we aren't http2_only already, // If ALPN is h2 and we aren't http2_only already,
@@ -518,34 +523,34 @@ where C: Connect + Sync + 'static,
// Another connection has already upgraded, // Another connection has already upgraded,
// the pool checkout should finish up for us. // the pool checkout should finish up for us.
let canceled = crate::Error::new_canceled().with("ALPN upgraded to HTTP/2"); let canceled = crate::Error::new_canceled().with("ALPN upgraded to HTTP/2");
return Either::B(future::err(canceled)); return Either::Right(future::err(canceled));
} }
} }
} else { } else {
connecting connecting
}; };
let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2; let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2;
Either::A(conn_builder Either::Left(conn_builder
.http2_only(is_h2) .http2_only(is_h2)
.handshake(io) .handshake(io)
.and_then(move |(tx, conn)| { .and_then(move |(tx, conn)| {
trace!("handshake complete, spawning background dispatcher task"); trace!("handshake complete, spawning background dispatcher task");
let bg = executor.execute(conn.map_err(|e| { let bg = executor.execute(conn.map_err(|e| {
debug!("client connection error: {}", e) debug!("client connection error: {}", e)
})); }).map(|_| ()));
// This task is critical, so an execute error // This task is critical, so an execute error
// should be returned. // should be returned.
if let Err(err) = bg { if let Err(err) = bg {
warn!("error spawning critical client task: {}", err); warn!("error spawning critical client task: {}", err);
return Either::A(future::err(err)); return Either::Left(future::err(err));
} }
// Wait for 'conn' to ready up before we // Wait for 'conn' to ready up before we
// declare this tx as usable // declare this tx as usable
Either::B(tx.when_ready()) Either::Right(tx.when_ready())
}) })
.map(move |tx| { .map_ok(move |tx| {
pool.pooled(connecting, PoolClient { pool.pooled(connecting, PoolClient {
conn_info: connected, conn_info: connected,
tx: if is_h2 { tx: if is_h2 {
@@ -578,18 +583,12 @@ impl<C, B> fmt::Debug for Client<C, B> {
} }
} }
/// A `Future` that will resolve to an HTTP Response. // ===== impl ResponseFuture =====
///
/// This is returned by `Client::request` (and `Client::get`).
#[must_use = "futures do nothing unless polled"]
pub struct ResponseFuture {
inner: Box<dyn Future<Item=Response<Body>, Error=crate::Error> + Send>,
}
impl ResponseFuture { impl ResponseFuture {
fn new(fut: Box<dyn Future<Item=Response<Body>, Error=crate::Error> + Send>) -> Self { fn new(fut: Box<dyn Future<Output=crate::Result<Response<Body>>> + Send>) -> Self {
Self { Self {
inner: fut, inner: fut.into(),
} }
} }
@@ -606,14 +605,15 @@ impl fmt::Debug for ResponseFuture {
} }
impl Future for ResponseFuture { impl Future for ResponseFuture {
type Item = Response<Body>; type Output = crate::Result<Response<Body>>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
self.inner.poll() Pin::new(&mut self.inner).poll(cx)
} }
} }
// ===== impl PoolClient =====
// FIXME: allow() required due to `impl Trait` leaking types to this lint // FIXME: allow() required due to `impl Trait` leaking types to this lint
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
struct PoolClient<B> { struct PoolClient<B> {
@@ -627,10 +627,10 @@ enum PoolTx<B> {
} }
impl<B> PoolClient<B> { impl<B> PoolClient<B> {
fn poll_ready(&mut self) -> Poll<(), crate::Error> { fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
match self.tx { match self.tx {
PoolTx::Http1(ref mut tx) => tx.poll_ready(), PoolTx::Http1(ref mut tx) => tx.poll_ready(cx),
PoolTx::Http2(_) => Ok(Async::Ready(())), PoolTx::Http2(_) => Poll::Ready(Ok(())),
} }
} }
@@ -661,13 +661,13 @@ impl<B> PoolClient<B> {
} }
impl<B: Payload + 'static> PoolClient<B> { impl<B: Payload + 'static> PoolClient<B> {
fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Item = Response<Body>, Error = (crate::Error, Option<Request<B>>)> fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>>
where where
B: Send, B: Send,
{ {
match self.tx { match self.tx {
PoolTx::Http1(ref mut tx) => Either::A(tx.send_request_retryable(req)), PoolTx::Http1(ref mut tx) => Either::Left(tx.send_request_retryable(req)),
PoolTx::Http2(ref mut tx) => Either::B(tx.send_request_retryable(req)), PoolTx::Http2(ref mut tx) => Either::Right(tx.send_request_retryable(req)),
} }
} }
} }
@@ -710,6 +710,8 @@ where
} }
} }
// ===== impl ClientError =====
// FIXME: allow() required due to `impl Trait` leaking types to this lint // FIXME: allow() required due to `impl Trait` leaking types to this lint
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
enum ClientError<B> { enum ClientError<B> {
@@ -1027,6 +1029,7 @@ impl Builder {
self self
} }
/*
/// Provide an executor to execute background `Connection` tasks. /// Provide an executor to execute background `Connection` tasks.
pub fn executor<E>(&mut self, exec: E) -> &mut Self pub fn executor<E>(&mut self, exec: E) -> &mut Self
where where
@@ -1035,6 +1038,7 @@ impl Builder {
self.conn_builder.executor(exec); self.conn_builder.executor(exec);
self self
} }
*/
/// Builder a client with this configuration and the default `HttpConnector`. /// Builder a client with this configuration and the default `HttpConnector`.
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]

View File

@@ -4,12 +4,11 @@ use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Weak}; use std::sync::{Arc, Mutex, Weak};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use futures::{Future, Async, Poll}; use futures_channel::oneshot;
use futures::sync::oneshot;
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
use tokio_timer::Interval; use tokio_timer::Interval;
use crate::common::Exec; use crate::common::{Exec, Future, Pin, Poll, Unpin, task};
use super::Ver; use super::Ver;
// FIXME: allow() required due to `impl Trait` leaking types to this lint // FIXME: allow() required due to `impl Trait` leaking types to this lint
@@ -24,7 +23,7 @@ pub(super) struct Pool<T> {
// This is a trait to allow the `client::pool::tests` to work for `i32`. // This is a trait to allow the `client::pool::tests` to work for `i32`.
// //
// See https://github.com/hyperium/hyper/issues/1429 // See https://github.com/hyperium/hyper/issues/1429
pub(super) trait Poolable: Send + Sized + 'static { pub(super) trait Poolable: Unpin + Send + Sized + 'static {
fn is_open(&self) -> bool; fn is_open(&self) -> bool;
/// Reserve this connection. /// Reserve this connection.
/// ///
@@ -415,7 +414,7 @@ impl<T: Poolable> PoolInner<T> {
let start = Instant::now() + dur; let start = Instant::now() + dur;
let interval = IdleInterval { let interval = IdleTask {
interval: Interval::new(start, dur), interval: Interval::new(start, dur),
pool: WeakOpt::downgrade(pool_ref), pool: WeakOpt::downgrade(pool_ref),
pool_drop_notifier: rx, pool_drop_notifier: rx,
@@ -449,7 +448,7 @@ impl<T> PoolInner<T> {
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
impl<T: Poolable> PoolInner<T> { impl<T: Poolable> PoolInner<T> {
/// This should *only* be called by the IdleInterval. /// This should *only* be called by the IdleTask
fn clear_expired(&mut self) { fn clear_expired(&mut self) {
let dur = self.timeout.expect("interval assumes timeout"); let dur = self.timeout.expect("interval assumes timeout");
@@ -569,25 +568,25 @@ pub(super) struct Checkout<T> {
} }
impl<T: Poolable> Checkout<T> { impl<T: Poolable> Checkout<T> {
fn poll_waiter(&mut self) -> Poll<Option<Pooled<T>>, crate::Error> { fn poll_waiter(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Pooled<T>>>> {
static CANCELED: &str = "pool checkout failed"; static CANCELED: &str = "pool checkout failed";
if let Some(mut rx) = self.waiter.take() { if let Some(mut rx) = self.waiter.take() {
match rx.poll() { match Pin::new(&mut rx).poll(cx) {
Ok(Async::Ready(value)) => { Poll::Ready(Ok(value)) => {
if value.is_open() { if value.is_open() {
Ok(Async::Ready(Some(self.pool.reuse(&self.key, value)))) Poll::Ready(Some(Ok(self.pool.reuse(&self.key, value))))
} else { } else {
Err(crate::Error::new_canceled().with(CANCELED)) Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED))))
} }
}, },
Ok(Async::NotReady) => { Poll::Pending => {
self.waiter = Some(rx); self.waiter = Some(rx);
Ok(Async::NotReady) Poll::Pending
}, },
Err(_canceled) => Err(crate::Error::new_canceled().with(CANCELED)), Poll::Ready(Err(_canceled)) => Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED)))),
} }
} else { } else {
Ok(Async::Ready(None)) Poll::Ready(None)
} }
} }
@@ -622,9 +621,7 @@ impl<T: Poolable> Checkout<T> {
} }
if entry.is_none() && self.waiter.is_none() { if entry.is_none() && self.waiter.is_none() {
let (tx, mut rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let _ = rx.poll(); // park this task
trace!("checkout waiting for idle connection: {:?}", self.key); trace!("checkout waiting for idle connection: {:?}", self.key);
inner inner
.waiters .waiters
@@ -643,20 +640,21 @@ impl<T: Poolable> Checkout<T> {
} }
impl<T: Poolable> Future for Checkout<T> { impl<T: Poolable> Future for Checkout<T> {
type Item = Pooled<T>; type Output = crate::Result<Pooled<T>>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
if let Some(pooled) = try_ready!(self.poll_waiter()) { if let Some(pooled) = ready!(self.poll_waiter(cx)?) {
return Ok(Async::Ready(pooled)); return Poll::Ready(Ok(pooled));
} }
if let Some(pooled) = self.checkout() { if let Some(pooled) = self.checkout() {
Ok(Async::Ready(pooled)) Poll::Ready(Ok(pooled))
} else if !self.pool.is_enabled() { } else if !self.pool.is_enabled() {
Err(crate::Error::new_canceled().with("pool is disabled")) Poll::Ready(Err(crate::Error::new_canceled().with("pool is disabled")))
} else { } else {
Ok(Async::NotReady) // There's a new waiter, but there's no way it should be ready yet.
// We just need to register the waker.
self.poll_waiter(cx).map(|_| unreachable!())
} }
} }
} }
@@ -717,37 +715,34 @@ impl Expiration {
} }
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
struct IdleInterval<T> { struct IdleTask<T> {
interval: Interval, interval: Interval,
pool: WeakOpt<Mutex<PoolInner<T>>>, pool: WeakOpt<Mutex<PoolInner<T>>>,
// This allows the IdleInterval to be notified as soon as the entire // This allows the IdleTask to be notified as soon as the entire
// Pool is fully dropped, and shutdown. This channel is never sent on, // Pool is fully dropped, and shutdown. This channel is never sent on,
// but Err(Canceled) will be received when the Pool is dropped. // but Err(Canceled) will be received when the Pool is dropped.
pool_drop_notifier: oneshot::Receiver<crate::common::Never>, pool_drop_notifier: oneshot::Receiver<crate::common::Never>,
} }
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
impl<T: Poolable + 'static> Future for IdleInterval<T> { impl<T: Poolable + 'static> Future for IdleTask<T> {
type Item = (); type Output = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
// Interval is a Stream // Interval is a Stream
use futures::Stream; use futures_core::Stream;
loop { loop {
match self.pool_drop_notifier.poll() { match Pin::new(&mut self.pool_drop_notifier).poll(cx) {
Ok(Async::Ready(n)) => match n {}, Poll::Ready(Ok(n)) => match n {},
Ok(Async::NotReady) => (), Poll::Pending => (),
Err(_canceled) => { Poll::Ready(Err(_canceled)) => {
trace!("pool closed, canceling idle interval"); trace!("pool closed, canceling idle interval");
return Ok(Async::Ready(())); return Poll::Ready(());
} }
} }
try_ready!(self.interval.poll().map_err(|err| { ready!(Pin::new(&mut self.interval).poll_next(cx));
error!("idle interval timer error: {}", err);
}));
if let Some(inner) = self.pool.upgrade() { if let Some(inner) = self.pool.upgrade() {
if let Ok(mut inner) = inner.lock() { if let Ok(mut inner) = inner.lock() {
@@ -756,7 +751,7 @@ impl<T: Poolable + 'static> Future for IdleInterval<T> {
continue; continue;
} }
} }
return Ok(Async::Ready(())); return Poll::Ready(());
} }
} }
} }

View File

@@ -1,14 +1,19 @@
use std::mem; use std::mem;
use futures::{Async, Future, Poll, Stream}; use tokio_sync::{mpsc, watch};
use futures::future::Shared;
use futures::sync::{mpsc, oneshot};
use super::Never; use super::{Future, Never, Poll, Pin, task};
// Sentinel value signaling that the watch is still open
enum Action {
Open,
// Closed isn't sent via the `Action` type, but rather once
// the watch::Sender is dropped.
}
pub fn channel() -> (Signal, Watch) { pub fn channel() -> (Signal, Watch) {
let (tx, rx) = oneshot::channel(); let (tx, rx) = watch::channel(Action::Open);
let (drained_tx, drained_rx) = mpsc::channel(0); let (drained_tx, drained_rx) = mpsc::channel(1);
( (
Signal { Signal {
drained_rx, drained_rx,
@@ -16,14 +21,14 @@ pub fn channel() -> (Signal, Watch) {
}, },
Watch { Watch {
drained_tx, drained_tx,
rx: rx.shared(), rx,
}, },
) )
} }
pub struct Signal { pub struct Signal {
drained_rx: mpsc::Receiver<Never>, drained_rx: mpsc::Receiver<Never>,
tx: oneshot::Sender<()>, tx: watch::Sender<Action>,
} }
pub struct Draining { pub struct Draining {
@@ -33,7 +38,7 @@ pub struct Draining {
#[derive(Clone)] #[derive(Clone)]
pub struct Watch { pub struct Watch {
drained_tx: mpsc::Sender<Never>, drained_tx: mpsc::Sender<Never>,
rx: Shared<oneshot::Receiver<()>>, rx: watch::Receiver<Action>,
} }
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@@ -50,7 +55,7 @@ enum State<F> {
impl Signal { impl Signal {
pub fn drain(self) -> Draining { pub fn drain(self) -> Draining {
let _ = self.tx.send(()); // Simply dropping `self.tx` will signal the watchers
Draining { Draining {
drained_rx: self.drained_rx, drained_rx: self.drained_rx,
} }
@@ -58,13 +63,12 @@ impl Signal {
} }
impl Future for Draining { impl Future for Draining {
type Item = (); type Output = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match try_ready!(self.drained_rx.poll()) { match ready!(self.drained_rx.poll_recv(cx)) {
Some(never) => match never {}, Some(never) => match never {},
None => Ok(Async::Ready(())), None => Poll::Ready(()),
} }
} }
} }
@@ -73,7 +77,7 @@ impl Watch {
pub fn watch<F, FN>(self, future: F, on_drain: FN) -> Watching<F, FN> pub fn watch<F, FN>(self, future: F, on_drain: FN) -> Watching<F, FN>
where where
F: Future, F: Future,
FN: FnOnce(&mut F), FN: FnOnce(Pin<&mut F>),
{ {
Watching { Watching {
future, future,
@@ -86,28 +90,29 @@ impl Watch {
impl<F, FN> Future for Watching<F, FN> impl<F, FN> Future for Watching<F, FN>
where where
F: Future, F: Future,
FN: FnOnce(&mut F), FN: FnOnce(Pin<&mut F>),
{ {
type Item = F::Item; type Output = F::Output;
type Error = F::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
let me = unsafe { self.get_unchecked_mut() };
loop { loop {
match mem::replace(&mut self.state, State::Draining) { match mem::replace(&mut me.state, State::Draining) {
State::Watch(on_drain) => { State::Watch(on_drain) => {
match self.watch.rx.poll() { match me.watch.rx.poll_ref(cx) {
Ok(Async::Ready(_)) | Err(_) => { Poll::Ready(None) => {
// Drain has been triggered! // Drain has been triggered!
on_drain(&mut self.future); on_drain(unsafe { Pin::new_unchecked(&mut me.future) });
}, },
Ok(Async::NotReady) => { Poll::Ready(Some(_/*State::Open*/)) |
self.state = State::Watch(on_drain); Poll::Pending => {
return self.future.poll(); me.state = State::Watch(on_drain);
return unsafe { Pin::new_unchecked(&mut me.future) }.poll(cx);
}, },
} }
}, },
State::Draining => { State::Draining => {
return self.future.poll(); return unsafe { Pin::new_unchecked(&mut me.future) }.poll(cx);
}, },
} }
} }

View File

@@ -1,7 +1,9 @@
use std::fmt; use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use futures::future::{Executor, Future}; use tokio_executor::TypedExecutor;
use crate::body::Payload; use crate::body::Payload;
use crate::proto::h2::server::H2Stream; use crate::proto::h2::server::H2Stream;
@@ -9,11 +11,11 @@ use crate::server::conn::spawn_all::{NewSvcTask, Watcher};
use crate::service::Service; use crate::service::Service;
pub trait H2Exec<F, B: Payload>: Clone { pub trait H2Exec<F, B: Payload>: Clone {
fn execute_h2stream(&self, fut: H2Stream<F, B>) -> crate::Result<()>; fn execute_h2stream(&mut self, fut: H2Stream<F, B>) -> crate::Result<()>;
} }
pub trait NewSvcExec<I, N, S: Service, E, W: Watcher<I, S, E>>: Clone { pub trait NewSvcExec<I, N, S: Service, E, W: Watcher<I, S, E>>: Clone {
fn execute_new_svc(&self, fut: NewSvcTask<I, N, S, E, W>) -> crate::Result<()>; fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>) -> crate::Result<()>;
} }
// Either the user provides an executor for background tasks, or we use // Either the user provides an executor for background tasks, or we use
@@ -21,7 +23,7 @@ pub trait NewSvcExec<I, N, S: Service, E, W: Watcher<I, S, E>>: Clone {
#[derive(Clone)] #[derive(Clone)]
pub enum Exec { pub enum Exec {
Default, Default,
Executor(Arc<dyn Executor<Box<dyn Future<Item=(), Error=()> + Send>> + Send + Sync>), Executor(Arc<dyn TypedExecutor<Pin<Box<dyn Future<Output=()> + Send>>> + Send + Sync>),
} }
// ===== impl Exec ===== // ===== impl Exec =====
@@ -29,14 +31,13 @@ pub enum Exec {
impl Exec { impl Exec {
pub(crate) fn execute<F>(&self, fut: F) -> crate::Result<()> pub(crate) fn execute<F>(&self, fut: F) -> crate::Result<()>
where where
F: Future<Item=(), Error=()> + Send + 'static, F: Future<Output=()> + Send + 'static,
{ {
match *self { match *self {
Exec::Default => { Exec::Default => {
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
{ {
use std::error::Error as StdError; use std::error::Error as StdError;
use ::tokio_executor::Executor;
struct TokioSpawnError; struct TokioSpawnError;
@@ -59,7 +60,7 @@ impl Exec {
} }
::tokio_executor::DefaultExecutor::current() ::tokio_executor::DefaultExecutor::current()
.spawn(Box::new(fut)) .spawn(Box::pin(fut))
.map_err(|err| { .map_err(|err| {
warn!("executor error: {:?}", err); warn!("executor error: {:?}", err);
crate::Error::new_execute(TokioSpawnError) crate::Error::new_execute(TokioSpawnError)
@@ -72,11 +73,14 @@ impl Exec {
} }
}, },
Exec::Executor(ref e) => { Exec::Executor(ref e) => {
e.execute(Box::new(fut)) unimplemented!("custom executor exec");
/* XXX: needs mut
e.spawn(Box::pin(fut))
.map_err(|err| { .map_err(|err| {
warn!("executor error: {:?}", err.kind()); warn!("executor error: {:?}", err);
crate::Error::new_execute("custom executor failed") crate::Error::new_execute("custom executor failed")
}) })
*/
}, },
} }
} }
@@ -92,21 +96,21 @@ impl fmt::Debug for Exec {
impl<F, B> H2Exec<F, B> for Exec impl<F, B> H2Exec<F, B> for Exec
where where
H2Stream<F, B>: Future<Item=(), Error=()> + Send + 'static, H2Stream<F, B>: Future<Output = ()> + Send + 'static,
B: Payload, B: Payload,
{ {
fn execute_h2stream(&self, fut: H2Stream<F, B>) -> crate::Result<()> { fn execute_h2stream(&mut self, fut: H2Stream<F, B>) -> crate::Result<()> {
self.execute(fut) self.execute(fut)
} }
} }
impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec
where where
NewSvcTask<I, N, S, E, W>: Future<Item=(), Error=()> + Send + 'static, NewSvcTask<I, N, S, E, W>: Future<Output=()> + Send + 'static,
S: Service, S: Service,
W: Watcher<I, S, E>, W: Watcher<I, S, E>,
{ {
fn execute_new_svc(&self, fut: NewSvcTask<I, N, S, E, W>) -> crate::Result<()> { fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>) -> crate::Result<()> {
self.execute(fut) self.execute(fut)
} }
} }
@@ -115,14 +119,14 @@ where
impl<E, F, B> H2Exec<F, B> for E impl<E, F, B> H2Exec<F, B> for E
where where
E: Executor<H2Stream<F, B>> + Clone, E: TypedExecutor<H2Stream<F, B>> + Clone,
H2Stream<F, B>: Future<Item=(), Error=()>, H2Stream<F, B>: Future<Output=()>,
B: Payload, B: Payload,
{ {
fn execute_h2stream(&self, fut: H2Stream<F, B>) -> crate::Result<()> { fn execute_h2stream(&mut self, fut: H2Stream<F, B>) -> crate::Result<()> {
self.execute(fut) self.spawn(fut)
.map_err(|err| { .map_err(|err| {
warn!("executor error: {:?}", err.kind()); warn!("executor error: {:?}", err);
crate::Error::new_execute("custom executor failed") crate::Error::new_execute("custom executor failed")
}) })
} }
@@ -130,15 +134,15 @@ where
impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E
where where
E: Executor<NewSvcTask<I, N, S, E, W>> + Clone, E: TypedExecutor<NewSvcTask<I, N, S, E, W>> + Clone,
NewSvcTask<I, N, S, E, W>: Future<Item=(), Error=()>, NewSvcTask<I, N, S, E, W>: Future<Output=()>,
S: Service, S: Service,
W: Watcher<I, S, E>, W: Watcher<I, S, E>,
{ {
fn execute_new_svc(&self, fut: NewSvcTask<I, N, S, E, W>) -> crate::Result<()> { fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>) -> crate::Result<()> {
self.execute(fut) self.spawn(fut)
.map_err(|err| { .map_err(|err| {
warn!("executor error: {:?}", err.kind()); warn!("executor error: {:?}", err);
crate::Error::new_execute("custom executor failed") crate::Error::new_execute("custom executor failed")
}) })
} }

View File

@@ -1,10 +1,11 @@
use std::cmp; use std::io::{self, Read};
use std::io::{self, Read, Write}; use std::marker::Unpin;
use bytes::{Buf, BufMut, Bytes, IntoBuf}; use bytes::{Buf, BufMut, Bytes, IntoBuf};
use futures::{Async, Poll};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, task};
/// Combine a buffer with an IO, rewinding reads to use the buffer. /// Combine a buffer with an IO, rewinding reads to use the buffer.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Rewind<T> { pub(crate) struct Rewind<T> {
@@ -37,12 +38,16 @@ impl<T> Rewind<T> {
} }
} }
impl<T> Read for Rewind<T> impl<T> AsyncRead for Rewind<T>
where where
T: Read, T: AsyncRead + Unpin,
{ {
#[inline] #[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.inner.prepare_uninitialized_buffer(buf)
}
fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
if let Some(pre_bs) = self.pre.take() { if let Some(pre_bs) = self.pre.take() {
// If there are no remaining bytes, let the bytes get dropped. // If there are no remaining bytes, let the bytes get dropped.
if pre_bs.len() > 0 { if pre_bs.len() > 0 {
@@ -57,39 +62,17 @@ where
self.pre = Some(new_pre); self.pre = Some(new_pre);
} }
return Ok(read_cnt); return Poll::Ready(Ok(read_cnt));
} }
} }
self.inner.read(buf) Pin::new(&mut self.inner).poll_read(cx, buf)
}
}
impl<T> Write for Rewind<T>
where
T: Write,
{
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<T> AsyncRead for Rewind<T>
where
T: AsyncRead,
{
#[inline]
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.inner.prepare_uninitialized_buffer(buf)
} }
/*
#[inline] #[inline]
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
use std::cmp;
if let Some(bs) = self.pre.take() { if let Some(bs) = self.pre.take() {
let pre_len = bs.len(); let pre_len = bs.len();
// If there are no remaining bytes, let the bytes get dropped. // If there are no remaining bytes, let the bytes get dropped.
@@ -112,21 +95,31 @@ where
} }
self.inner.read_buf(buf) self.inner.read_buf(buf)
} }
*/
} }
impl<T> AsyncWrite for Rewind<T> impl<T> AsyncWrite for Rewind<T>
where where
T: AsyncWrite, T: AsyncWrite + Unpin,
{ {
#[inline] fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
fn shutdown(&mut self) -> Poll<(), io::Error> { Pin::new(&mut self.inner).poll_write(cx, buf)
AsyncWrite::shutdown(&mut self.inner)
} }
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_flush(cx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_shutdown(cx)
}
/*
#[inline] #[inline]
fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
self.inner.write_buf(buf) self.inner.write_buf(buf)
} }
*/
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,6 +1,6 @@
use std::mem; use std::mem;
use futures::{Future, IntoFuture, Poll}; use super::{Future, Pin, Poll, task};
pub(crate) trait Started: Future { pub(crate) trait Started: Future {
fn started(&self) -> bool; fn started(&self) -> bool;
@@ -9,7 +9,7 @@ pub(crate) trait Started: Future {
pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R> pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R>
where where
F: FnOnce() -> R, F: FnOnce() -> R,
R: IntoFuture, R: Future + Unpin,
{ {
Lazy { Lazy {
inner: Inner::Init(func), inner: Inner::Init(func),
@@ -18,8 +18,8 @@ where
// FIXME: allow() required due to `impl Trait` leaking types to this lint // FIXME: allow() required due to `impl Trait` leaking types to this lint
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub(crate) struct Lazy<F, R: IntoFuture> { pub(crate) struct Lazy<F, R> {
inner: Inner<F, R::Future> inner: Inner<F, R>
} }
enum Inner<F, R> { enum Inner<F, R> {
@@ -31,7 +31,7 @@ enum Inner<F, R> {
impl<F, R> Started for Lazy<F, R> impl<F, R> Started for Lazy<F, R>
where where
F: FnOnce() -> R, F: FnOnce() -> R,
R: IntoFuture, R: Future + Unpin,
{ {
fn started(&self) -> bool { fn started(&self) -> bool {
match self.inner { match self.inner {
@@ -45,21 +45,20 @@ where
impl<F, R> Future for Lazy<F, R> impl<F, R> Future for Lazy<F, R>
where where
F: FnOnce() -> R, F: FnOnce() -> R,
R: IntoFuture, R: Future + Unpin,
{ {
type Item = R::Item; type Output = R::Output;
type Error = R::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match self.inner { match self.inner {
Inner::Fut(ref mut f) => return f.poll(), Inner::Fut(ref mut f) => return Pin::new(f).poll(cx),
_ => (), _ => (),
} }
match mem::replace(&mut self.inner, Inner::Empty) { match mem::replace(&mut self.inner, Inner::Empty) {
Inner::Init(func) => { Inner::Init(func) => {
let mut fut = func().into_future(); let mut fut = func();
let ret = fut.poll(); let ret = Pin::new(&mut fut).poll(cx);
self.inner = Inner::Fut(fut); self.inner = Inner::Fut(fut);
ret ret
}, },
@@ -68,3 +67,6 @@ where
} }
} }
// The closure `F` is never pinned
impl<F, R: Unpin> Unpin for Lazy<F, R> {}

View File

@@ -1,3 +1,12 @@
macro_rules! ready {
($e:expr) => (
match $e {
::std::task::Poll::Ready(v) => v,
::std::task::Poll::Pending => return ::std::task::Poll::Pending,
}
)
}
mod buf; mod buf;
pub(crate) mod drain; pub(crate) mod drain;
pub(crate) mod exec; pub(crate) mod exec;
@@ -10,4 +19,12 @@ pub(crate) use self::buf::StaticBuf;
pub(crate) use self::exec::Exec; pub(crate) use self::exec::Exec;
pub(crate) use self::lazy::{lazy, Started as Lazy}; pub(crate) use self::lazy::{lazy, Started as Lazy};
pub use self::never::Never; pub use self::never::Never;
pub(crate) use self::task::YieldNow; pub(crate) use self::task::Poll;
// group up types normally needed for `Future`
pub(crate) use std::{
future::Future,
marker::Unpin,
pin::Pin,
};

View File

@@ -1,40 +1,10 @@
use futures::{Async, Poll, task::Task}; pub(crate) use std::task::{Context, Poll};
use super::Never; use super::Never;
/// A type to help "yield" a future, such that it is re-scheduled immediately. /// A function to help "yield" a future, such that it is re-scheduled immediately.
/// ///
/// Useful for spin counts, so a future doesn't hog too much time. /// Useful for spin counts, so a future doesn't hog too much time.
#[derive(Debug)] pub(crate) fn yield_now(cx: &mut Context) -> Poll<Never> {
pub(crate) struct YieldNow { cx.waker().wake_by_ref();
cached_task: Option<Task>, Poll::Pending
}
impl YieldNow {
pub(crate) fn new() -> YieldNow {
YieldNow {
cached_task: None,
}
}
/// Returns `Ok(Async::NotReady)` always, while also notifying the
/// current task so that it is rescheduled immediately.
///
/// Since it never returns `Async::Ready` or `Err`, those types are
/// set to `Never`.
pub(crate) fn poll_yield(&mut self) -> Poll<Never, Never> {
// Check for a cached `Task` first...
if let Some(ref t) = self.cached_task {
if t.will_notify_current() {
t.notify();
return Ok(Async::NotReady);
}
}
// No cached task, or not current, so get a new one...
let t = ::futures::task::current();
t.notify();
self.cached_task = Some(t);
Ok(Async::NotReady)
}
} }

View File

@@ -1,7 +1,10 @@
#![doc(html_root_url = "https://docs.rs/hyper/0.12.32")] #![doc(html_root_url = "https://docs.rs/hyper/0.12.32")]
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))] // XXX NOOOOOOOO
//#![cfg_attr(test, deny(warnings))]
#![allow(warnings)]
#![feature(async_await)]
#![cfg_attr(all(test, feature = "nightly"), feature(test))] #![cfg_attr(all(test, feature = "nightly"), feature(test))]
//! # hyper //! # hyper
@@ -17,27 +20,8 @@
//! If looking for just a convenient HTTP client, consider the //! If looking for just a convenient HTTP client, consider the
//! [reqwest](https://crates.io/crates/reqwest) crate. //! [reqwest](https://crates.io/crates/reqwest) crate.
extern crate bytes;
#[macro_use] extern crate futures;
#[cfg(feature = "runtime")] extern crate futures_cpupool;
extern crate h2;
#[doc(hidden)] pub extern crate http; #[doc(hidden)] pub extern crate http;
extern crate http_body;
extern crate httparse;
extern crate iovec;
extern crate itoa;
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[cfg(feature = "runtime")] extern crate net2;
extern crate time;
#[cfg(feature = "runtime")] extern crate tokio;
extern crate tokio_buf;
#[cfg(feature = "runtime")] extern crate tokio_executor;
#[macro_use] extern crate tokio_io;
#[cfg(feature = "runtime")] extern crate tokio_reactor;
#[cfg(feature = "runtime")] extern crate tokio_tcp;
#[cfg(feature = "runtime")] extern crate tokio_threadpool;
#[cfg(feature = "runtime")] extern crate tokio_timer;
extern crate want;
#[cfg(all(test, feature = "nightly"))] #[cfg(all(test, feature = "nightly"))]
extern crate test; extern crate test;

View File

@@ -3,12 +3,12 @@ use std::io::{self};
use std::marker::PhantomData; use std::marker::PhantomData;
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use futures::{Async, Poll};
use http::{HeaderMap, Method, Version}; use http::{HeaderMap, Method, Version};
use http::header::{HeaderValue, CONNECTION}; use http::header::{HeaderValue, CONNECTION};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::Chunk; use crate::Chunk;
use crate::common::{Pin, Poll, Unpin, task};
use crate::proto::{BodyLength, DecodedLength, MessageHead}; use crate::proto::{BodyLength, DecodedLength, MessageHead};
use crate::headers::connection_keep_alive; use crate::headers::connection_keep_alive;
use super::io::{Buffered}; use super::io::{Buffered};
@@ -26,11 +26,11 @@ const H2_PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
pub(crate) struct Conn<I, B, T> { pub(crate) struct Conn<I, B, T> {
io: Buffered<I, EncodedBuf<B>>, io: Buffered<I, EncodedBuf<B>>,
state: State, state: State,
_marker: PhantomData<T> _marker: PhantomData<fn(T)>
} }
impl<I, B, T> Conn<I, B, T> impl<I, B, T> Conn<I, B, T>
where I: AsyncRead + AsyncWrite, where I: AsyncRead + AsyncWrite + Unpin,
B: Buf, B: Buf,
T: Http1Transaction, T: Http1Transaction,
{ {
@@ -129,16 +129,15 @@ where I: AsyncRead + AsyncWrite,
read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE
} }
pub fn read_head(&mut self) -> Poll<Option<(MessageHead<T::Incoming>, DecodedLength, bool)>, crate::Error> { pub fn poll_read_head(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<(MessageHead<T::Incoming>, DecodedLength, bool)>>> {
debug_assert!(self.can_read_head()); debug_assert!(self.can_read_head());
trace!("Conn::read_head"); trace!("Conn::read_head");
let msg = match self.io.parse::<T>(ParseContext { let msg = match ready!(self.io.parse::<T>(cx, ParseContext {
cached_headers: &mut self.state.cached_headers, cached_headers: &mut self.state.cached_headers,
req_method: &mut self.state.method, req_method: &mut self.state.method,
}) { })) {
Ok(Async::Ready(msg)) => msg, Ok(msg) => msg,
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => return self.on_read_head_error(e), Err(e) => return self.on_read_head_error(e),
}; };
@@ -155,7 +154,7 @@ where I: AsyncRead + AsyncWrite,
debug_assert!(!msg.expect_continue, "expect-continue needs a body"); debug_assert!(!msg.expect_continue, "expect-continue needs a body");
self.state.reading = Reading::KeepAlive; self.state.reading = Reading::KeepAlive;
if !T::should_read_first() { if !T::should_read_first() {
self.try_keep_alive(); self.try_keep_alive(cx);
} }
} else { } else {
if msg.expect_continue { if msg.expect_continue {
@@ -165,10 +164,10 @@ where I: AsyncRead + AsyncWrite,
self.state.reading = Reading::Body(Decoder::new(msg.decode)); self.state.reading = Reading::Body(Decoder::new(msg.decode));
}; };
Ok(Async::Ready(Some((msg.head, msg.decode, msg.wants_upgrade)))) Poll::Ready(Some(Ok((msg.head, msg.decode, msg.wants_upgrade))))
} }
fn on_read_head_error<Z>(&mut self, e: crate::Error) -> Poll<Option<Z>, crate::Error> { fn on_read_head_error<Z>(&mut self, e: crate::Error) -> Poll<Option<crate::Result<Z>>> {
// If we are currently waiting on a message, then an empty // If we are currently waiting on a message, then an empty
// message should be reported as an error. If not, it is just // message should be reported as an error. If not, it is just
// the connection closing gracefully. // the connection closing gracefully.
@@ -179,25 +178,28 @@ where I: AsyncRead + AsyncWrite,
if was_mid_parse || must_error { if was_mid_parse || must_error {
// We check if the buf contains the h2 Preface // We check if the buf contains the h2 Preface
debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len()); debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len());
self.on_parse_error(e) match self.on_parse_error(e) {
.map(|()| Async::NotReady) Ok(()) => Poll::Pending, // XXX: wat?
Err(e) => Poll::Ready(Some(Err(e))),
}
} else { } else {
debug!("read eof"); debug!("read eof");
Ok(Async::Ready(None)) Poll::Ready(None)
} }
} }
pub fn read_body(&mut self) -> Poll<Option<Chunk>, io::Error> { pub fn poll_read_body(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<io::Result<Chunk>>> {
debug_assert!(self.can_read_body()); debug_assert!(self.can_read_body());
let (reading, ret) = match self.state.reading { let (reading, ret) = match self.state.reading {
Reading::Body(ref mut decoder) => { Reading::Body(ref mut decoder) => {
match decoder.decode(&mut self.io) { match decoder.decode(cx, &mut self.io) {
Ok(Async::Ready(slice)) => { Poll::Ready(Ok(slice)) => {
let (reading, chunk) = if decoder.is_eof() { let (reading, chunk) = if decoder.is_eof() {
debug!("incoming body completed"); debug!("incoming body completed");
(Reading::KeepAlive, if !slice.is_empty() { (Reading::KeepAlive, if !slice.is_empty() {
Some(Chunk::from(slice)) Some(Ok(Chunk::from(slice)))
} else { } else {
None None
}) })
@@ -208,14 +210,14 @@ where I: AsyncRead + AsyncWrite,
// an empty slice... // an empty slice...
(Reading::Closed, None) (Reading::Closed, None)
} else { } else {
return Ok(Async::Ready(Some(Chunk::from(slice)))); return Poll::Ready(Some(Ok(Chunk::from(slice))));
}; };
(reading, Ok(Async::Ready(chunk))) (reading, Poll::Ready(chunk))
}, },
Ok(Async::NotReady) => return Ok(Async::NotReady), Poll::Pending => return Poll::Pending,
Err(e) => { Poll::Ready(Err(e)) => {
debug!("decode stream error: {}", e); debug!("decode stream error: {}", e);
(Reading::Closed, Err(e)) (Reading::Closed, Poll::Ready(Some(Err(e))))
}, },
} }
}, },
@@ -223,7 +225,7 @@ where I: AsyncRead + AsyncWrite,
}; };
self.state.reading = reading; self.state.reading = reading;
self.try_keep_alive(); self.try_keep_alive(cx);
ret ret
} }
@@ -233,13 +235,13 @@ where I: AsyncRead + AsyncWrite,
ret ret
} }
pub fn read_keep_alive(&mut self) -> Poll<(), crate::Error> { pub fn poll_read_keep_alive(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
debug_assert!(!self.can_read_head() && !self.can_read_body()); debug_assert!(!self.can_read_head() && !self.can_read_body());
if self.is_mid_message() { if self.is_mid_message() {
self.mid_message_detect_eof() self.mid_message_detect_eof(cx)
} else { } else {
self.require_empty_read() self.require_empty_read(cx)
} }
} }
@@ -254,25 +256,25 @@ where I: AsyncRead + AsyncWrite,
// //
// This should only be called for Clients wanting to enter the idle // This should only be called for Clients wanting to enter the idle
// state. // state.
fn require_empty_read(&mut self) -> Poll<(), crate::Error> { fn require_empty_read(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
debug_assert!(!self.can_read_head() && !self.can_read_body()); debug_assert!(!self.can_read_head() && !self.can_read_body());
debug_assert!(!self.is_mid_message()); debug_assert!(!self.is_mid_message());
debug_assert!(T::is_client()); debug_assert!(T::is_client());
if !self.io.read_buf().is_empty() { if !self.io.read_buf().is_empty() {
debug!("received an unexpected {} bytes", self.io.read_buf().len()); debug!("received an unexpected {} bytes", self.io.read_buf().len());
return Err(crate::Error::new_unexpected_message()); return Poll::Ready(Err(crate::Error::new_unexpected_message()));
} }
let num_read = try_ready!(self.force_io_read().map_err(crate::Error::new_io)); let num_read = ready!(self.force_io_read(cx)).map_err(crate::Error::new_io)?;
if num_read == 0 { if num_read == 0 {
let ret = if self.should_error_on_eof() { let ret = if self.should_error_on_eof() {
trace!("found unexpected EOF on busy connection: {:?}", self.state); trace!("found unexpected EOF on busy connection: {:?}", self.state);
Err(crate::Error::new_incomplete()) Poll::Ready(Err(crate::Error::new_incomplete()))
} else { } else {
trace!("found EOF on idle connection, closing"); trace!("found EOF on idle connection, closing");
Ok(Async::Ready(())) Poll::Ready(Ok(()))
}; };
// order is important: should_error needs state BEFORE close_read // order is important: should_error needs state BEFORE close_read
@@ -281,38 +283,39 @@ where I: AsyncRead + AsyncWrite,
} }
debug!("received unexpected {} bytes on an idle connection", num_read); debug!("received unexpected {} bytes on an idle connection", num_read);
Err(crate::Error::new_unexpected_message()) Poll::Ready(Err(crate::Error::new_unexpected_message()))
} }
fn mid_message_detect_eof(&mut self) -> Poll<(), crate::Error> { fn mid_message_detect_eof(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
debug_assert!(!self.can_read_head() && !self.can_read_body()); debug_assert!(!self.can_read_head() && !self.can_read_body());
debug_assert!(self.is_mid_message()); debug_assert!(self.is_mid_message());
if self.state.allow_half_close || !self.io.read_buf().is_empty() { if self.state.allow_half_close || !self.io.read_buf().is_empty() {
return Ok(Async::NotReady); return Poll::Pending;
} }
let num_read = try_ready!(self.force_io_read().map_err(crate::Error::new_io)); let num_read = ready!(self.force_io_read(cx)).map_err(crate::Error::new_io)?;
if num_read == 0 { if num_read == 0 {
trace!("found unexpected EOF on busy connection: {:?}", self.state); trace!("found unexpected EOF on busy connection: {:?}", self.state);
self.state.close_read(); self.state.close_read();
Err(crate::Error::new_incomplete()) Poll::Ready(Err(crate::Error::new_incomplete()))
} else { } else {
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
} }
fn force_io_read(&mut self) -> Poll<usize, io::Error> { fn force_io_read(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<usize>> {
self.io.read_from_io().map_err(|e| { let result = ready!(self.io.poll_read_from_io(cx));
Poll::Ready(result.map_err(|e| {
trace!("force_io_read; io error = {:?}", e); trace!("force_io_read; io error = {:?}", e);
self.state.close(); self.state.close();
e e
}) }))
} }
fn maybe_notify(&mut self) { fn maybe_notify(&mut self, cx: &mut task::Context<'_>) {
// its possible that we returned NotReady from poll() without having // its possible that we returned NotReady from poll() without having
// exhausted the underlying Io. We would have done this when we // exhausted the underlying Io. We would have done this when we
// determined we couldn't keep reading until we knew how writing // determined we couldn't keep reading until we knew how writing
@@ -336,13 +339,13 @@ where I: AsyncRead + AsyncWrite,
if !self.io.is_read_blocked() { if !self.io.is_read_blocked() {
if self.io.read_buf().is_empty() { if self.io.read_buf().is_empty() {
match self.io.read_from_io() { match self.io.poll_read_from_io(cx) {
Ok(Async::Ready(_)) => (), Poll::Ready(Ok(_)) => (),
Ok(Async::NotReady) => { Poll::Pending => {
trace!("maybe_notify; read_from_io blocked"); trace!("maybe_notify; read_from_io blocked");
return return
}, },
Err(e) => { Poll::Ready(Err(e)) => {
trace!("maybe_notify; read_from_io error: {}", e); trace!("maybe_notify; read_from_io error: {}", e);
self.state.close(); self.state.close();
} }
@@ -352,9 +355,9 @@ where I: AsyncRead + AsyncWrite,
} }
} }
fn try_keep_alive(&mut self) { fn try_keep_alive(&mut self, cx: &mut task::Context<'_>) {
self.state.try_keep_alive::<T>(); self.state.try_keep_alive::<T>();
self.maybe_notify(); self.maybe_notify(cx);
} }
pub fn can_write_head(&self) -> bool { pub fn can_write_head(&self) -> bool {
@@ -586,23 +589,22 @@ where I: AsyncRead + AsyncWrite,
Err(err) Err(err)
} }
pub fn flush(&mut self) -> Poll<(), io::Error> { pub fn poll_flush(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
try_ready!(self.io.flush()); ready!(Pin::new(&mut self.io).poll_flush(cx))?;
self.try_keep_alive(); self.try_keep_alive(cx);
trace!("flushed({}): {:?}", T::LOG, self.state); trace!("flushed({}): {:?}", T::LOG, self.state);
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
pub fn shutdown(&mut self) -> Poll<(), io::Error> { pub fn poll_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
match self.io.io_mut().shutdown() { match ready!(Pin::new(self.io.io_mut()).poll_shutdown(cx)) {
Ok(Async::NotReady) => Ok(Async::NotReady), Ok(()) => {
Ok(Async::Ready(())) => {
trace!("shut down IO complete"); trace!("shut down IO complete");
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} },
Err(e) => { Err(e) => {
debug!("error shutting down IO: {}", e); debug!("error shutting down IO: {}", e);
Err(e) Poll::Ready(Err(e))
} }
} }
} }
@@ -652,6 +654,9 @@ impl<I, B: Buf, T> fmt::Debug for Conn<I, B, T> {
} }
} }
// B and T are never pinned
impl<I: Unpin, B, T> Unpin for Conn<I, B, T> {}
struct State { struct State {
allow_half_close: bool, allow_half_close: bool,
/// Re-usable HeaderMap to reduce allocating new ones. /// Re-usable HeaderMap to reduce allocating new ones.

View File

@@ -3,9 +3,10 @@ use std::fmt;
use std::usize; use std::usize;
use std::io; use std::io;
use futures::{Async, Poll};
use bytes::Bytes; use bytes::Bytes;
use crate::common::{Poll, task};
use super::io::MemRead; use super::io::MemRead;
use super::{DecodedLength}; use super::{DecodedLength};
@@ -93,50 +94,51 @@ impl Decoder {
} }
} }
pub fn decode<R: MemRead>(&mut self, body: &mut R) -> Poll<Bytes, io::Error> { pub fn decode<R: MemRead>(&mut self, cx: &mut task::Context<'_>, body: &mut R) -> Poll<Result<Bytes, io::Error>> {
trace!("decode; state={:?}", self.kind); trace!("decode; state={:?}", self.kind);
match self.kind { match self.kind {
Length(ref mut remaining) => { Length(ref mut remaining) => {
if *remaining == 0 { if *remaining == 0 {
Ok(Async::Ready(Bytes::new())) Poll::Ready(Ok(Bytes::new()))
} else { } else {
let to_read = *remaining as usize; let to_read = *remaining as usize;
let buf = try_ready!(body.read_mem(to_read)); let buf = ready!(body.read_mem(cx, to_read))?;
let num = buf.as_ref().len() as u64; let num = buf.as_ref().len() as u64;
if num > *remaining { if num > *remaining {
*remaining = 0; *remaining = 0;
} else if num == 0 { } else if num == 0 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)); return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)));
} else { } else {
*remaining -= num; *remaining -= num;
} }
Ok(Async::Ready(buf)) Poll::Ready(Ok(buf))
} }
} }
Chunked(ref mut state, ref mut size) => { Chunked(ref mut state, ref mut size) => {
loop { loop {
let mut buf = None; let mut buf = None;
// advances the chunked state // advances the chunked state
*state = try_ready!(state.step(body, size, &mut buf)); *state = ready!(state.step(cx, body, size, &mut buf))?;
if *state == ChunkedState::End { if *state == ChunkedState::End {
trace!("end of chunked"); trace!("end of chunked");
return Ok(Async::Ready(Bytes::new())); return Poll::Ready(Ok(Bytes::new()));
} }
if let Some(buf) = buf { if let Some(buf) = buf {
return Ok(Async::Ready(buf)); return Poll::Ready(Ok(buf));
} }
} }
} }
Eof(ref mut is_eof) => { Eof(ref mut is_eof) => {
if *is_eof { if *is_eof {
Ok(Async::Ready(Bytes::new())) Poll::Ready(Ok(Bytes::new()))
} else { } else {
// 8192 chosen because its about 2 packets, there probably // 8192 chosen because its about 2 packets, there probably
// won't be that much available, so don't have MemReaders // won't be that much available, so don't have MemReaders
// allocate buffers to big // allocate buffers to big
let slice = try_ready!(body.read_mem(8192)); body.read_mem(cx, 8192).map_ok(|slice| {
*is_eof = slice.is_empty(); *is_eof = slice.is_empty();
Ok(Async::Ready(slice)) slice
})
} }
} }
} }
@@ -151,41 +153,42 @@ impl fmt::Debug for Decoder {
} }
macro_rules! byte ( macro_rules! byte (
($rdr:ident) => ({ ($rdr:ident, $cx:expr) => ({
let buf = try_ready!($rdr.read_mem(1)); let buf = ready!($rdr.read_mem($cx, 1))?;
if !buf.is_empty() { if !buf.is_empty() {
buf[0] buf[0]
} else { } else {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof,
"Unexpected eof during chunk size line")); "unexpected EOF during chunk size line")));
} }
}) })
); );
impl ChunkedState { impl ChunkedState {
fn step<R: MemRead>(&self, fn step<R: MemRead>(&self,
cx: &mut task::Context<'_>,
body: &mut R, body: &mut R,
size: &mut u64, size: &mut u64,
buf: &mut Option<Bytes>) buf: &mut Option<Bytes>)
-> Poll<ChunkedState, io::Error> { -> Poll<Result<ChunkedState, io::Error>> {
use self::ChunkedState::*; use self::ChunkedState::*;
match *self { match *self {
Size => ChunkedState::read_size(body, size), Size => ChunkedState::read_size(cx, body, size),
SizeLws => ChunkedState::read_size_lws(body), SizeLws => ChunkedState::read_size_lws(cx, body),
Extension => ChunkedState::read_extension(body), Extension => ChunkedState::read_extension(cx, body),
SizeLf => ChunkedState::read_size_lf(body, *size), SizeLf => ChunkedState::read_size_lf(cx, body, *size),
Body => ChunkedState::read_body(body, size, buf), Body => ChunkedState::read_body(cx, body, size, buf),
BodyCr => ChunkedState::read_body_cr(body), BodyCr => ChunkedState::read_body_cr(cx, body),
BodyLf => ChunkedState::read_body_lf(body), BodyLf => ChunkedState::read_body_lf(cx, body),
EndCr => ChunkedState::read_end_cr(body), EndCr => ChunkedState::read_end_cr(cx, body),
EndLf => ChunkedState::read_end_lf(body), EndLf => ChunkedState::read_end_lf(cx, body),
End => Ok(Async::Ready(ChunkedState::End)), End => Poll::Ready(Ok(ChunkedState::End)),
} }
} }
fn read_size<R: MemRead>(rdr: &mut R, size: &mut u64) -> Poll<ChunkedState, io::Error> { fn read_size<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, size: &mut u64) -> Poll<Result<ChunkedState, io::Error>> {
trace!("Read chunk hex size"); trace!("Read chunk hex size");
let radix = 16; let radix = 16;
match byte!(rdr) { match byte!(rdr, cx) {
b @ b'0'..=b'9' => { b @ b'0'..=b'9' => {
*size *= radix; *size *= radix;
*size += (b - b'0') as u64; *size += (b - b'0') as u64;
@@ -198,55 +201,55 @@ impl ChunkedState {
*size *= radix; *size *= radix;
*size += (b + 10 - b'A') as u64; *size += (b + 10 - b'A') as u64;
} }
b'\t' | b' ' => return Ok(Async::Ready(ChunkedState::SizeLws)), b'\t' | b' ' => return Poll::Ready(Ok(ChunkedState::SizeLws)),
b';' => return Ok(Async::Ready(ChunkedState::Extension)), b';' => return Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => return Ok(Async::Ready(ChunkedState::SizeLf)), b'\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => { _ => {
return Err(io::Error::new(io::ErrorKind::InvalidInput, return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput,
"Invalid chunk size line: Invalid Size")); "Invalid chunk size line: Invalid Size")));
} }
} }
Ok(Async::Ready(ChunkedState::Size)) Poll::Ready(Ok(ChunkedState::Size))
} }
fn read_size_lws<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> { fn read_size_lws<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
trace!("read_size_lws"); trace!("read_size_lws");
match byte!(rdr) { match byte!(rdr, cx) {
// LWS can follow the chunk size, but no more digits can come // LWS can follow the chunk size, but no more digits can come
b'\t' | b' ' => Ok(Async::Ready(ChunkedState::SizeLws)), b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),
b';' => Ok(Async::Ready(ChunkedState::Extension)), b';' => Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)), b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => { _ => {
Err(io::Error::new(io::ErrorKind::InvalidInput, Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput,
"Invalid chunk size linear white space")) "Invalid chunk size linear white space")))
} }
} }
} }
fn read_extension<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> { fn read_extension<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
trace!("read_extension"); trace!("read_extension");
match byte!(rdr) { match byte!(rdr, cx) {
b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)), b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => Ok(Async::Ready(ChunkedState::Extension)), // no supported extensions _ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
} }
} }
fn read_size_lf<R: MemRead>(rdr: &mut R, size: u64) -> Poll<ChunkedState, io::Error> { fn read_size_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, size: u64) -> Poll<Result<ChunkedState, io::Error>> {
trace!("Chunk size is {:?}", size); trace!("Chunk size is {:?}", size);
match byte!(rdr) { match byte!(rdr, cx) {
b'\n' => { b'\n' => {
if size == 0 { if size == 0 {
Ok(Async::Ready(ChunkedState::EndCr)) Poll::Ready(Ok(ChunkedState::EndCr))
} else { } else {
debug!("incoming chunked header: {0:#X} ({0} bytes)", size); debug!("incoming chunked header: {0:#X} ({0} bytes)", size);
Ok(Async::Ready(ChunkedState::Body)) Poll::Ready(Ok(ChunkedState::Body))
} }
}, },
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size LF")), _ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size LF"))),
} }
} }
fn read_body<R: MemRead>(rdr: &mut R, fn read_body<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R,
rem: &mut u64, rem: &mut u64,
buf: &mut Option<Bytes>) buf: &mut Option<Bytes>)
-> Poll<ChunkedState, io::Error> { -> Poll<Result<ChunkedState, io::Error>> {
trace!("Chunked read, remaining={:?}", rem); trace!("Chunked read, remaining={:?}", rem);
// cap remaining bytes at the max capacity of usize // cap remaining bytes at the max capacity of usize
@@ -256,45 +259,45 @@ impl ChunkedState {
}; };
let to_read = rem_cap; let to_read = rem_cap;
let slice = try_ready!(rdr.read_mem(to_read)); let slice = ready!(rdr.read_mem(cx, to_read))?;
let count = slice.len(); let count = slice.len();
if count == 0 { if count == 0 {
*rem = 0; *rem = 0;
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)); return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)));
} }
*buf = Some(slice); *buf = Some(slice);
*rem -= count as u64; *rem -= count as u64;
if *rem > 0 { if *rem > 0 {
Ok(Async::Ready(ChunkedState::Body)) Poll::Ready(Ok(ChunkedState::Body))
} else { } else {
Ok(Async::Ready(ChunkedState::BodyCr)) Poll::Ready(Ok(ChunkedState::BodyCr))
} }
} }
fn read_body_cr<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> { fn read_body_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) { match byte!(rdr, cx) {
b'\r' => Ok(Async::Ready(ChunkedState::BodyLf)), b'\r' => Poll::Ready(Ok(ChunkedState::BodyLf)),
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR")), _ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR"))),
} }
} }
fn read_body_lf<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> { fn read_body_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) { match byte!(rdr, cx) {
b'\n' => Ok(Async::Ready(ChunkedState::Size)), b'\n' => Poll::Ready(Ok(ChunkedState::Size)),
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF")), _ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF"))),
} }
} }
fn read_end_cr<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> { fn read_end_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) { match byte!(rdr, cx) {
b'\r' => Ok(Async::Ready(ChunkedState::EndLf)), b'\r' => Poll::Ready(Ok(ChunkedState::EndLf)),
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR")), _ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR"))),
} }
} }
fn read_end_lf<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> { fn read_end_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) { match byte!(rdr, cx) {
b'\n' => Ok(Async::Ready(ChunkedState::End)), b'\n' => Poll::Ready(Ok(ChunkedState::End)),
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF")), _ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF"))),
} }
} }
} }
@@ -326,15 +329,15 @@ mod tests {
use crate::mock::AsyncIo; use crate::mock::AsyncIo;
impl<'a> MemRead for &'a [u8] { impl<'a> MemRead for &'a [u8] {
fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error> { fn read_mem(&mut self, len: usize) -> Poll<Result<Bytes, io::Error>> {
let n = ::std::cmp::min(len, self.len()); let n = ::std::cmp::min(len, self.len());
if n > 0 { if n > 0 {
let (a, b) = self.split_at(n); let (a, b) = self.split_at(n);
let mut buf = BytesMut::from(a); let mut buf = BytesMut::from(a);
*self = b; *self = b;
Ok(Async::Ready(buf.split_to(n).freeze())) Poll::Ready(Ok(buf.split_to(n).freeze()))
} else { } else {
Ok(Async::Ready(Bytes::new())) Poll::Ready(Ok(Bytes::new()))
} }
} }
} }

View File

@@ -1,13 +1,12 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use futures::{Async, Future, Poll, Stream};
use http::{Request, Response, StatusCode}; use http::{Request, Response, StatusCode};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::body::internal::FullDataArg; use crate::body::internal::FullDataArg;
use crate::common::{Never, YieldNow}; use crate::common::{Future, Never, Poll, Pin, Unpin, task};
use crate::proto::{BodyLength, DecodedLength, Conn, Dispatched, MessageHead, RequestHead, RequestLine, ResponseHead}; use crate::proto::{BodyLength, DecodedLength, Conn, Dispatched, MessageHead, RequestHead, RequestLine, ResponseHead};
use super::Http1Transaction; use super::Http1Transaction;
use crate::service::Service; use crate::service::Service;
@@ -16,12 +15,8 @@ pub(crate) struct Dispatcher<D, Bs: Payload, I, T> {
conn: Conn<I, Bs::Data, T>, conn: Conn<I, Bs::Data, T>,
dispatch: D, dispatch: D,
body_tx: Option<crate::body::Sender>, body_tx: Option<crate::body::Sender>,
body_rx: Option<Bs>, body_rx: Pin<Box<Option<Bs>>>,
is_closing: bool, is_closing: bool,
/// If the poll loop reaches its max spin count, it will yield by notifying
/// the task immediately. This will cache that `Task`, since it usually is
/// the same one.
yield_now: YieldNow,
} }
pub(crate) trait Dispatch { pub(crate) trait Dispatch {
@@ -29,14 +24,14 @@ pub(crate) trait Dispatch {
type PollBody; type PollBody;
type PollError; type PollError;
type RecvItem; type RecvItem;
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Self::PollBody)>, Self::PollError>; fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>>;
fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()>; fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()>;
fn poll_ready(&mut self) -> Poll<(), ()>; fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>>;
fn should_poll(&self) -> bool; fn should_poll(&self) -> bool;
} }
pub struct Server<S: Service> { pub struct Server<S: Service> {
in_flight: Option<S::Future>, in_flight: Pin<Box<Option<S::Future>>>,
pub(crate) service: S, pub(crate) service: S,
} }
@@ -49,10 +44,10 @@ type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>
impl<D, Bs, I, T> Dispatcher<D, Bs, I, T> impl<D, Bs, I, T> Dispatcher<D, Bs, I, T>
where where
D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>>, D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>, D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
T: Http1Transaction, T: Http1Transaction + Unpin,
Bs: Payload, Bs: Payload,
{ {
pub fn new(dispatch: D, conn: Conn<I, Bs::Data, T>) -> Self { pub fn new(dispatch: D, conn: Conn<I, Bs::Data, T>) -> Self {
@@ -60,9 +55,8 @@ where
conn: conn, conn: conn,
dispatch: dispatch, dispatch: dispatch,
body_tx: None, body_tx: None,
body_rx: None, body_rx: Box::pin(None),
is_closing: false, is_closing: false,
yield_now: YieldNow::new(),
} }
} }
@@ -80,55 +74,74 @@ where
/// ///
/// This is useful for old-style HTTP upgrades, but ignores /// This is useful for old-style HTTP upgrades, but ignores
/// newer-style upgrade API. /// newer-style upgrade API.
pub fn poll_without_shutdown(&mut self) -> Poll<(), crate::Error> { pub(crate) fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>>
self.poll_catch(false) where
.map(|x| { Self: Unpin,
x.map(|ds| if let Dispatched::Upgrade(pending) = ds { {
pending.manual(); Pin::new(self).poll_catch(cx, false).map_ok(|ds| {
}) if let Dispatched::Upgrade(pending) = ds {
}) pending.manual();
}
})
} }
fn poll_catch(&mut self, should_shutdown: bool) -> Poll<Dispatched, crate::Error> { fn poll_catch(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> {
self.poll_inner(should_shutdown).or_else(|e| { Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| {
// An error means we're shutting down either way. // An error means we're shutting down either way.
// We just try to give the error to the user, // We just try to give the error to the user,
// and close the connection with an Ok. If we // and close the connection with an Ok. If we
// cannot give it to the user, then return the Err. // cannot give it to the user, then return the Err.
self.dispatch.recv_msg(Err(e))?; self.dispatch.recv_msg(Err(e))?;
Ok(Async::Ready(Dispatched::Shutdown)) Ok(Dispatched::Shutdown)
}) }))
} }
fn poll_inner(&mut self, should_shutdown: bool) -> Poll<Dispatched, crate::Error> { fn poll_inner(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> {
T::update_date(); T::update_date();
try_ready!(self.poll_loop()); ready!(self.poll_loop(cx))?;
loop {
self.poll_read(cx)?;
self.poll_write(cx)?;
self.poll_flush(cx)?;
// This could happen if reading paused before blocking on IO,
// such as getting to the end of a framed message, but then
// writing/flushing set the state back to Init. In that case,
// if the read buffer still had bytes, we'd want to try poll_read
// again, or else we wouldn't ever be woken up again.
//
// Using this instead of task::current() and notify() inside
// the Conn is noticeably faster in pipelined benchmarks.
if !self.conn.wants_read_again() {
break;
}
}
if self.is_done() { if self.is_done() {
if let Some(pending) = self.conn.pending_upgrade() { if let Some(pending) = self.conn.pending_upgrade() {
self.conn.take_error()?; self.conn.take_error()?;
return Ok(Async::Ready(Dispatched::Upgrade(pending))); return Poll::Ready(Ok(Dispatched::Upgrade(pending)));
} else if should_shutdown { } else if should_shutdown {
try_ready!(self.conn.shutdown().map_err(crate::Error::new_shutdown)); ready!(self.conn.poll_shutdown(cx)).map_err(crate::Error::new_shutdown)?;
} }
self.conn.take_error()?; self.conn.take_error()?;
Ok(Async::Ready(Dispatched::Shutdown)) Poll::Ready(Ok(Dispatched::Shutdown))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
fn poll_loop(&mut self) -> Poll<(), crate::Error> { fn poll_loop(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
// Limit the looping on this connection, in case it is ready far too // Limit the looping on this connection, in case it is ready far too
// often, so that other futures don't starve. // often, so that other futures don't starve.
// //
// 16 was chosen arbitrarily, as that is number of pipelined requests // 16 was chosen arbitrarily, as that is number of pipelined requests
// benchmarks often use. Perhaps it should be a config option instead. // benchmarks often use. Perhaps it should be a config option instead.
for _ in 0..16 { for _ in 0..16 {
self.poll_read()?; self.poll_read(cx)?;
self.poll_write()?; self.poll_write(cx)?;
self.poll_flush()?; self.poll_flush(cx)?;
// This could happen if reading paused before blocking on IO, // This could happen if reading paused before blocking on IO,
// such as getting to the end of a framed message, but then // such as getting to the end of a framed message, but then
@@ -140,45 +153,39 @@ where
// the Conn is noticeably faster in pipelined benchmarks. // the Conn is noticeably faster in pipelined benchmarks.
if !self.conn.wants_read_again() { if !self.conn.wants_read_again() {
//break; //break;
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} }
} }
trace!("poll_loop yielding (self = {:p})", self); trace!("poll_loop yielding (self = {:p})", self);
match self.yield_now.poll_yield() { task::yield_now(cx).map(|never| match never {})
Ok(Async::NotReady) => Ok(Async::NotReady),
// maybe with `!` this can be cleaner...
// but for now, just doing this to eliminate branches
Ok(Async::Ready(never)) |
Err(never) => match never {}
}
} }
fn poll_read(&mut self) -> Poll<(), crate::Error> { fn poll_read(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
loop { loop {
if self.is_closing { if self.is_closing {
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} else if self.conn.can_read_head() { } else if self.conn.can_read_head() {
try_ready!(self.poll_read_head()); ready!(self.poll_read_head(cx))?;
} else if let Some(mut body) = self.body_tx.take() { } else if let Some(mut body) = self.body_tx.take() {
if self.conn.can_read_body() { if self.conn.can_read_body() {
match body.poll_ready() { match body.poll_ready(cx) {
Ok(Async::Ready(())) => (), Poll::Ready(Ok(())) => (),
Ok(Async::NotReady) => { Poll::Pending => {
self.body_tx = Some(body); self.body_tx = Some(body);
return Ok(Async::NotReady); return Poll::Pending;
}, },
Err(_canceled) => { Poll::Ready(Err(_canceled)) => {
// user doesn't care about the body // user doesn't care about the body
// so we should stop reading // so we should stop reading
trace!("body receiver dropped before eof, closing"); trace!("body receiver dropped before eof, closing");
self.conn.close_read(); self.conn.close_read();
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} }
} }
match self.conn.read_body() { match self.conn.poll_read_body(cx) {
Ok(Async::Ready(Some(chunk))) => { Poll::Ready(Some(Ok(chunk))) => {
match body.send_data(chunk) { match body.send_data(chunk) {
Ok(()) => { Ok(()) => {
self.body_tx = Some(body); self.body_tx = Some(body);
@@ -191,14 +198,14 @@ where
} }
} }
}, },
Ok(Async::Ready(None)) => { Poll::Ready(None) => {
// just drop, the body will close automatically // just drop, the body will close automatically
}, },
Ok(Async::NotReady) => { Poll::Pending => {
self.body_tx = Some(body); self.body_tx = Some(body);
return Ok(Async::NotReady); return Poll::Pending;
} }
Err(e) => { Poll::Ready(Some(Err(e))) => {
body.send_error(crate::Error::new_body(e)); body.send_error(crate::Error::new_body(e));
} }
} }
@@ -206,25 +213,24 @@ where
// just drop, the body will close automatically // just drop, the body will close automatically
} }
} else { } else {
return self.conn.read_keep_alive(); return self.conn.poll_read_keep_alive(cx);
} }
} }
} }
fn poll_read_head(&mut self) -> Poll<(), crate::Error> { fn poll_read_head(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
// can dispatch receive, or does it still care about, an incoming message? // can dispatch receive, or does it still care about, an incoming message?
match self.dispatch.poll_ready() { match ready!(self.dispatch.poll_ready(cx)) {
Ok(Async::Ready(())) => (), Ok(()) => (),
Ok(Async::NotReady) => return Ok(Async::NotReady), // service might not be ready
Err(()) => { Err(()) => {
trace!("dispatch no longer receiving messages"); trace!("dispatch no longer receiving messages");
self.close(); self.close();
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} }
} }
// dispatch is ready for a message, try to read one // dispatch is ready for a message, try to read one
match self.conn.read_head() { match ready!(self.conn.poll_read_head(cx)) {
Ok(Async::Ready(Some((head, body_len, wants_upgrade)))) => { Some(Ok((head, body_len, wants_upgrade))) => {
let mut body = match body_len { let mut body = match body_len {
DecodedLength::ZERO => Body::empty(), DecodedLength::ZERO => Body::empty(),
other => { other => {
@@ -237,67 +243,78 @@ where
body.set_on_upgrade(self.conn.on_upgrade()); body.set_on_upgrade(self.conn.on_upgrade());
} }
self.dispatch.recv_msg(Ok((head, body)))?; self.dispatch.recv_msg(Ok((head, body)))?;
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} },
Ok(Async::Ready(None)) => { Some(Err(err)) => {
// read eof, conn will start to shutdown automatically
Ok(Async::Ready(()))
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => {
debug!("read_head error: {}", err); debug!("read_head error: {}", err);
self.dispatch.recv_msg(Err(err))?; self.dispatch.recv_msg(Err(err))?;
// if here, the dispatcher gave the user the error // if here, the dispatcher gave the user the error
// somewhere else. we still need to shutdown, but // somewhere else. we still need to shutdown, but
// not as a second error. // not as a second error.
Ok(Async::Ready(())) Poll::Ready(Ok(()))
},
None => {
// read eof, conn will start to shutdown automatically
Poll::Ready(Ok(()))
} }
} }
} }
fn poll_write(&mut self) -> Poll<(), crate::Error> { fn poll_write(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
loop { loop {
if self.is_closing { if self.is_closing {
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() { } else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() {
if let Some((head, mut body)) = try_ready!(self.dispatch.poll_msg().map_err(crate::Error::new_user_service)) { if let Some(msg) = ready!(self.dispatch.poll_msg(cx)) {
let (head, mut body) = msg.map_err(crate::Error::new_user_service)?;
// Check if the body knows its full data immediately. // Check if the body knows its full data immediately.
// //
// If so, we can skip a bit of bookkeeping that streaming // If so, we can skip a bit of bookkeeping that streaming
// bodies need to do. // bodies need to do.
if let Some(full) = body.__hyper_full_data(FullDataArg(())).0 { if let Some(full) = body.__hyper_full_data(FullDataArg(())).0 {
self.conn.write_full_msg(head, full); self.conn.write_full_msg(head, full);
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} }
let body_type = if body.is_end_stream() { let body_type = if body.is_end_stream() {
self.body_rx = None; self.body_rx.set(None);
None None
} else { } else {
let btype = body.content_length() let btype = body.content_length()
.map(BodyLength::Known) .map(BodyLength::Known)
.or_else(|| Some(BodyLength::Unknown)); .or_else(|| Some(BodyLength::Unknown));
self.body_rx = Some(body); self.body_rx.set(Some(body));
btype btype
}; };
self.conn.write_head(head, body_type); self.conn.write_head(head, body_type);
} else { } else {
self.close(); self.close();
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
} }
} else if !self.conn.can_buffer_body() { } else if !self.conn.can_buffer_body() {
try_ready!(self.poll_flush()); ready!(self.poll_flush(cx))?;
} else if let Some(mut body) = self.body_rx.take() { } else {
if !self.conn.can_write_body() { // A new scope is needed :(
trace!( if let (Some(mut body), clear_body) = OptGuard::new(self.body_rx.as_mut()).guard_mut() {
"no more write body allowed, user body is_end_stream = {}", debug_assert!(!*clear_body, "opt guard defaults to keeping body");
body.is_end_stream(), if !self.conn.can_write_body() {
); trace!(
continue; "no more write body allowed, user body is_end_stream = {}",
} body.is_end_stream(),
match body.poll_data().map_err(crate::Error::new_user_body)? { );
Async::Ready(Some(chunk)) => { *clear_body = true;
continue;
}
let item = ready!(body.as_mut().poll_data(cx));
if let Some(item) = item {
let chunk = item.map_err(|e| {
*clear_body = true;
crate::Error::new_user_body(e)
})?;
let eos = body.is_end_stream(); let eos = body.is_end_stream();
if eos { if eos {
*clear_body = true;
if chunk.remaining() == 0 { if chunk.remaining() == 0 {
trace!("discarding empty chunk"); trace!("discarding empty chunk");
self.conn.end_body(); self.conn.end_body();
@@ -305,30 +322,25 @@ where
self.conn.write_body_and_end(chunk); self.conn.write_body_and_end(chunk);
} }
} else { } else {
self.body_rx = Some(body);
if chunk.remaining() == 0 { if chunk.remaining() == 0 {
trace!("discarding empty chunk"); trace!("discarding empty chunk");
continue; continue;
} }
self.conn.write_body(chunk); self.conn.write_body(chunk);
} }
}, } else {
Async::Ready(None) => { *clear_body = true;
self.conn.end_body(); self.conn.end_body();
},
Async::NotReady => {
self.body_rx = Some(body);
return Ok(Async::NotReady);
} }
} else {
return Poll::Pending;
} }
} else {
return Ok(Async::NotReady);
} }
} }
} }
fn poll_flush(&mut self) -> Poll<(), crate::Error> { fn poll_flush(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
self.conn.flush().map_err(|err| { self.conn.poll_flush(cx).map_err(|err| {
debug!("error writing: {}", err); debug!("error writing: {}", err);
crate::Error::new_body_write(err) crate::Error::new_body_write(err)
}) })
@@ -360,35 +372,65 @@ where
impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T> impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T>
where where
D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>>, D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>, D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
T: Http1Transaction, T: Http1Transaction + Unpin,
Bs: Payload, Bs: Payload,
{ {
type Item = Dispatched; type Output = crate::Result<Dispatched>;
type Error = crate::Error;
#[inline] #[inline]
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
self.poll_catch(true) self.poll_catch(cx, true)
}
}
// ===== impl OptGuard =====
/// A drop guard to allow a mutable borrow of an Option while being able to
/// set whether the `Option` should be cleared on drop.
struct OptGuard<'a, T>(Pin<&'a mut Option<T>>, bool);
impl<'a, T> OptGuard<'a, T> {
fn new(pin: Pin<&'a mut Option<T>>) -> Self {
OptGuard(pin, false)
}
fn guard_mut(&mut self) -> (Option<Pin<&mut T>>, &mut bool) {
(self.0.as_mut().as_pin_mut(), &mut self.1)
}
}
impl<'a, T> Drop for OptGuard<'a, T> {
fn drop(&mut self) {
if self.1 {
self.0.set(None);
}
} }
} }
// ===== impl Server ===== // ===== impl Server =====
impl<S> Server<S> where S: Service { impl<S> Server<S>
where
S: Service,
{
pub fn new(service: S) -> Server<S> { pub fn new(service: S) -> Server<S> {
Server { Server {
in_flight: None, in_flight: Box::pin(None),
service: service, service: service,
} }
} }
pub fn into_service(self) -> S { pub fn into_service(self) -> S {
self.service self.service
} }
} }
// Service is never pinned
impl<S: Service> Unpin for Server<S> {}
impl<S, Bs> Dispatch for Server<S> impl<S, Bs> Dispatch for Server<S>
where where
S: Service<ReqBody=Body, ResBody=Bs>, S: Service<ReqBody=Body, ResBody=Bs>,
@@ -400,25 +442,23 @@ where
type PollError = S::Error; type PollError = S::Error;
type RecvItem = RequestHead; type RecvItem = RequestHead;
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Self::PollBody)>, Self::PollError> { fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> {
if let Some(mut fut) = self.in_flight.take() { let ret = if let Some(ref mut fut) = self.in_flight.as_mut().as_pin_mut() {
let resp = match fut.poll()? { let resp = ready!(fut.as_mut().poll(cx)?);
Async::Ready(res) => res,
Async::NotReady => {
self.in_flight = Some(fut);
return Ok(Async::NotReady);
}
};
let (parts, body) = resp.into_parts(); let (parts, body) = resp.into_parts();
let head = MessageHead { let head = MessageHead {
version: parts.version, version: parts.version,
subject: parts.status, subject: parts.status,
headers: parts.headers, headers: parts.headers,
}; };
Ok(Async::Ready(Some((head, body)))) Poll::Ready(Some(Ok((head, body))))
} else { } else {
unreachable!("poll_msg shouldn't be called if no inflight"); unreachable!("poll_msg shouldn't be called if no inflight");
} };
// Since in_flight finished, remove it
self.in_flight.set(None);
ret
} }
fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()> { fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()> {
@@ -428,15 +468,16 @@ where
*req.uri_mut() = msg.subject.1; *req.uri_mut() = msg.subject.1;
*req.headers_mut() = msg.headers; *req.headers_mut() = msg.headers;
*req.version_mut() = msg.version; *req.version_mut() = msg.version;
self.in_flight = Some(self.service.call(req)); let fut = self.service.call(req);
self.in_flight.set(Some(fut));
Ok(()) Ok(())
} }
fn poll_ready(&mut self) -> Poll<(), ()> { fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> {
if self.in_flight.is_some() { if self.in_flight.is_some() {
Ok(Async::NotReady) Poll::Pending
} else { } else {
self.service.poll_ready() self.service.poll_ready(cx)
.map_err(|_e| { .map_err(|_e| {
// FIXME: return error value. // FIXME: return error value.
trace!("service closed"); trace!("service closed");
@@ -470,16 +511,16 @@ where
type PollError = Never; type PollError = Never;
type RecvItem = ResponseHead; type RecvItem = ResponseHead;
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Self::PollBody)>, Never> { fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> {
match self.rx.poll() { match self.rx.poll_next(cx) {
Ok(Async::Ready(Some((req, mut cb)))) => { Poll::Ready(Some((req, mut cb))) => {
// check that future hasn't been canceled already // check that future hasn't been canceled already
match cb.poll_cancel().expect("poll_cancel cannot error") { match cb.poll_cancel(cx) {
Async::Ready(()) => { Poll::Ready(()) => {
trace!("request canceled"); trace!("request canceled");
Ok(Async::Ready(None)) Poll::Ready(None)
}, },
Async::NotReady => { Poll::Pending => {
let (parts, body) = req.into_parts(); let (parts, body) = req.into_parts();
let head = RequestHead { let head = RequestHead {
version: parts.version, version: parts.version,
@@ -487,17 +528,16 @@ where
headers: parts.headers, headers: parts.headers,
}; };
self.callback = Some(cb); self.callback = Some(cb);
Ok(Async::Ready(Some((head, body)))) Poll::Ready(Some(Ok((head, body))))
} }
} }
}, },
Ok(Async::Ready(None)) => { Poll::Ready(None) => {
trace!("client tx closed"); trace!("client tx closed");
// user has dropped sender handle // user has dropped sender handle
Ok(Async::Ready(None)) Poll::Ready(None)
}, },
Ok(Async::NotReady) => Ok(Async::NotReady), Poll::Pending => Poll::Pending,
Err(never) => match never {},
} }
} }
@@ -522,30 +562,32 @@ where
if let Some(cb) = self.callback.take() { if let Some(cb) = self.callback.take() {
let _ = cb.send(Err((err, None))); let _ = cb.send(Err((err, None)));
Ok(()) Ok(())
} else if let Ok(Async::Ready(Some((req, cb)))) = self.rx.poll() {
trace!("canceling queued request with connection error: {}", err);
// in this case, the message was never even started, so it's safe to tell
// the user that the request was completely canceled
let _ = cb.send(Err((crate::Error::new_canceled().with(err), Some(req))));
Ok(())
} else { } else {
Err(err) self.rx.close();
if let Some((req, cb)) = self.rx.try_recv() {
trace!("canceling queued request with connection error: {}", err);
// in this case, the message was never even started, so it's safe to tell
// the user that the request was completely canceled
let _ = cb.send(Err((crate::Error::new_canceled().with(err), Some(req))));
Ok(())
} else {
Err(err)
}
} }
} }
} }
} }
fn poll_ready(&mut self) -> Poll<(), ()> { fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> {
match self.callback { match self.callback {
Some(ref mut cb) => match cb.poll_cancel() { Some(ref mut cb) => match cb.poll_cancel(cx) {
Ok(Async::Ready(())) => { Poll::Ready(()) => {
trace!("callback receiver has dropped"); trace!("callback receiver has dropped");
Err(()) Poll::Ready(Err(()))
}, },
Ok(Async::NotReady) => Ok(Async::Ready(())), Poll::Pending => Poll::Ready(Ok(())),
Err(_) => unreachable!("oneshot poll_cancel cannot error"),
}, },
None => Err(()), None => Poll::Ready(Err(())),
} }
} }

View File

@@ -5,10 +5,10 @@ use std::fmt;
use std::io; use std::io;
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures::{Async, Poll};
use iovec::IoVec; use iovec::IoVec;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, Unpin, task};
use super::{Http1Transaction, ParseContext, ParsedMessage}; use super::{Http1Transaction, ParseContext, ParsedMessage};
/// The initial buffer size allocated before trying to read from IO. /// The initial buffer size allocated before trying to read from IO.
@@ -52,7 +52,7 @@ where
impl<T, B> Buffered<T, B> impl<T, B> Buffered<T, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite + Unpin,
B: Buf, B: Buf,
{ {
pub fn new(io: T) -> Buffered<T, B> { pub fn new(io: T) -> Buffered<T, B> {
@@ -135,57 +135,56 @@ where
} }
} }
pub(super) fn parse<S>(&mut self, ctx: ParseContext) pub(super) fn parse<S>(&mut self, cx: &mut task::Context<'_>, parse_ctx: ParseContext)
-> Poll<ParsedMessage<S::Incoming>, crate::Error> -> Poll<crate::Result<ParsedMessage<S::Incoming>>>
where where
S: Http1Transaction, S: Http1Transaction,
{ {
loop { loop {
match S::parse(&mut self.read_buf, ParseContext { match S::parse(&mut self.read_buf, ParseContext {
cached_headers: ctx.cached_headers, cached_headers: parse_ctx.cached_headers,
req_method: ctx.req_method, req_method: parse_ctx.req_method,
})? { })? {
Some(msg) => { Some(msg) => {
debug!("parsed {} headers", msg.head.headers.len()); debug!("parsed {} headers", msg.head.headers.len());
return Ok(Async::Ready(msg)) return Poll::Ready(Ok(msg));
}, },
None => { None => {
let max = self.read_buf_strategy.max(); let max = self.read_buf_strategy.max();
if self.read_buf.len() >= max { if self.read_buf.len() >= max {
debug!("max_buf_size ({}) reached, closing", max); debug!("max_buf_size ({}) reached, closing", max);
return Err(crate::Error::new_too_large()); return Poll::Ready(Err(crate::Error::new_too_large()));
} }
}, },
} }
match try_ready!(self.read_from_io().map_err(crate::Error::new_io)) { match ready!(self.poll_read_from_io(cx)).map_err(crate::Error::new_io)? {
0 => { 0 => {
trace!("parse eof"); trace!("parse eof");
return Err(crate::Error::new_incomplete()); return Poll::Ready(Err(crate::Error::new_incomplete()));
} }
_ => {}, _ => {},
} }
} }
} }
pub fn read_from_io(&mut self) -> Poll<usize, io::Error> { pub fn poll_read_from_io(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<usize>> {
self.read_blocked = false; self.read_blocked = false;
let next = self.read_buf_strategy.next(); let next = self.read_buf_strategy.next();
if self.read_buf.remaining_mut() < next { if self.read_buf.remaining_mut() < next {
self.read_buf.reserve(next); self.read_buf.reserve(next);
} }
self.io.read_buf(&mut self.read_buf).map(|ok| { match Pin::new(&mut self.io).poll_read_buf(cx, &mut self.read_buf) {
match ok { Poll::Ready(Ok(n)) => {
Async::Ready(n) => {
debug!("read {} bytes", n); debug!("read {} bytes", n);
self.read_buf_strategy.record(n); self.read_buf_strategy.record(n);
Async::Ready(n) Poll::Ready(Ok(n))
}, },
Async::NotReady => { Poll::Pending => {
self.read_blocked = true; self.read_blocked = true;
Async::NotReady Poll::Pending
}
} }
}) Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
}
} }
pub fn into_inner(self) -> (T, Bytes) { pub fn into_inner(self) -> (T, Bytes) {
@@ -200,38 +199,37 @@ where
self.read_blocked self.read_blocked
} }
pub fn flush(&mut self) -> Poll<(), io::Error> { pub fn poll_flush(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
if self.flush_pipeline && !self.read_buf.is_empty() { if self.flush_pipeline && !self.read_buf.is_empty() {
//Ok(()) Poll::Ready(Ok(()))
} else if self.write_buf.remaining() == 0 { } else if self.write_buf.remaining() == 0 {
try_nb!(self.io.flush()); Pin::new(&mut self.io).poll_flush(cx)
} else { } else {
match self.write_buf.strategy { match self.write_buf.strategy {
WriteStrategy::Flatten => return self.flush_flattened(), WriteStrategy::Flatten => return self.poll_flush_flattened(cx),
_ => (), _ => (),
} }
loop { loop {
let n = try_ready!(self.io.write_buf(&mut self.write_buf.auto())); let n = ready!(Pin::new(&mut self.io).poll_write_buf(cx, &mut self.write_buf.auto()))?;
debug!("flushed {} bytes", n); debug!("flushed {} bytes", n);
if self.write_buf.remaining() == 0 { if self.write_buf.remaining() == 0 {
break; break;
} else if n == 0 { } else if n == 0 {
trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining()); trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining());
return Err(io::ErrorKind::WriteZero.into()) return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
} }
} }
try_nb!(self.io.flush()) Pin::new(&mut self.io).poll_flush(cx)
} }
Ok(Async::Ready(()))
} }
/// Specialized version of `flush` when strategy is Flatten. /// Specialized version of `flush` when strategy is Flatten.
/// ///
/// Since all buffered bytes are flattened into the single headers buffer, /// Since all buffered bytes are flattened into the single headers buffer,
/// that skips some bookkeeping around using multiple buffers. /// that skips some bookkeeping around using multiple buffers.
fn flush_flattened(&mut self) -> Poll<(), io::Error> { fn poll_flush_flattened(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
loop { loop {
let n = try_nb!(self.io.write(self.write_buf.headers.bytes())); let n = ready!(Pin::new(&mut self.io).poll_write(cx, self.write_buf.headers.bytes()))?;
debug!("flushed {} bytes", n); debug!("flushed {} bytes", n);
self.write_buf.headers.advance(n); self.write_buf.headers.advance(n);
if self.write_buf.headers.remaining() == 0 { if self.write_buf.headers.remaining() == 0 {
@@ -239,30 +237,33 @@ where
break; break;
} else if n == 0 { } else if n == 0 {
trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining()); trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining());
return Err(io::ErrorKind::WriteZero.into()) return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
} }
} }
try_nb!(self.io.flush()); Pin::new(&mut self.io).poll_flush(cx)
Ok(Async::Ready(()))
} }
} }
// The `B` is a `Buf`, we never project a pin to it
impl<T: Unpin, B> Unpin for Buffered<T, B> {}
// TODO: This trait is old... at least rename to PollBytes or something...
pub trait MemRead { pub trait MemRead {
fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error>; fn read_mem(&mut self, cx: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>>;
} }
impl<T, B> MemRead for Buffered<T, B> impl<T, B> MemRead for Buffered<T, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite + Unpin,
B: Buf, B: Buf,
{ {
fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error> { fn read_mem(&mut self, cx: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {
if !self.read_buf.is_empty() { if !self.read_buf.is_empty() {
let n = ::std::cmp::min(len, self.read_buf.len()); let n = ::std::cmp::min(len, self.read_buf.len());
Ok(Async::Ready(self.read_buf.split_to(n).freeze())) Poll::Ready(Ok(self.read_buf.split_to(n).freeze()))
} else { } else {
let n = try_ready!(self.read_from_io()); let n = ready!(self.poll_read_from_io(cx))?;
Ok(Async::Ready(self.read_buf.split_to(::std::cmp::min(len, n)).freeze())) Poll::Ready(Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze()))
} }
} }
} }

View File

@@ -1,26 +1,26 @@
use bytes::IntoBuf; use bytes::IntoBuf;
use futures::{Async, Future, Poll, Stream}; //use futures::{Async, Future, Poll, Stream};
use futures::future::{self, Either}; //use futures::future::{self, Either};
use futures::sync::{mpsc, oneshot}; //use futures::sync::{mpsc, oneshot};
use h2::client::{Builder, Handshake, SendRequest}; use h2::client::{Builder, Handshake, SendRequest};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::headers::content_length_parse_all; use crate::headers::content_length_parse_all;
use crate::body::Payload; use crate::body::Payload;
use crate::common::{Exec, Never}; use crate::common::{Exec, Future, Never, Pin, Poll, task};
use crate::headers; use crate::headers;
use crate::proto::Dispatched; use crate::proto::Dispatched;
use super::{PipeToSendStream, SendBuf}; use super::{PipeToSendStream, SendBuf};
use crate::{Body, Request, Response}; use crate::{Body, Request, Response};
type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>; type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>;
/// An mpsc channel is used to help notify the `Connection` task when *all* ///// An mpsc channel is used to help notify the `Connection` task when *all*
/// other handles to it have been dropped, so that it can shutdown. ///// other handles to it have been dropped, so that it can shutdown.
type ConnDropRef = mpsc::Sender<Never>; //type ConnDropRef = mpsc::Sender<Never>;
/// A oneshot channel watches the `Connection` task, and when it completes, ///// A oneshot channel watches the `Connection` task, and when it completes,
/// the "dispatch" task will be notified and can shutdown sooner. ///// the "dispatch" task will be notified and can shutdown sooner.
type ConnEof = oneshot::Receiver<Never>; //type ConnEof = oneshot::Receiver<Never>;
pub(crate) struct Client<T, B> pub(crate) struct Client<T, B>
where where
@@ -33,7 +33,7 @@ where
enum State<T, B> where B: IntoBuf { enum State<T, B> where B: IntoBuf {
Handshaking(Handshake<T, B>), Handshaking(Handshake<T, B>),
Ready(SendRequest<B>, ConnDropRef, ConnEof), //Ready(SendRequest<B>, ConnDropRef, ConnEof),
} }
impl<T, B> Client<T, B> impl<T, B> Client<T, B>
@@ -42,6 +42,8 @@ where
B: Payload, B: Payload,
{ {
pub(crate) fn new(io: T, rx: ClientRx<B>, builder: &Builder, exec: Exec) -> Client<T, B> { pub(crate) fn new(io: T, rx: ClientRx<B>, builder: &Builder, exec: Exec) -> Client<T, B> {
unimplemented!("proto::h2::Client::new");
/*
let handshake = builder.handshake(io); let handshake = builder.handshake(io);
Client { Client {
@@ -49,6 +51,7 @@ where
rx: rx, rx: rx,
state: State::Handshaking(handshake), state: State::Handshaking(handshake),
} }
*/
} }
} }
@@ -57,10 +60,11 @@ where
T: AsyncRead + AsyncWrite + Send + 'static, T: AsyncRead + AsyncWrite + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
{ {
type Item = Dispatched; type Output = crate::Result<Dispatched>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
unimplemented!("impl Future for proto::h2::Client");
/*
loop { loop {
let next = match self.state { let next = match self.state {
State::Handshaking(ref mut h) => { State::Handshaking(ref mut h) => {
@@ -196,5 +200,6 @@ where
}; };
self.state = next; self.state = next;
} }
*/
} }
} }

View File

@@ -1,5 +1,5 @@
use bytes::Buf; use bytes::Buf;
use futures::{Async, Future, Poll}; //use futures::{Async, Future, Poll};
use h2::{SendStream}; use h2::{SendStream};
use http::header::{ use http::header::{
HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER, HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER,
@@ -106,6 +106,7 @@ where
} }
} }
/*
impl<S> Future for PipeToSendStream<S> impl<S> Future for PipeToSendStream<S>
where where
S: Payload, S: Payload,
@@ -114,6 +115,8 @@ where
type Error = crate::Error; type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
unimplemented!("impl Future for PipeToSendStream");
/*
loop { loop {
if !self.data_done { if !self.data_done {
// we don't have the next chunk of data yet, so just reserve 1 byte to make // we don't have the next chunk of data yet, so just reserve 1 byte to make
@@ -189,8 +192,10 @@ where
} }
} }
} }
*/
} }
} }
*/
struct SendBuf<B>(Option<B>); struct SendBuf<B>(Option<B>);

View File

@@ -1,15 +1,15 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use futures::{Async, Future, Poll, Stream};
use h2::Reason; use h2::Reason;
use h2::server::{Builder, Connection, Handshake, SendResponse}; use h2::server::{Builder, Connection, Handshake, SendResponse};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::headers::content_length_parse_all;
use crate::body::Payload; use crate::body::Payload;
use crate::body::internal::FullDataArg; use crate::body::internal::FullDataArg;
use crate::common::exec::H2Exec; use crate::common::exec::H2Exec;
use crate::common::{Future, Pin, Poll, task};
use crate::headers; use crate::headers;
use crate::headers::content_length_parse_all;
use crate::service::Service; use crate::service::Service;
use crate::proto::Dispatched; use crate::proto::Dispatched;
use super::{PipeToSendStream, SendBuf}; use super::{PipeToSendStream, SendBuf};
@@ -26,6 +26,9 @@ where
state: State<T, B>, state: State<T, B>,
} }
// TODO: fix me
impl<T, S: Service, B: Payload, E> Unpin for Server<T, S, B, E> {}
enum State<T, B> enum State<T, B>
where where
B: Payload, B: Payload,
@@ -53,15 +56,20 @@ where
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
pub(crate) fn new(io: T, service: S, builder: &Builder, exec: E) -> Server<T, S, B, E> { pub(crate) fn new(io: T, service: S, builder: &Builder, exec: E) -> Server<T, S, B, E> {
unimplemented!("proto::h2::Server::new")
/*
let handshake = builder.handshake(io); let handshake = builder.handshake(io);
Server { Server {
exec, exec,
state: State::Handshaking(handshake), state: State::Handshaking(handshake),
service, service,
} }
*/
} }
pub fn graceful_shutdown(&mut self) { pub fn graceful_shutdown(&mut self) {
unimplemented!("proto::h2::Server::graceful_shutdown")
/*
trace!("graceful_shutdown"); trace!("graceful_shutdown");
match self.state { match self.state {
State::Handshaking(..) => { State::Handshaking(..) => {
@@ -78,6 +86,7 @@ where
} }
} }
self.state = State::Closed; self.state = State::Closed;
*/
} }
} }
@@ -89,10 +98,11 @@ where
B: Payload, B: Payload,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
type Item = Dispatched; type Output = crate::Result<Dispatched>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
unimplemented!("h2 server future")
/*
loop { loop {
let next = match self.state { let next = match self.state {
State::Handshaking(ref mut h) => { State::Handshaking(ref mut h) => {
@@ -114,6 +124,7 @@ where
}; };
self.state = next; self.state = next;
} }
*/
} }
} }
@@ -122,7 +133,7 @@ where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
B: Payload, B: Payload,
{ {
fn poll_server<S, E>(&mut self, service: &mut S, exec: &E) -> Poll<(), crate::Error> fn poll_server<S, E>(&mut self, service: &mut S, exec: &E) -> Poll<crate::Result<()>>
where where
S: Service< S: Service<
ReqBody=Body, ReqBody=Body,
@@ -131,6 +142,7 @@ where
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
/*
if self.closing.is_none() { if self.closing.is_none() {
loop { loop {
// At first, polls the readiness of supplied service. // At first, polls the readiness of supplied service.
@@ -182,6 +194,8 @@ where
try_ready!(self.conn.poll_close().map_err(crate::Error::new_h2)); try_ready!(self.conn.poll_close().map_err(crate::Error::new_h2));
Err(self.closing.take().expect("polled after error")) Err(self.closing.take().expect("polled after error"))
*/
unimplemented!("h2 server poll_server")
} }
} }
@@ -204,8 +218,8 @@ where
impl<F, B> H2Stream<F, B> impl<F, B> H2Stream<F, B>
where where
F: Future<Item=Response<B>>, //F: Future<Item=Response<B>>,
F::Error: Into<Box<dyn StdError + Send + Sync>>, //F::Error: Into<Box<dyn StdError + Send + Sync>>,
B: Payload, B: Payload,
{ {
fn new(fut: F, respond: SendResponse<SendBuf<B::Data>>) -> H2Stream<F, B> { fn new(fut: F, respond: SendResponse<SendBuf<B::Data>>) -> H2Stream<F, B> {
@@ -214,8 +228,19 @@ where
state: H2StreamState::Service(fut), state: H2StreamState::Service(fut),
} }
} }
}
fn poll2(&mut self) -> Poll<(), crate::Error> { impl<F, B> Future for H2Stream<F, B>
where
//F: Future<Item=Response<B>>,
//F::Error: Into<Box<dyn StdError + Send + Sync>>,
B: Payload,
{
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
unimplemented!("impl Future for H2Stream");
/*
loop { loop {
let next = match self.state { let next = match self.state {
H2StreamState::Service(ref mut h) => { H2StreamState::Service(ref mut h) => {
@@ -292,9 +317,10 @@ where
}; };
self.state = next; self.state = next;
} }
*/
} }
} }
/*
impl<F, B> Future for H2Stream<F, B> impl<F, B> Future for H2Stream<F, B>
where where
F: Future<Item=Response<B>>, F: Future<Item=Response<B>>,
@@ -309,4 +335,5 @@ where
.map_err(|e| debug!("stream error: {}", e)) .map_err(|e| debug!("stream error: {}", e))
} }
} }
*/

View File

@@ -6,8 +6,9 @@
//! The inclusion of a default runtime can be disabled by turning off hyper's //! The inclusion of a default runtime can be disabled by turning off hyper's
//! `runtime` Cargo feature. //! `runtime` Cargo feature.
pub use futures::{Future, Stream}; pub use std::future::Future;
pub use futures::future::{lazy, poll_fn}; pub use futures_core::Stream;
use tokio; use tokio;
use self::inner::Spawn; use self::inner::Spawn;
@@ -25,7 +26,7 @@ use self::inner::Spawn;
/// ignored for now. /// ignored for now.
pub fn spawn<F>(f: F) -> Spawn pub fn spawn<F>(f: F) -> Spawn
where where
F: Future<Item=(), Error=()> + Send + 'static, F: Future<Output = ()> + Send + 'static,
{ {
tokio::spawn(f); tokio::spawn(f);
Spawn { Spawn {
@@ -40,7 +41,7 @@ where
/// See the [server documentation](::server) for an example of its usage. /// See the [server documentation](::server) for an example of its usage.
pub fn run<F>(f: F) pub fn run<F>(f: F)
where where
F: Future<Item=(), Error=()> + Send + 'static F: Future<Output = ()> + Send + 'static
{ {
tokio::run(f); tokio::run(f);
} }

View File

@@ -16,15 +16,16 @@ use std::sync::Arc;
#[cfg(feature = "runtime")] use std::time::Duration; #[cfg(feature = "runtime")] use std::time::Duration;
use bytes::Bytes; use bytes::Bytes;
use futures::{Async, Future, Poll, Stream}; use futures_core::Stream;
use futures::future::{Either, Executor};
use h2; use h2;
use pin_utils::{unsafe_pinned, unsafe_unpinned};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
#[cfg(feature = "runtime")] use tokio_reactor::Handle; #[cfg(feature = "runtime")] use tokio_reactor::Handle;
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::exec::{Exec, H2Exec, NewSvcExec}; use crate::common::exec::{Exec, H2Exec, NewSvcExec};
use crate::common::io::Rewind; use crate::common::io::Rewind;
use crate::common::{Future, Pin, Poll, Unpin, task};
use crate::error::{Kind, Parse}; use crate::error::{Kind, Parse};
use crate::proto; use crate::proto;
use crate::service::{MakeServiceRef, Service}; use crate::service::{MakeServiceRef, Service};
@@ -103,8 +104,7 @@ pub struct Connection<T, S, E = Exec>
where where
S: Service, S: Service,
{ {
pub(super) conn: Option< pub(super) conn: Option<Either<
Either<
proto::h1::Dispatcher< proto::h1::Dispatcher<
proto::h1::dispatch::Server<S>, proto::h1::dispatch::Server<S>,
S::ResBody, S::ResBody,
@@ -121,6 +121,11 @@ where
fallback: Fallback<E>, fallback: Fallback<E>,
} }
pub(super) enum Either<A, B> {
A(A),
B(B),
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum Fallback<E> { enum Fallback<E> {
ToHttp2(h2::server::Builder, E), ToHttp2(h2::server::Builder, E),
@@ -136,6 +141,8 @@ impl<E> Fallback<E> {
} }
} }
impl<E> Unpin for Fallback<E> {}
/// Deconstructed parts of a `Connection`. /// Deconstructed parts of a `Connection`.
/// ///
/// This allows taking apart a `Connection` at a later time, in order to /// This allows taking apart a `Connection` at a later time, in order to
@@ -175,16 +182,6 @@ impl Http {
pipeline_flush: false, pipeline_flush: false,
} }
} }
#[doc(hidden)]
#[deprecated(note = "use Http::with_executor instead")]
pub fn executor<E>(&mut self, exec: E) -> &mut Self
where
E: Executor<Box<dyn Future<Item=(), Error=()> + Send>> + Send + Sync + 'static
{
self.exec = Exec::Executor(Arc::new(exec));
self
}
} }
impl<E> Http<E> { impl<E> Http<E> {
@@ -367,7 +364,7 @@ impl<E> Http<E> {
S: Service<ReqBody=Body, ResBody=Bd>, S: Service<ReqBody=Body, ResBody=Bd>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
Bd: Payload, Bd: Payload,
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
E: H2Exec<S::Future, Bd>, E: H2Exec<S::Future, Bd>,
{ {
let either = match self.mode { let either = match self.mode {
@@ -457,13 +454,13 @@ impl<E> Http<E> {
} }
/// Bind the provided stream of incoming IO objects with a `MakeService`. /// Bind the provided stream of incoming IO objects with a `MakeService`.
pub fn serve_incoming<I, S, Bd>(&self, incoming: I, make_service: S) -> Serve<I, S, E> pub fn serve_incoming<I, IO, IE, S, Bd>(&self, incoming: I, make_service: S) -> Serve<I, S, E>
where where
I: Stream, I: Stream<Item = Result<IO, IE>>,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite, IO: AsyncRead + AsyncWrite + Unpin,
S: MakeServiceRef< S: MakeServiceRef<
I::Item, IO,
ReqBody=Body, ReqBody=Body,
ResBody=Bd, ResBody=Bd,
>, >,
@@ -486,7 +483,7 @@ impl<I, B, S, E> Connection<I, S, E>
where where
S: Service<ReqBody=Body, ResBody=B>, S: Service<ReqBody=Body, ResBody=B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
B: Payload + 'static, B: Payload + 'static,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
@@ -494,8 +491,10 @@ where
/// ///
/// This `Connection` should continue to be polled until shutdown /// This `Connection` should continue to be polled until shutdown
/// can finish. /// can finish.
pub fn graceful_shutdown(&mut self) { pub fn graceful_shutdown(self: Pin<&mut Self>) {
match *self.conn.as_mut().unwrap() { // Safety: neither h1 nor h2 poll any of the generic futures
// in these methods.
match unsafe { self.get_unchecked_mut() }.conn.as_mut().unwrap() {
Either::A(ref mut h1) => { Either::A(ref mut h1) => {
h1.disable_keep_alive(); h1.disable_keep_alive();
}, },
@@ -547,21 +546,26 @@ where
/// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html) /// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html)
/// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html) /// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html)
/// to work with this function; or use the `without_shutdown` wrapper. /// to work with this function; or use the `without_shutdown` wrapper.
pub fn poll_without_shutdown(&mut self) -> Poll<(), crate::Error> { pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>>
where
S: Unpin,
S::Future: Unpin,
B: Unpin,
{
loop { loop {
let polled = match *self.conn.as_mut().unwrap() { let polled = match *self.conn.as_mut().unwrap() {
Either::A(ref mut h1) => h1.poll_without_shutdown(), Either::A(ref mut h1) => h1.poll_without_shutdown(cx),
Either::B(ref mut h2) => return h2.poll().map(|x| x.map(|_| ())), Either::B(ref mut h2) => unimplemented!("Connection::poll_without_shutdown h2"),//return h2.poll().map(|x| x.map(|_| ())),
}; };
match polled { match ready!(polled) {
Ok(x) => return Ok(x), Ok(x) => return Poll::Ready(Ok(x)),
Err(e) => { Err(e) => {
match *e.kind() { match *e.kind() {
Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => {
self.upgrade_h2(); self.upgrade_h2();
continue; continue;
} }
_ => return Err(e), _ => return Poll::Ready(Err(e)),
} }
} }
} }
@@ -570,11 +574,16 @@ where
/// Prevent shutdown of the underlying IO object at the end of service the request, /// Prevent shutdown of the underlying IO object at the end of service the request,
/// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`. /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`.
pub fn without_shutdown(self) -> impl Future<Item=Parts<I,S>, Error=crate::Error> { pub fn without_shutdown(self) -> impl Future<Output=crate::Result<Parts<I, S>>>
where
S: Unpin,
S::Future: Unpin,
B: Unpin,
{
let mut conn = Some(self); let mut conn = Some(self);
::futures::future::poll_fn(move || -> crate::Result<_> { futures_util::future::poll_fn(move |cx| {
try_ready!(conn.as_mut().unwrap().poll_without_shutdown()); ready!(conn.as_mut().unwrap().poll_without_shutdown(cx))?;
Ok(conn.take().unwrap().into_parts().into()) Poll::Ready(Ok(conn.take().unwrap().into_parts()))
}) })
} }
@@ -624,32 +633,32 @@ impl<I, B, S, E> Future for Connection<I, S, E>
where where
S: Service<ReqBody=Body, ResBody=B> + 'static, S: Service<ReqBody=Body, ResBody=B> + 'static,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite + 'static, I: AsyncRead + AsyncWrite + Unpin + 'static,
B: Payload + 'static, B: Payload + 'static,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
type Item = (); type Output = crate::Result<()>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
loop { loop {
match self.conn.poll() { match ready!(Pin::new(self.conn.as_mut().unwrap()).poll(cx)) {
Ok(x) => return Ok(x.map(|opt| { Ok(done) => {
if let Some(proto::Dispatched::Upgrade(pending)) = opt { if let proto::Dispatched::Upgrade(pending) = done {
// With no `Send` bound on `I`, we can't try to do // With no `Send` bound on `I`, we can't try to do
// upgrades here. In case a user was trying to use // upgrades here. In case a user was trying to use
// `Body::on_upgrade` with this API, send a special // `Body::on_upgrade` with this API, send a special
// error letting them know about that. // error letting them know about that.
pending.manual(); pending.manual();
} }
})), return Poll::Ready(Ok(()));
},
Err(e) => { Err(e) => {
match *e.kind() { match *e.kind() {
Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => {
self.upgrade_h2(); self.upgrade_h2();
continue; continue;
} }
_ => return Err(e), _ => return Poll::Ready(Err(e)),
} }
} }
} }
@@ -669,6 +678,9 @@ where
// ===== impl Serve ===== // ===== impl Serve =====
impl<I, S, E> Serve<I, S, E> { impl<I, S, E> Serve<I, S, E> {
unsafe_pinned!(incoming: I);
unsafe_unpinned!(make_service: S);
/// Spawn all incoming connections onto the executor in `Http`. /// Spawn all incoming connections onto the executor in `Http`.
pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> { pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> {
SpawnAll { SpawnAll {
@@ -689,60 +701,63 @@ impl<I, S, E> Serve<I, S, E> {
} }
} }
impl<I, S, B, E> Stream for Serve<I, S, E> impl<I, IO, IE, S, B, E> Stream for Serve<I, S, E>
where where
I: Stream, I: Stream<Item = Result<IO, IE>>,
I::Item: AsyncRead + AsyncWrite, IO: AsyncRead + AsyncWrite + Unpin,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
S: MakeServiceRef<I::Item, ReqBody=Body, ResBody=B>, S: MakeServiceRef<IO, ReqBody=Body, ResBody=B>,
//S::Error2: Into<Box<StdError + Send + Sync>>, //S::Error2: Into<Box<StdError + Send + Sync>>,
//SME: Into<Box<StdError + Send + Sync>>, //SME: Into<Box<StdError + Send + Sync>>,
B: Payload, B: Payload,
E: H2Exec<<S::Service as Service>::Future, B>, E: H2Exec<<S::Service as Service>::Future, B>,
{ {
type Item = Connecting<I::Item, S::Future, E>; type Item = crate::Result<Connecting<IO, S::Future, E>>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
match self.make_service.poll_ready_ref() { match ready!(self.as_mut().make_service().poll_ready_ref(cx)) {
Ok(Async::Ready(())) => (), Ok(()) => (),
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => { Err(e) => {
trace!("make_service closed"); trace!("make_service closed");
return Err(crate::Error::new_user_make_service(e)); return Poll::Ready(Some(Err(crate::Error::new_user_make_service(e))));
} }
} }
if let Some(io) = try_ready!(self.incoming.poll().map_err(crate::Error::new_accept)) { if let Some(item) = ready!(self.as_mut().incoming().poll_next(cx)) {
let new_fut = self.make_service.make_service_ref(&io); let io = item.map_err(crate::Error::new_accept)?;
Ok(Async::Ready(Some(Connecting { let new_fut = self.as_mut().make_service().make_service_ref(&io);
Poll::Ready(Some(Ok(Connecting {
future: new_fut, future: new_fut,
io: Some(io), io: Some(io),
protocol: self.protocol.clone(), protocol: self.protocol.clone(),
}))) })))
} else { } else {
Ok(Async::Ready(None)) Poll::Ready(None)
} }
} }
} }
// ===== impl Connecting ===== // ===== impl Connecting =====
impl<I, F, E, S, B> Future for Connecting<I, F, E> impl<I, F, E> Connecting<I, F, E> {
unsafe_pinned!(future: F);
unsafe_unpinned!(io: Option<I>);
}
impl<I, F, S, FE, E, B> Future for Connecting<I, F, E>
where where
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
F: Future<Item=S>, F: Future<Output=Result<S, FE>>,
S: Service<ReqBody=Body, ResBody=B>, S: Service<ReqBody=Body, ResBody=B>,
B: Payload, B: Payload,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
type Item = Connection<I, S, E>; type Output = Result<Connection<I, S, E>, FE>;
type Error = F::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
let service = try_ready!(self.future.poll()); let service = ready!(self.as_mut().future().poll(cx))?;
let io = self.io.take().expect("polled after complete"); let io = self.as_mut().io().take().expect("polled after complete");
Ok(self.protocol.serve_connection(io, service).into()) Poll::Ready(Ok(self.protocol.serve_connection(io, service)))
} }
} }
@@ -761,30 +776,51 @@ impl<I, S, E> SpawnAll<I, S, E> {
} }
} }
impl<I, S, B, E> SpawnAll<I, S, E> impl<I, IO, IE, S, B, E> SpawnAll<I, S, E>
where where
I: Stream, I: Stream<Item=Result<IO, IE>>,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static, IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: MakeServiceRef< S: MakeServiceRef<
I::Item, IO,
ReqBody=Body, ReqBody=Body,
ResBody=B, ResBody=B,
>, >,
B: Payload, B: Payload,
E: H2Exec<<S::Service as Service>::Future, B>, E: H2Exec<<S::Service as Service>::Future, B>,
{ {
pub(super) fn poll_watch<W>(&mut self, watcher: &W) -> Poll<(), crate::Error> pub(super) fn poll_watch<W>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, watcher: &W) -> Poll<crate::Result<()>>
where where
E: NewSvcExec<I::Item, S::Future, S::Service, E, W>, E: NewSvcExec<IO, S::Future, S::Service, E, W>,
W: Watcher<I::Item, S::Service, E>, W: Watcher<IO, S::Service, E>,
{ {
// Safety: futures are never moved... lolwtf
let me = unsafe { self.get_unchecked_mut() };
loop { loop {
if let Some(connecting) = try_ready!(self.serve.poll()) { if let Some(connecting) = ready!(unsafe { Pin::new_unchecked(&mut me.serve) }.poll_next(cx)?) {
let fut = NewSvcTask::new(connecting, watcher.clone()); let fut = NewSvcTask::new(connecting, watcher.clone());
self.serve.protocol.exec.execute_new_svc(fut)?; me.serve.protocol.exec.execute_new_svc(fut)?;
} else { } else {
return Ok(Async::Ready(())) return Poll::Ready(Ok(()));
}
}
}
}
impl<A, B> Future for Either<A, B>
where
A: Future,
B: Future<Output=A::Output>,
{
type Output = A::Output;
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
// Just simple pin projection to the inner variants
unsafe {
match self.get_unchecked_mut() {
Either::A(a) => Pin::new_unchecked(a).poll(cx),
Either::B(b) => Pin::new_unchecked(b).poll(cx),
} }
} }
} }
@@ -792,11 +828,11 @@ where
pub(crate) mod spawn_all { pub(crate) mod spawn_all {
use std::error::Error as StdError; use std::error::Error as StdError;
use futures::{Future, Poll};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::exec::H2Exec; use crate::common::exec::H2Exec;
use crate::common::{Future, Pin, Poll, Unpin, task};
use crate::service::Service; use crate::service::Service;
use super::{Connecting, UpgradeableConnection}; use super::{Connecting, UpgradeableConnection};
@@ -809,7 +845,7 @@ pub(crate) mod spawn_all {
// connections, and signal that they start to shutdown when prompted, so // connections, and signal that they start to shutdown when prompted, so
// it has a `GracefulWatcher` implementation to do that. // it has a `GracefulWatcher` implementation to do that.
pub trait Watcher<I, S: Service, E>: Clone { pub trait Watcher<I, S: Service, E>: Clone {
type Future: Future<Item=(), Error=crate::Error>; type Future: Future<Output = crate::Result<()>>;
fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future; fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future;
} }
@@ -820,7 +856,7 @@ pub(crate) mod spawn_all {
impl<I, S, E> Watcher<I, S, E> for NoopWatcher impl<I, S, E> Watcher<I, S, E> for NoopWatcher
where where
I: AsyncRead + AsyncWrite + Send + 'static, I: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: Service<ReqBody=Body> + 'static, S: Service<ReqBody=Body> + 'static,
E: H2Exec<S::Future, S::ResBody>, E: H2Exec<S::Future, S::ResBody>,
{ {
@@ -858,42 +894,51 @@ pub(crate) mod spawn_all {
} }
} }
impl<I, N, S, B, E, W> Future for NewSvcTask<I, N, S, E, W> impl<I, N, S, NE, B, E, W> Future for NewSvcTask<I, N, S, E, W>
where where
I: AsyncRead + AsyncWrite + Send + 'static, I: AsyncRead + AsyncWrite + Unpin + Send + 'static,
N: Future<Item=S>, N: Future<Output=Result<S, NE>>,
N::Error: Into<Box<dyn StdError + Send + Sync>>, NE: Into<Box<dyn StdError + Send + Sync>>,
S: Service<ReqBody=Body, ResBody=B>, S: Service<ReqBody=Body, ResBody=B>,
B: Payload, B: Payload,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
W: Watcher<I, S, E>, W: Watcher<I, S, E>,
{ {
type Item = (); type Output = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
// If it weren't for needing to name this type so the `Send` bounds
// could be projected to the `Serve` executor, this could just be
// an `async fn`, and much safer. Woe is me.
let me = unsafe { self.get_unchecked_mut() };
loop { loop {
let next = match self.state { let next = match me.state {
State::Connecting(ref mut connecting, ref watcher) => { State::Connecting(ref mut connecting, ref watcher) => {
let conn = try_ready!(connecting let res = ready!(unsafe { Pin::new_unchecked(connecting).poll(cx) });
.poll() let conn = match res {
.map_err(|err| { Ok(conn) => conn,
Err(err) => {
let err = crate::Error::new_user_make_service(err); let err = crate::Error::new_user_make_service(err);
debug!("connecting error: {}", err); debug!("connecting error: {}", err);
})); return Poll::Ready(());
}
};
let connected = watcher.watch(conn.with_upgrades()); let connected = watcher.watch(conn.with_upgrades());
State::Connected(connected) State::Connected(connected)
}, },
State::Connected(ref mut future) => { State::Connected(ref mut future) => {
return future return unsafe { Pin::new_unchecked(future) }
.poll() .poll(cx)
.map_err(|err| { .map(|res| {
debug!("connection error: {}", err); if let Err(err) = res {
debug!("connection error: {}", err);
}
}); });
} }
}; };
self.state = next; me.state = next;
} }
} }
} }
@@ -919,7 +964,7 @@ mod upgrades {
where where
S: Service<ReqBody=Body, ResBody=B>,// + 'static, S: Service<ReqBody=Body, ResBody=B>,// + 'static,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
B: Payload + 'static, B: Payload + 'static,
E: H2Exec<S::Future, B>, E: H2Exec<S::Future, B>,
{ {
@@ -927,8 +972,8 @@ mod upgrades {
/// ///
/// This `Connection` should continue to be polled until shutdown /// This `Connection` should continue to be polled until shutdown
/// can finish. /// can finish.
pub fn graceful_shutdown(&mut self) { pub fn graceful_shutdown(mut self: Pin<&mut Self>) {
self.inner.graceful_shutdown() Pin::new(&mut self.inner).graceful_shutdown()
} }
} }
@@ -936,22 +981,17 @@ mod upgrades {
where where
S: Service<ReqBody=Body, ResBody=B> + 'static, S: Service<ReqBody=Body, ResBody=B> + 'static,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite + Send + 'static, I: AsyncRead + AsyncWrite + Unpin + Send + 'static,
B: Payload + 'static, B: Payload + 'static,
E: super::H2Exec<S::Future, B>, E: super::H2Exec<S::Future, B>,
{ {
type Item = (); type Output = crate::Result<()>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
loop { loop {
match self.inner.conn.poll() { match ready!(Pin::new(self.inner.conn.as_mut().unwrap()).poll(cx)) {
Ok(Async::NotReady) => return Ok(Async::NotReady), Ok(proto::Dispatched::Shutdown) => return Poll::Ready(Ok(())),
Ok(Async::Ready(Some(proto::Dispatched::Shutdown))) | Ok(proto::Dispatched::Upgrade(pending)) => {
Ok(Async::Ready(None)) => {
return Ok(Async::Ready(()));
},
Ok(Async::Ready(Some(proto::Dispatched::Upgrade(pending)))) => {
let h1 = match mem::replace(&mut self.inner.conn, None) { let h1 = match mem::replace(&mut self.inner.conn, None) {
Some(Either::A(h1)) => h1, Some(Either::A(h1)) => h1,
_ => unreachable!("Upgrade expects h1"), _ => unreachable!("Upgrade expects h1"),
@@ -959,7 +999,7 @@ mod upgrades {
let (io, buf, _) = h1.into_inner(); let (io, buf, _) = h1.into_inner();
pending.fulfill(Upgraded::new(Box::new(io), buf)); pending.fulfill(Upgraded::new(Box::new(io), buf));
return Ok(Async::Ready(())); return Poll::Ready(Ok(()));
}, },
Err(e) => { Err(e) => {
match *e.kind() { match *e.kind() {
@@ -967,7 +1007,7 @@ mod upgrades {
self.inner.upgrade_h2(); self.inner.upgrade_h2();
continue; continue;
} }
_ => return Err(e), _ => return Poll::Ready(Err(e)),
} }
} }
} }

View File

@@ -60,12 +60,14 @@ use std::fmt;
#[cfg(feature = "runtime")] use std::time::Duration; #[cfg(feature = "runtime")] use std::time::Duration;
use futures::{Future, Stream, Poll}; use futures_core::Stream;
use pin_utils::unsafe_pinned;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
#[cfg(feature = "runtime")] use tokio_reactor; #[cfg(feature = "runtime")] use tokio_reactor;
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::exec::{Exec, H2Exec, NewSvcExec}; use crate::common::exec::{Exec, H2Exec, NewSvcExec};
use crate::common::{Future, Pin, Poll, Unpin, task};
use crate::service::{MakeServiceRef, Service}; use crate::service::{MakeServiceRef, Service};
// Renamed `Http` as `Http_` for now so that people upgrading don't see an // Renamed `Http` as `Http_` for now so that people upgrading don't see an
// error that `hyper::server::Http` is private... // error that `hyper::server::Http` is private...
@@ -102,6 +104,11 @@ impl<I> Server<I, ()> {
} }
} }
impl<I, S, E> Server<I, S, E> {
// Never moved, just projected
unsafe_pinned!(spawn_all: SpawnAll<I, S, E>);
}
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
impl Server<AddrIncoming, ()> { impl Server<AddrIncoming, ()> {
/// Binds to the provided address, and returns a [`Builder`](Builder). /// Binds to the provided address, and returns a [`Builder`](Builder).
@@ -140,17 +147,17 @@ impl<S> Server<AddrIncoming, S> {
} }
} }
impl<I, S, E, B> Server<I, S, E> impl<I, IO, IE, S, E, B> Server<I, S, E>
where where
I: Stream, I: Stream<Item=Result<IO, IE>>,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static, IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: MakeServiceRef<I::Item, ReqBody=Body, ResBody=B>, S: MakeServiceRef<IO, ReqBody=Body, ResBody=B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
S::Service: 'static, S::Service: 'static,
B: Payload, B: Payload,
E: H2Exec<<S::Service as Service>::Future, B>, E: H2Exec<<S::Service as Service>::Future, B>,
E: NewSvcExec<I::Item, S::Future, S::Service, E, GracefulWatcher>, E: NewSvcExec<IO, S::Future, S::Service, E, GracefulWatcher>,
{ {
/// Prepares a server to handle graceful shutdown when the provided future /// Prepares a server to handle graceful shutdown when the provided future
/// completes. /// completes.
@@ -193,29 +200,28 @@ where
/// ``` /// ```
pub fn with_graceful_shutdown<F>(self, signal: F) -> Graceful<I, S, F, E> pub fn with_graceful_shutdown<F>(self, signal: F) -> Graceful<I, S, F, E>
where where
F: Future<Item=()> F: Future<Output=()>
{ {
Graceful::new(self.spawn_all, signal) Graceful::new(self.spawn_all, signal)
} }
} }
impl<I, S, B, E> Future for Server<I, S, E> impl<I, IO, IE, S, B, E> Future for Server<I, S, E>
where where
I: Stream, I: Stream<Item=Result<IO, IE>>,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static, IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: MakeServiceRef<I::Item, ReqBody=Body, ResBody=B>, S: MakeServiceRef<IO, ReqBody=Body, ResBody=B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
S::Service: 'static, S::Service: 'static,
B: Payload, B: Payload,
E: H2Exec<<S::Service as Service>::Future, B>, E: H2Exec<<S::Service as Service>::Future, B>,
E: NewSvcExec<I::Item, S::Future, S::Service, E, NoopWatcher>, E: NewSvcExec<IO, S::Future, S::Service, E, NoopWatcher>,
{ {
type Item = (); type Output = crate::Result<()>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
self.spawn_all.poll_watch(&NoopWatcher) self.spawn_all().poll_watch(cx, &NoopWatcher)
} }
} }
@@ -396,16 +402,16 @@ impl<I, E> Builder<I, E> {
/// // Finally, spawn `server` onto an Executor... /// // Finally, spawn `server` onto an Executor...
/// # } /// # }
/// ``` /// ```
pub fn serve<S, B>(self, new_service: S) -> Server<I, S, E> pub fn serve<S, B, IO, IE>(self, new_service: S) -> Server<I, S, E>
where where
I: Stream, I: Stream<Item=Result<IO, IE>>,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static, IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: MakeServiceRef<I::Item, ReqBody=Body, ResBody=B>, S: MakeServiceRef<IO, ReqBody=Body, ResBody=B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
S::Service: 'static, S::Service: 'static,
B: Payload, B: Payload,
E: NewSvcExec<I::Item, S::Future, S::Service, E, NoopWatcher>, E: NewSvcExec<IO, S::Future, S::Service, E, NoopWatcher>,
E: H2Exec<<S::Service as Service>::Future, B>, E: H2Exec<<S::Service as Service>::Future, B>,
{ {
let serve = self.protocol.serve_incoming(self.incoming, new_service); let serve = self.protocol.serve_incoming(self.incoming, new_service);

View File

@@ -1,11 +1,12 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use futures::{Async, Future, Stream, Poll}; use futures_core::Stream;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::body::{Body, Payload}; use crate::body::{Body, Payload};
use crate::common::drain::{self, Draining, Signal, Watch, Watching}; use crate::common::drain::{self, Draining, Signal, Watch, Watching};
use crate::common::exec::{H2Exec, NewSvcExec}; use crate::common::exec::{H2Exec, NewSvcExec};
use crate::common::{Future, Pin, Poll, Unpin, task};
use crate::service::{MakeServiceRef, Service}; use crate::service::{MakeServiceRef, Service};
use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; use super::conn::{SpawnAll, UpgradeableConnection, Watcher};
@@ -37,31 +38,32 @@ impl<I, S, F, E> Graceful<I, S, F, E> {
} }
impl<I, S, B, F, E> Future for Graceful<I, S, F, E> impl<I, IO, IE, S, B, F, E> Future for Graceful<I, S, F, E>
where where
I: Stream, I: Stream<Item=Result<IO, IE>>,
I::Error: Into<Box<dyn StdError + Send + Sync>>, IE: Into<Box<dyn StdError + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static, IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: MakeServiceRef<I::Item, ReqBody=Body, ResBody=B>, S: MakeServiceRef<IO, ReqBody=Body, ResBody=B>,
S::Service: 'static, S::Service: 'static,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
B: Payload, B: Payload,
F: Future<Item=()>, F: Future<Output=()>,
E: H2Exec<<S::Service as Service>::Future, B>, E: H2Exec<<S::Service as Service>::Future, B>,
E: NewSvcExec<I::Item, S::Future, S::Service, E, GracefulWatcher>, E: NewSvcExec<IO, S::Future, S::Service, E, GracefulWatcher>,
{ {
type Item = (); type Output = crate::Result<()>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
// Safety: the futures are NEVER moved, self.state is overwritten instead.
let me = unsafe { self.get_unchecked_mut() };
loop { loop {
let next = match self.state { let next = match me.state {
State::Running { State::Running {
ref mut drain, ref mut drain,
ref mut spawn_all, ref mut spawn_all,
ref mut signal, ref mut signal,
} => match signal.poll() { } => match unsafe { Pin::new_unchecked(signal) }.poll(cx) {
Ok(Async::Ready(())) | Err(_) => { Poll::Ready(()) => {
debug!("signal received, starting graceful shutdown"); debug!("signal received, starting graceful shutdown");
let sig = drain let sig = drain
.take() .take()
@@ -69,21 +71,21 @@ where
.0; .0;
State::Draining(sig.drain()) State::Draining(sig.drain())
}, },
Ok(Async::NotReady) => { Poll::Pending => {
let watch = drain let watch = drain
.as_ref() .as_ref()
.expect("drain channel") .expect("drain channel")
.1 .1
.clone(); .clone();
return spawn_all.poll_watch(&GracefulWatcher(watch)); return unsafe { Pin::new_unchecked(spawn_all) }.poll_watch(cx, &GracefulWatcher(watch));
}, },
}, },
State::Draining(ref mut draining) => { State::Draining(ref mut draining) => {
return draining.poll() return Pin::new(draining).poll(cx).map(Ok);
.map_err(|()| unreachable!("drain mpsc rx never errors"));
} }
}; };
self.state = next; // It's important to just assign, not mem::replace or anything.
me.state = next;
} }
} }
} }
@@ -94,11 +96,11 @@ pub struct GracefulWatcher(Watch);
impl<I, S, E> Watcher<I, S, E> for GracefulWatcher impl<I, S, E> Watcher<I, S, E> for GracefulWatcher
where where
I: AsyncRead + AsyncWrite + Send + 'static, I: AsyncRead + AsyncWrite + Unpin + Send + 'static,
S: Service<ReqBody=Body> + 'static, S: Service<ReqBody=Body> + 'static,
E: H2Exec<S::Future, S::ResBody>, E: H2Exec<S::Future, S::ResBody>,
{ {
type Future = Watching<UpgradeableConnection<I, S, E>, fn(&mut UpgradeableConnection<I, S, E>)>; type Future = Watching<UpgradeableConnection<I, S, E>, fn(Pin<&mut UpgradeableConnection<I, S, E>>)>;
fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future { fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future {
self self
@@ -108,11 +110,11 @@ where
} }
} }
fn on_drain<I, S, E>(conn: &mut UpgradeableConnection<I, S, E>) fn on_drain<I, S, E>(conn: Pin<&mut UpgradeableConnection<I, S, E>>)
where where
S: Service<ReqBody=Body>, S: Service<ReqBody=Body>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite, I: AsyncRead + AsyncWrite + Unpin,
S::ResBody: Payload + 'static, S::ResBody: Payload + 'static,
E: H2Exec<S::Future, S::ResBody>, E: H2Exec<S::Future, S::ResBody>,
{ {

View File

@@ -3,11 +3,13 @@ use std::io;
use std::net::{SocketAddr, TcpListener as StdTcpListener}; use std::net::{SocketAddr, TcpListener as StdTcpListener};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use futures::{Async, Future, Poll, Stream}; use futures_core::Stream;
use tokio_reactor::Handle; use tokio_reactor::Handle;
use tokio_tcp::TcpListener; use tokio_tcp::TcpListener;
use tokio_timer::Delay; use tokio_timer::Delay;
use crate::common::{Future, Pin, Poll, task};
pub use self::addr_stream::AddrStream; pub use self::addr_stream::AddrStream;
/// A stream of connections from binding to an address. /// A stream of connections from binding to an address.
@@ -92,28 +94,20 @@ impl AddrIncoming {
pub fn set_sleep_on_errors(&mut self, val: bool) { pub fn set_sleep_on_errors(&mut self, val: bool) {
self.sleep_on_errors = val; self.sleep_on_errors = val;
} }
}
impl Stream for AddrIncoming { fn poll_next_(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<AddrStream>> {
// currently unnameable...
type Item = AddrStream;
type Error = ::std::io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// Check if a previous timeout is active that was set by IO errors. // Check if a previous timeout is active that was set by IO errors.
if let Some(ref mut to) = self.timeout { if let Some(ref mut to) = self.timeout {
match to.poll() { match Pin::new(to).poll(cx) {
Ok(Async::Ready(())) => {} Poll::Ready(()) => {}
Ok(Async::NotReady) => return Ok(Async::NotReady), Poll::Pending => return Poll::Pending,
Err(err) => {
error!("sleep timer error: {}", err);
}
} }
} }
self.timeout = None; self.timeout = None;
loop { loop {
match self.listener.poll_accept() { match Pin::new(&mut self.listener).poll_accept(cx) {
Ok(Async::Ready((socket, addr))) => { Poll::Ready(Ok((socket, addr))) => {
if let Some(dur) = self.tcp_keepalive_timeout { if let Some(dur) = self.tcp_keepalive_timeout {
if let Err(e) = socket.set_keepalive(Some(dur)) { if let Err(e) = socket.set_keepalive(Some(dur)) {
trace!("error trying to set TCP keepalive: {}", e); trace!("error trying to set TCP keepalive: {}", e);
@@ -122,10 +116,10 @@ impl Stream for AddrIncoming {
if let Err(e) = socket.set_nodelay(self.tcp_nodelay) { if let Err(e) = socket.set_nodelay(self.tcp_nodelay) {
trace!("error trying to set TCP nodelay: {}", e); trace!("error trying to set TCP nodelay: {}", e);
} }
return Ok(Async::Ready(Some(AddrStream::new(socket, addr)))); return Poll::Ready(Ok(AddrStream::new(socket, addr)));
}, },
Ok(Async::NotReady) => return Ok(Async::NotReady), Poll::Pending => return Poll::Pending,
Err(e) => { Poll::Ready(Err(e)) => {
// Connection errors can be ignored directly, continue by // Connection errors can be ignored directly, continue by
// accepting the next request. // accepting the next request.
if is_connection_error(&e) { if is_connection_error(&e) {
@@ -134,28 +128,24 @@ impl Stream for AddrIncoming {
} }
if self.sleep_on_errors { if self.sleep_on_errors {
error!("accept error: {}", e);
// Sleep 1s. // Sleep 1s.
let delay = Instant::now() + Duration::from_secs(1); let delay = Instant::now() + Duration::from_secs(1);
let mut timeout = Delay::new(delay); let mut timeout = Delay::new(delay);
match timeout.poll() { match Pin::new(&mut timeout).poll(cx) {
Ok(Async::Ready(())) => { Poll::Ready(()) => {
// Wow, it's been a second already? Ok then... // Wow, it's been a second already? Ok then...
error!("accept error: {}", e);
continue continue
}, },
Ok(Async::NotReady) => { Poll::Pending => {
error!("accept error: {}", e);
self.timeout = Some(timeout); self.timeout = Some(timeout);
return Ok(Async::NotReady); return Poll::Pending;
}, },
Err(timer_err) => {
error!("couldn't sleep on error, timer error: {}", timer_err);
return Err(e);
}
} }
} else { } else {
return Err(e); return Poll::Ready(Err(e));
} }
}, },
} }
@@ -163,6 +153,15 @@ impl Stream for AddrIncoming {
} }
} }
impl Stream for AddrIncoming {
type Item = io::Result<AddrStream>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
let result = ready!(self.poll_next_(cx));
Poll::Ready(Some(result))
}
}
/// This function defines errors that are per-connection. Which basically /// This function defines errors that are per-connection. Which basically
/// means that if we get this error from `accept()` system call it means /// means that if we get this error from `accept()` system call it means
/// next connection might be ready to be accepted. /// next connection might be ready to be accepted.
@@ -191,13 +190,14 @@ impl fmt::Debug for AddrIncoming {
} }
mod addr_stream { mod addr_stream {
use std::io::{self, Read, Write}; use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
use bytes::{Buf, BufMut}; use bytes::{Buf, BufMut};
use futures::Poll;
use tokio_tcp::TcpStream; use tokio_tcp::TcpStream;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, task};
/// A transport returned yieled by `AddrIncoming`. /// A transport returned yieled by `AddrIncoming`.
#[derive(Debug)] #[derive(Debug)]
@@ -227,26 +227,6 @@ mod addr_stream {
} }
} }
impl Read for AddrStream {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
impl Write for AddrStream {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
// TcpStream::flush is a noop, so skip calling it...
Ok(())
}
}
impl AsyncRead for AddrStream { impl AsyncRead for AddrStream {
#[inline] #[inline]
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
@@ -254,20 +234,36 @@ mod addr_stream {
} }
#[inline] #[inline]
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
self.inner.read_buf(buf) Pin::new(&mut self.inner).poll_read(cx, buf)
}
#[inline]
fn poll_read_buf<B: BufMut>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_read_buf(cx, buf)
} }
} }
impl AsyncWrite for AddrStream { impl AsyncWrite for AddrStream {
#[inline] #[inline]
fn shutdown(&mut self) -> Poll<(), io::Error> { fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
AsyncWrite::shutdown(&mut self.inner) Pin::new(&mut self.inner).poll_write(cx, buf)
} }
#[inline] #[inline]
fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { fn poll_write_buf<B: Buf>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> {
self.inner.write_buf(buf) Pin::new(&mut self.inner).poll_write_buf(cx, buf)
}
#[inline]
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
// TCP flush is a noop
Poll::Ready(Ok(()))
}
#[inline]
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_shutdown(cx)
} }
} }
} }

View File

@@ -1,13 +1,12 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
use futures::{Async, Future, IntoFuture, Poll};
use crate::body::Payload; use crate::body::Payload;
use crate::common::{Future, Poll, task};
use super::Service; use super::Service;
/// An asynchronous constructor of `Service`s. /// An asynchronous constructor of `Service`s.
pub trait MakeService<Ctx> { pub trait MakeService<Target> {
/// The `Payload` body of the `http::Request`. /// The `Payload` body of the `http::Request`.
type ReqBody: Payload; type ReqBody: Payload;
@@ -25,7 +24,7 @@ pub trait MakeService<Ctx> {
>; >;
/// The future returned from `new_service` of a `Service`. /// The future returned from `new_service` of a `Service`.
type Future: Future<Item=Self::Service, Error=Self::MakeError>; type Future: Future<Output=Result<Self::Service, Self::MakeError>>;
/// The error type that can be returned when creating a new `Service`. /// The error type that can be returned when creating a new `Service`.
type MakeError: Into<Box<dyn StdError + Send + Sync>>; type MakeError: Into<Box<dyn StdError + Send + Sync>>;
@@ -35,18 +34,18 @@ pub trait MakeService<Ctx> {
/// The implementation of this method is allowed to return a `Ready` even if /// The implementation of this method is allowed to return a `Ready` even if
/// the factory is not ready to create a new service. In this case, the future /// the factory is not ready to create a new service. In this case, the future
/// returned from `make_service` will resolve to an error. /// returned from `make_service` will resolve to an error.
fn poll_ready(&mut self) -> Poll<(), Self::MakeError> { fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>> {
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
/// Create a new `Service`. /// Create a new `Service`.
fn make_service(&mut self, ctx: Ctx) -> Self::Future; fn make_service(&mut self, target: Target) -> Self::Future;
} }
// Just a sort-of "trait alias" of `MakeService`, not to be implemented // Just a sort-of "trait alias" of `MakeService`, not to be implemented
// by anyone, only used as bounds. // by anyone, only used as bounds.
#[doc(hidden)] #[doc(hidden)]
pub trait MakeServiceRef<Ctx>: self::sealed::Sealed<Ctx> { pub trait MakeServiceRef<Target>: self::sealed::Sealed<Target> {
type ReqBody: Payload; type ReqBody: Payload;
type ResBody: Payload; type ResBody: Payload;
type Error: Into<Box<dyn StdError + Send + Sync>>; type Error: Into<Box<dyn StdError + Send + Sync>>;
@@ -56,7 +55,7 @@ pub trait MakeServiceRef<Ctx>: self::sealed::Sealed<Ctx> {
Error=Self::Error, Error=Self::Error,
>; >;
type MakeError: Into<Box<dyn StdError + Send + Sync>>; type MakeError: Into<Box<dyn StdError + Send + Sync>>;
type Future: Future<Item=Self::Service, Error=Self::MakeError>; type Future: Future<Output=Result<Self::Service, Self::MakeError>>;
// Acting like a #[non_exhaustive] for associated types of this trait. // Acting like a #[non_exhaustive] for associated types of this trait.
// //
@@ -69,18 +68,18 @@ pub trait MakeServiceRef<Ctx>: self::sealed::Sealed<Ctx> {
// if necessary. // if necessary.
type __DontNameMe: self::sealed::CantImpl; type __DontNameMe: self::sealed::CantImpl;
fn poll_ready_ref(&mut self) -> Poll<(), Self::MakeError>; fn poll_ready_ref(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>>;
fn make_service_ref(&mut self, ctx: &Ctx) -> Self::Future; fn make_service_ref(&mut self, target: &Target) -> Self::Future;
} }
impl<T, Ctx, E, ME, S, F, IB, OB> MakeServiceRef<Ctx> for T impl<T, Target, E, ME, S, F, IB, OB> MakeServiceRef<Target> for T
where where
T: for<'a> MakeService<&'a Ctx, Error=E, MakeError=ME, Service=S, Future=F, ReqBody=IB, ResBody=OB>, T: for<'a> MakeService<&'a Target, Error=E, MakeError=ME, Service=S, Future=F, ReqBody=IB, ResBody=OB>,
E: Into<Box<dyn StdError + Send + Sync>>, E: Into<Box<dyn StdError + Send + Sync>>,
ME: Into<Box<dyn StdError + Send + Sync>>, ME: Into<Box<dyn StdError + Send + Sync>>,
S: Service<ReqBody=IB, ResBody=OB, Error=E>, S: Service<ReqBody=IB, ResBody=OB, Error=E>,
F: Future<Item=S, Error=ME>, F: Future<Output=Result<S, ME>>,
IB: Payload, IB: Payload,
OB: Payload, OB: Payload,
{ {
@@ -93,22 +92,22 @@ where
type __DontNameMe = self::sealed::CantName; type __DontNameMe = self::sealed::CantName;
fn poll_ready_ref(&mut self) -> Poll<(), Self::MakeError> { fn poll_ready_ref(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>> {
self.poll_ready() self.poll_ready(cx)
} }
fn make_service_ref(&mut self, ctx: &Ctx) -> Self::Future { fn make_service_ref(&mut self, target: &Target) -> Self::Future {
self.make_service(ctx) self.make_service(target)
} }
} }
impl<T, Ctx, E, ME, S, F, IB, OB> self::sealed::Sealed<Ctx> for T impl<T, Target, E, ME, S, F, IB, OB> self::sealed::Sealed<Target> for T
where where
T: for<'a> MakeService<&'a Ctx, Error=E, MakeError=ME, Service=S, Future=F, ReqBody=IB, ResBody=OB>, T: for<'a> MakeService<&'a Target, Error=E, MakeError=ME, Service=S, Future=F, ReqBody=IB, ResBody=OB>,
E: Into<Box<dyn StdError + Send + Sync>>, E: Into<Box<dyn StdError + Send + Sync>>,
ME: Into<Box<dyn StdError + Send + Sync>>, ME: Into<Box<dyn StdError + Send + Sync>>,
S: Service<ReqBody=IB, ResBody=OB, Error=E>, S: Service<ReqBody=IB, ResBody=OB, Error=E>,
F: Future<Item=S, Error=ME>, F: Future<Output=Result<S, ME>>,
IB: Payload, IB: Payload,
OB: Payload, OB: Payload,
{} {}
@@ -146,10 +145,10 @@ where
/// # } /// # }
/// # #[cfg(not(feature = "runtime"))] fn main() {} /// # #[cfg(not(feature = "runtime"))] fn main() {}
/// ``` /// ```
pub fn make_service_fn<F, Ctx, Ret>(f: F) -> MakeServiceFn<F> pub fn make_service_fn<F, Target, Ret>(f: F) -> MakeServiceFn<F>
where where
F: FnMut(&Ctx) -> Ret, F: FnMut(&Target) -> Ret,
Ret: IntoFuture, Ret: Future,
{ {
MakeServiceFn { MakeServiceFn {
f, f,
@@ -161,24 +160,24 @@ pub struct MakeServiceFn<F> {
f: F, f: F,
} }
impl<'c, F, Ctx, Ret, ReqBody, ResBody> MakeService<&'c Ctx> for MakeServiceFn<F> impl<'t, F, Target, Ret, ReqBody, ResBody, Svc, MkErr> MakeService<&'t Target> for MakeServiceFn<F>
where where
F: FnMut(&Ctx) -> Ret, F: FnMut(&Target) -> Ret,
Ret: IntoFuture, Ret: Future<Output=Result<Svc, MkErr>>,
Ret::Item: Service<ReqBody=ReqBody, ResBody=ResBody>, Svc: Service<ReqBody=ReqBody, ResBody=ResBody>,
Ret::Error: Into<Box<dyn StdError + Send + Sync>>, MkErr: Into<Box<dyn StdError + Send + Sync>>,
ReqBody: Payload, ReqBody: Payload,
ResBody: Payload, ResBody: Payload,
{ {
type ReqBody = ReqBody; type ReqBody = ReqBody;
type ResBody = ResBody; type ResBody = ResBody;
type Error = <Ret::Item as Service>::Error; type Error = Svc::Error;
type Service = Ret::Item; type Service = Svc;
type Future = Ret::Future; type Future = Ret;
type MakeError = Ret::Error; type MakeError = MkErr;
fn make_service(&mut self, ctx: &'c Ctx) -> Self::Future { fn make_service(&mut self, target: &'t Target) -> Self::Future {
(self.f)(ctx).into_future() (self.f)(target)
} }
} }

View File

@@ -31,11 +31,7 @@
//! is called. //! is called.
mod make_service; mod make_service;
mod new_service;
mod service; mod service;
pub use self::make_service::{make_service_fn, MakeService, MakeServiceRef}; pub use self::make_service::{make_service_fn, MakeService, MakeServiceRef};
// NewService is soft-deprecated. pub use self::service::{service_fn, Service};
#[doc(hidden)]
pub use self::new_service::NewService;
pub use self::service::{service_fn, service_fn_ok, Service};

View File

@@ -1,79 +0,0 @@
use std::error::Error as StdError;
use futures::{Async, Future, IntoFuture, Poll};
use crate::body::Payload;
use super::{MakeService, Service};
/// An asynchronous constructor of `Service`s.
pub trait NewService {
/// The `Payload` body of the `http::Request`.
type ReqBody: Payload;
/// The `Payload` body of the `http::Response`.
type ResBody: Payload;
/// The error type that can be returned by `Service`s.
type Error: Into<Box<dyn StdError + Send + Sync>>;
/// The resolved `Service` from `new_service()`.
type Service: Service<
ReqBody=Self::ReqBody,
ResBody=Self::ResBody,
Error=Self::Error,
>;
/// The future returned from `new_service` of a `Service`.
type Future: Future<Item=Self::Service, Error=Self::InitError>;
/// The error type that can be returned when creating a new `Service`.
type InitError: Into<Box<dyn StdError + Send + Sync>>;
#[doc(hidden)]
fn poll_ready(&mut self) -> Poll<(), Self::InitError> {
Ok(Async::Ready(()))
}
/// Create a new `Service`.
fn new_service(&self) -> Self::Future;
}
impl<F, R, S> NewService for F
where
F: Fn() -> R,
R: IntoFuture<Item=S>,
R::Error: Into<Box<dyn StdError + Send + Sync>>,
S: Service,
{
type ReqBody = S::ReqBody;
type ResBody = S::ResBody;
type Error = S::Error;
type Service = S;
type Future = R::Future;
type InitError = R::Error;
fn new_service(&self) -> Self::Future {
(*self)().into_future()
}
}
impl<N, Ctx> MakeService<Ctx> for N
where
N: NewService,
{
type ReqBody = N::ReqBody;
type ResBody = N::ResBody;
type Error = N::Error;
type Service = N::Service;
type Future = N::Future;
type MakeError = N::InitError;
fn poll_ready(&mut self) -> Poll<(), Self::MakeError> {
NewService::poll_ready(self)
}
fn make_service(&mut self, _: Ctx) -> Self::Future {
self.new_service()
}
}

View File

@@ -2,10 +2,8 @@ use std::error::Error as StdError;
use std::fmt; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{future, Async, Future, IntoFuture, Poll};
use crate::body::Payload; use crate::body::Payload;
use crate::common::Never; use crate::common::{Future, Never, Poll, task};
use crate::{Request, Response}; use crate::{Request, Response};
/// An asynchronous function from `Request` to `Response`. /// An asynchronous function from `Request` to `Response`.
@@ -24,15 +22,15 @@ pub trait Service {
type Error: Into<Box<dyn StdError + Send + Sync>>; type Error: Into<Box<dyn StdError + Send + Sync>>;
/// The `Future` returned by this `Service`. /// The `Future` returned by this `Service`.
type Future: Future<Item=Response<Self::ResBody>, Error=Self::Error>; type Future: Future<Output=Result<Response<Self::ResBody>, Self::Error>>;
/// Returns `Ready` when the service is able to process requests. /// Returns `Ready` when the service is able to process requests.
/// ///
/// The implementation of this method is allowed to return a `Ready` even if /// The implementation of this method is allowed to return a `Ready` even if
/// the service is not ready to process. In this case, the future returned /// the service is not ready to process. In this case, the future returned
/// from `call` will resolve to an error. /// from `call` will resolve to an error.
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
/// Calls this `Service` with a request, returning a `Future` of the response. /// Calls this `Service` with a request, returning a `Future` of the response.
@@ -61,7 +59,7 @@ pub trait Service {
pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R> pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R>
where where
F: FnMut(Request<R>) -> S, F: FnMut(Request<R>) -> S,
S: IntoFuture, S: Future,
{ {
ServiceFn { ServiceFn {
f, f,
@@ -69,61 +67,27 @@ where
} }
} }
/// Create a `Service` from a function that never errors.
///
/// # Example
///
/// ```rust
/// use hyper::{Body, Request, Response};
/// use hyper::service::service_fn_ok;
///
/// let service = service_fn_ok(|req: Request<Body>| {
/// println!("request: {} {}", req.method(), req.uri());
/// Response::new(Body::from("Hello World"))
/// });
/// ```
pub fn service_fn_ok<F, R, S>(f: F) -> ServiceFnOk<F, R>
where
F: FnMut(Request<R>) -> Response<S>,
S: Payload,
{
ServiceFnOk {
f,
_req: PhantomData,
}
}
// Not exported from crate as this will likely be replaced with `impl Service`. // Not exported from crate as this will likely be replaced with `impl Service`.
pub struct ServiceFn<F, R> { pub struct ServiceFn<F, R> {
f: F, f: F,
_req: PhantomData<fn(R)>, _req: PhantomData<fn(R)>,
} }
impl<F, ReqBody, Ret, ResBody> Service for ServiceFn<F, ReqBody> impl<F, ReqBody, Ret, ResBody, E> Service for ServiceFn<F, ReqBody>
where where
F: FnMut(Request<ReqBody>) -> Ret, F: FnMut(Request<ReqBody>) -> Ret,
ReqBody: Payload, ReqBody: Payload,
Ret: IntoFuture<Item=Response<ResBody>>, Ret: Future<Output=Result<Response<ResBody>, E>>,
Ret::Error: Into<Box<dyn StdError + Send + Sync>>, E: Into<Box<dyn StdError + Send + Sync>>,
ResBody: Payload, ResBody: Payload,
{ {
type ReqBody = ReqBody; type ReqBody = ReqBody;
type ResBody = ResBody; type ResBody = ResBody;
type Error = Ret::Error; type Error = E;
type Future = Ret::Future; type Future = Ret;
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future { fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
(self.f)(req).into_future() (self.f)(req)
}
}
impl<F, R> IntoFuture for ServiceFn<F, R> {
type Future = future::FutureResult<Self::Item, Self::Error>;
type Item = Self;
type Error = Never;
fn into_future(self) -> Self::Future {
future::ok(self)
} }
} }
@@ -133,63 +97,3 @@ impl<F, R> fmt::Debug for ServiceFn<F, R> {
.finish() .finish()
} }
} }
// Not exported from crate as this will likely be replaced with `impl Service`.
pub struct ServiceFnOk<F, R> {
f: F,
_req: PhantomData<fn(R)>,
}
impl<F, ReqBody, ResBody> Service for ServiceFnOk<F, ReqBody>
where
F: FnMut(Request<ReqBody>) -> Response<ResBody>,
ReqBody: Payload,
ResBody: Payload,
{
type ReqBody = ReqBody;
type ResBody = ResBody;
type Error = Never;
type Future = future::FutureResult<Response<ResBody>, Never>;
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
future::ok((self.f)(req))
}
}
impl<F, R> IntoFuture for ServiceFnOk<F, R> {
type Future = future::FutureResult<Self::Item, Self::Error>;
type Item = Self;
type Error = Never;
fn into_future(self) -> Self::Future {
future::ok(self)
}
}
impl<F, R> fmt::Debug for ServiceFnOk<F, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("impl Service")
.finish()
}
}
//#[cfg(test)]
fn _assert_fn_mut() {
fn assert_service<T: Service>(_t: &T) {}
let mut val = 0;
let svc = service_fn(move |_req: Request<crate::Body>| {
val += 1;
future::ok::<_, Never>(Response::new(crate::Body::empty()))
});
assert_service(&svc);
let svc = service_fn_ok(move |_req: Request<crate::Body>| {
val += 1;
Response::new(crate::Body::empty())
});
assert_service(&svc);
}

View File

@@ -8,14 +8,15 @@
use std::any::TypeId; use std::any::TypeId;
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
use std::io::{self, Read, Write}; use std::io;
use std::marker::Unpin;
use bytes::{Buf, BufMut, Bytes}; use bytes::{/*Buf, BufMut, */Bytes};
use futures::{Async, Future, Poll};
use futures::sync::oneshot;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_sync::oneshot;
use crate::common::io::Rewind; use crate::common::io::Rewind;
use crate::common::{Future, Pin, Poll, task};
/// An upgraded HTTP connection. /// An upgraded HTTP connection.
/// ///
@@ -79,7 +80,7 @@ pub(crate) fn pending() -> (Pending, OnUpgrade) {
) )
} }
pub(crate) trait Io: AsyncRead + AsyncWrite + 'static { pub(crate) trait Io: AsyncRead + AsyncWrite + Unpin + 'static {
fn __hyper_type_id(&self) -> TypeId { fn __hyper_type_id(&self) -> TypeId {
TypeId::of::<Self>() TypeId::of::<Self>()
} }
@@ -104,7 +105,7 @@ impl dyn Io + Send {
} }
} }
impl<T: AsyncRead + AsyncWrite + 'static> Io for T {} impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Io for T {}
// ===== impl Upgraded ===== // ===== impl Upgraded =====
@@ -119,7 +120,7 @@ impl Upgraded {
/// ///
/// On success, returns the downcasted parts. On error, returns the /// On success, returns the downcasted parts. On error, returns the
/// `Upgraded` back. /// `Upgraded` back.
pub fn downcast<T: AsyncRead + AsyncWrite + 'static>(self) -> Result<Parts<T>, Self> { pub fn downcast<T: AsyncRead + AsyncWrite + Unpin + 'static>(self) -> Result<Parts<T>, Self> {
let (io, buf) = self.io.into_inner(); let (io, buf) = self.io.into_inner();
match io.__hyper_downcast() { match io.__hyper_downcast() {
Ok(t) => Ok(Parts { Ok(t) => Ok(Parts {
@@ -134,46 +135,27 @@ impl Upgraded {
} }
} }
impl Read for Upgraded {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.io.read(buf)
}
}
impl Write for Upgraded {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.io.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.io.flush()
}
}
impl AsyncRead for Upgraded { impl AsyncRead for Upgraded {
#[inline]
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.io.prepare_uninitialized_buffer(buf) self.io.prepare_uninitialized_buffer(buf)
} }
#[inline] fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { Pin::new(&mut self.io).poll_read(cx, buf)
self.io.read_buf(buf)
} }
} }
impl AsyncWrite for Upgraded { impl AsyncWrite for Upgraded {
#[inline] fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
fn shutdown(&mut self) -> Poll<(), io::Error> { Pin::new(&mut self.io).poll_write(cx, buf)
AsyncWrite::shutdown(&mut self.io)
} }
#[inline] fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { Pin::new(&mut self.io).poll_flush(cx)
self.io.write_buf(buf) }
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.io).poll_shutdown(cx)
} }
} }
@@ -199,20 +181,18 @@ impl OnUpgrade {
} }
impl Future for OnUpgrade { impl Future for OnUpgrade {
type Item = Upgraded; type Output = Result<Upgraded, crate::Error>;
type Error = crate::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
match self.rx { match self.rx {
Some(ref mut rx) => match rx.poll() { Some(ref mut rx) => Pin::new(rx).poll(cx).map(|res| match res {
Ok(Async::NotReady) => Ok(Async::NotReady), Ok(Ok(upgraded)) => Ok(upgraded),
Ok(Async::Ready(Ok(upgraded))) => Ok(Async::Ready(upgraded)), Ok(Err(err)) => Err(err),
Ok(Async::Ready(Err(err))) => Err(err),
Err(_oneshot_canceled) => Err( Err(_oneshot_canceled) => Err(
crate::Error::new_canceled().with(UpgradeExpected(())) crate::Error::new_canceled().with(UpgradeExpected(()))
), ),
}, }),
None => Err(crate::Error::new_user_no_upgrade()), None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())),
} }
} }
} }