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:
@@ -3,12 +3,12 @@ use std::io::{self};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
use futures::{Async, Poll};
|
||||
use http::{HeaderMap, Method, Version};
|
||||
use http::header::{HeaderValue, CONNECTION};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use crate::Chunk;
|
||||
use crate::common::{Pin, Poll, Unpin, task};
|
||||
use crate::proto::{BodyLength, DecodedLength, MessageHead};
|
||||
use crate::headers::connection_keep_alive;
|
||||
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> {
|
||||
io: Buffered<I, EncodedBuf<B>>,
|
||||
state: State,
|
||||
_marker: PhantomData<T>
|
||||
_marker: PhantomData<fn(T)>
|
||||
}
|
||||
|
||||
impl<I, B, T> Conn<I, B, T>
|
||||
where I: AsyncRead + AsyncWrite,
|
||||
where I: AsyncRead + AsyncWrite + Unpin,
|
||||
B: Buf,
|
||||
T: Http1Transaction,
|
||||
{
|
||||
@@ -129,16 +129,15 @@ where I: AsyncRead + AsyncWrite,
|
||||
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());
|
||||
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,
|
||||
req_method: &mut self.state.method,
|
||||
}) {
|
||||
Ok(Async::Ready(msg)) => msg,
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
})) {
|
||||
Ok(msg) => msg,
|
||||
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");
|
||||
self.state.reading = Reading::KeepAlive;
|
||||
if !T::should_read_first() {
|
||||
self.try_keep_alive();
|
||||
self.try_keep_alive(cx);
|
||||
}
|
||||
} else {
|
||||
if msg.expect_continue {
|
||||
@@ -165,10 +164,10 @@ where I: AsyncRead + AsyncWrite,
|
||||
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
|
||||
// message should be reported as an error. If not, it is just
|
||||
// the connection closing gracefully.
|
||||
@@ -179,25 +178,28 @@ where I: AsyncRead + AsyncWrite,
|
||||
if was_mid_parse || must_error {
|
||||
// We check if the buf contains the h2 Preface
|
||||
debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len());
|
||||
self.on_parse_error(e)
|
||||
.map(|()| Async::NotReady)
|
||||
match self.on_parse_error(e) {
|
||||
Ok(()) => Poll::Pending, // XXX: wat?
|
||||
Err(e) => Poll::Ready(Some(Err(e))),
|
||||
|
||||
}
|
||||
} else {
|
||||
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());
|
||||
|
||||
let (reading, ret) = match self.state.reading {
|
||||
Reading::Body(ref mut decoder) => {
|
||||
match decoder.decode(&mut self.io) {
|
||||
Ok(Async::Ready(slice)) => {
|
||||
match decoder.decode(cx, &mut self.io) {
|
||||
Poll::Ready(Ok(slice)) => {
|
||||
let (reading, chunk) = if decoder.is_eof() {
|
||||
debug!("incoming body completed");
|
||||
(Reading::KeepAlive, if !slice.is_empty() {
|
||||
Some(Chunk::from(slice))
|
||||
Some(Ok(Chunk::from(slice)))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@@ -208,14 +210,14 @@ where I: AsyncRead + AsyncWrite,
|
||||
// an empty slice...
|
||||
(Reading::Closed, None)
|
||||
} 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),
|
||||
Err(e) => {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(Err(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.try_keep_alive();
|
||||
self.try_keep_alive(cx);
|
||||
ret
|
||||
}
|
||||
|
||||
@@ -233,13 +235,13 @@ where I: AsyncRead + AsyncWrite,
|
||||
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());
|
||||
|
||||
if self.is_mid_message() {
|
||||
self.mid_message_detect_eof()
|
||||
self.mid_message_detect_eof(cx)
|
||||
} 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
|
||||
// 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.is_mid_message());
|
||||
debug_assert!(T::is_client());
|
||||
|
||||
if !self.io.read_buf().is_empty() {
|
||||
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 {
|
||||
let ret = if self.should_error_on_eof() {
|
||||
trace!("found unexpected EOF on busy connection: {:?}", self.state);
|
||||
Err(crate::Error::new_incomplete())
|
||||
Poll::Ready(Err(crate::Error::new_incomplete()))
|
||||
} else {
|
||||
trace!("found EOF on idle connection, closing");
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
};
|
||||
|
||||
// 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);
|
||||
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.is_mid_message());
|
||||
|
||||
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 {
|
||||
trace!("found unexpected EOF on busy connection: {:?}", self.state);
|
||||
self.state.close_read();
|
||||
Err(crate::Error::new_incomplete())
|
||||
Poll::Ready(Err(crate::Error::new_incomplete()))
|
||||
} else {
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn force_io_read(&mut self) -> Poll<usize, io::Error> {
|
||||
self.io.read_from_io().map_err(|e| {
|
||||
fn force_io_read(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<usize>> {
|
||||
let result = ready!(self.io.poll_read_from_io(cx));
|
||||
Poll::Ready(result.map_err(|e| {
|
||||
trace!("force_io_read; io error = {:?}", e);
|
||||
self.state.close();
|
||||
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
|
||||
// exhausted the underlying Io. We would have done this when we
|
||||
// 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.read_buf().is_empty() {
|
||||
match self.io.read_from_io() {
|
||||
Ok(Async::Ready(_)) => (),
|
||||
Ok(Async::NotReady) => {
|
||||
match self.io.poll_read_from_io(cx) {
|
||||
Poll::Ready(Ok(_)) => (),
|
||||
Poll::Pending => {
|
||||
trace!("maybe_notify; read_from_io blocked");
|
||||
return
|
||||
},
|
||||
Err(e) => {
|
||||
Poll::Ready(Err(e)) => {
|
||||
trace!("maybe_notify; read_from_io error: {}", e);
|
||||
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.maybe_notify();
|
||||
self.maybe_notify(cx);
|
||||
}
|
||||
|
||||
pub fn can_write_head(&self) -> bool {
|
||||
@@ -586,23 +589,22 @@ where I: AsyncRead + AsyncWrite,
|
||||
Err(err)
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Poll<(), io::Error> {
|
||||
try_ready!(self.io.flush());
|
||||
self.try_keep_alive();
|
||||
pub fn poll_flush(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
|
||||
ready!(Pin::new(&mut self.io).poll_flush(cx))?;
|
||||
self.try_keep_alive(cx);
|
||||
trace!("flushed({}): {:?}", T::LOG, self.state);
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) -> Poll<(), io::Error> {
|
||||
match self.io.io_mut().shutdown() {
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Ok(Async::Ready(())) => {
|
||||
pub fn poll_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
|
||||
match ready!(Pin::new(self.io.io_mut()).poll_shutdown(cx)) {
|
||||
Ok(()) => {
|
||||
trace!("shut down IO complete");
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
Poll::Ready(Ok(()))
|
||||
},
|
||||
Err(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 {
|
||||
allow_half_close: bool,
|
||||
/// Re-usable HeaderMap to reduce allocating new ones.
|
||||
|
||||
@@ -3,9 +3,10 @@ use std::fmt;
|
||||
use std::usize;
|
||||
use std::io;
|
||||
|
||||
use futures::{Async, Poll};
|
||||
use bytes::Bytes;
|
||||
|
||||
use crate::common::{Poll, task};
|
||||
|
||||
use super::io::MemRead;
|
||||
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);
|
||||
match self.kind {
|
||||
Length(ref mut remaining) => {
|
||||
if *remaining == 0 {
|
||||
Ok(Async::Ready(Bytes::new()))
|
||||
Poll::Ready(Ok(Bytes::new()))
|
||||
} else {
|
||||
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;
|
||||
if num > *remaining {
|
||||
*remaining = 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 {
|
||||
*remaining -= num;
|
||||
}
|
||||
Ok(Async::Ready(buf))
|
||||
Poll::Ready(Ok(buf))
|
||||
}
|
||||
}
|
||||
Chunked(ref mut state, ref mut size) => {
|
||||
loop {
|
||||
let mut buf = None;
|
||||
// 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 {
|
||||
trace!("end of chunked");
|
||||
return Ok(Async::Ready(Bytes::new()));
|
||||
return Poll::Ready(Ok(Bytes::new()));
|
||||
}
|
||||
if let Some(buf) = buf {
|
||||
return Ok(Async::Ready(buf));
|
||||
return Poll::Ready(Ok(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
Eof(ref mut is_eof) => {
|
||||
if *is_eof {
|
||||
Ok(Async::Ready(Bytes::new()))
|
||||
Poll::Ready(Ok(Bytes::new()))
|
||||
} else {
|
||||
// 8192 chosen because its about 2 packets, there probably
|
||||
// won't be that much available, so don't have MemReaders
|
||||
// allocate buffers to big
|
||||
let slice = try_ready!(body.read_mem(8192));
|
||||
*is_eof = slice.is_empty();
|
||||
Ok(Async::Ready(slice))
|
||||
body.read_mem(cx, 8192).map_ok(|slice| {
|
||||
*is_eof = slice.is_empty();
|
||||
slice
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,41 +153,42 @@ impl fmt::Debug for Decoder {
|
||||
}
|
||||
|
||||
macro_rules! byte (
|
||||
($rdr:ident) => ({
|
||||
let buf = try_ready!($rdr.read_mem(1));
|
||||
($rdr:ident, $cx:expr) => ({
|
||||
let buf = ready!($rdr.read_mem($cx, 1))?;
|
||||
if !buf.is_empty() {
|
||||
buf[0]
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
|
||||
"Unexpected eof during chunk size line"));
|
||||
return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF during chunk size line")));
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
impl ChunkedState {
|
||||
fn step<R: MemRead>(&self,
|
||||
cx: &mut task::Context<'_>,
|
||||
body: &mut R,
|
||||
size: &mut u64,
|
||||
buf: &mut Option<Bytes>)
|
||||
-> Poll<ChunkedState, io::Error> {
|
||||
-> Poll<Result<ChunkedState, io::Error>> {
|
||||
use self::ChunkedState::*;
|
||||
match *self {
|
||||
Size => ChunkedState::read_size(body, size),
|
||||
SizeLws => ChunkedState::read_size_lws(body),
|
||||
Extension => ChunkedState::read_extension(body),
|
||||
SizeLf => ChunkedState::read_size_lf(body, *size),
|
||||
Body => ChunkedState::read_body(body, size, buf),
|
||||
BodyCr => ChunkedState::read_body_cr(body),
|
||||
BodyLf => ChunkedState::read_body_lf(body),
|
||||
EndCr => ChunkedState::read_end_cr(body),
|
||||
EndLf => ChunkedState::read_end_lf(body),
|
||||
End => Ok(Async::Ready(ChunkedState::End)),
|
||||
Size => ChunkedState::read_size(cx, body, size),
|
||||
SizeLws => ChunkedState::read_size_lws(cx, body),
|
||||
Extension => ChunkedState::read_extension(cx, body),
|
||||
SizeLf => ChunkedState::read_size_lf(cx, body, *size),
|
||||
Body => ChunkedState::read_body(cx, body, size, buf),
|
||||
BodyCr => ChunkedState::read_body_cr(cx, body),
|
||||
BodyLf => ChunkedState::read_body_lf(cx, body),
|
||||
EndCr => ChunkedState::read_end_cr(cx, body),
|
||||
EndLf => ChunkedState::read_end_lf(cx, body),
|
||||
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");
|
||||
let radix = 16;
|
||||
match byte!(rdr) {
|
||||
match byte!(rdr, cx) {
|
||||
b @ b'0'..=b'9' => {
|
||||
*size *= radix;
|
||||
*size += (b - b'0') as u64;
|
||||
@@ -198,55 +201,55 @@ impl ChunkedState {
|
||||
*size *= radix;
|
||||
*size += (b + 10 - b'A') as u64;
|
||||
}
|
||||
b'\t' | b' ' => return Ok(Async::Ready(ChunkedState::SizeLws)),
|
||||
b';' => return Ok(Async::Ready(ChunkedState::Extension)),
|
||||
b'\r' => return Ok(Async::Ready(ChunkedState::SizeLf)),
|
||||
b'\t' | b' ' => return Poll::Ready(Ok(ChunkedState::SizeLws)),
|
||||
b';' => return Poll::Ready(Ok(ChunkedState::Extension)),
|
||||
b'\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)),
|
||||
_ => {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"Invalid chunk size line: Invalid Size"));
|
||||
return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"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");
|
||||
match byte!(rdr) {
|
||||
match byte!(rdr, cx) {
|
||||
// LWS can follow the chunk size, but no more digits can come
|
||||
b'\t' | b' ' => Ok(Async::Ready(ChunkedState::SizeLws)),
|
||||
b';' => Ok(Async::Ready(ChunkedState::Extension)),
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)),
|
||||
b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),
|
||||
b';' => Poll::Ready(Ok(ChunkedState::Extension)),
|
||||
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
|
||||
_ => {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"Invalid chunk size linear white space"))
|
||||
Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"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");
|
||||
match byte!(rdr) {
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)),
|
||||
_ => Ok(Async::Ready(ChunkedState::Extension)), // no supported extensions
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
|
||||
_ => 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);
|
||||
match byte!(rdr) {
|
||||
match byte!(rdr, cx) {
|
||||
b'\n' => {
|
||||
if size == 0 {
|
||||
Ok(Async::Ready(ChunkedState::EndCr))
|
||||
Poll::Ready(Ok(ChunkedState::EndCr))
|
||||
} else {
|
||||
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,
|
||||
buf: &mut Option<Bytes>)
|
||||
-> Poll<ChunkedState, io::Error> {
|
||||
-> Poll<Result<ChunkedState, io::Error>> {
|
||||
trace!("Chunked read, remaining={:?}", rem);
|
||||
|
||||
// cap remaining bytes at the max capacity of usize
|
||||
@@ -256,45 +259,45 @@ impl ChunkedState {
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
if count == 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);
|
||||
*rem -= count as u64;
|
||||
|
||||
if *rem > 0 {
|
||||
Ok(Async::Ready(ChunkedState::Body))
|
||||
Poll::Ready(Ok(ChunkedState::Body))
|
||||
} else {
|
||||
Ok(Async::Ready(ChunkedState::BodyCr))
|
||||
Poll::Ready(Ok(ChunkedState::BodyCr))
|
||||
}
|
||||
}
|
||||
fn read_body_cr<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> {
|
||||
match byte!(rdr) {
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::BodyLf)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR")),
|
||||
fn read_body_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Poll::Ready(Ok(ChunkedState::BodyLf)),
|
||||
_ => 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> {
|
||||
match byte!(rdr) {
|
||||
b'\n' => Ok(Async::Ready(ChunkedState::Size)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF")),
|
||||
fn read_body_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\n' => Poll::Ready(Ok(ChunkedState::Size)),
|
||||
_ => 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> {
|
||||
match byte!(rdr) {
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::EndLf)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR")),
|
||||
fn read_end_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Poll::Ready(Ok(ChunkedState::EndLf)),
|
||||
_ => 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> {
|
||||
match byte!(rdr) {
|
||||
b'\n' => Ok(Async::Ready(ChunkedState::End)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF")),
|
||||
fn read_end_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\n' => Poll::Ready(Ok(ChunkedState::End)),
|
||||
_ => Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,15 +329,15 @@ mod tests {
|
||||
use crate::mock::AsyncIo;
|
||||
|
||||
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());
|
||||
if n > 0 {
|
||||
let (a, b) = self.split_at(n);
|
||||
let mut buf = BytesMut::from(a);
|
||||
*self = b;
|
||||
Ok(Async::Ready(buf.split_to(n).freeze()))
|
||||
Poll::Ready(Ok(buf.split_to(n).freeze()))
|
||||
} else {
|
||||
Ok(Async::Ready(Bytes::new()))
|
||||
Poll::Ready(Ok(Bytes::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use std::error::Error as StdError;
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
use futures::{Async, Future, Poll, Stream};
|
||||
use http::{Request, Response, StatusCode};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use crate::body::{Body, Payload};
|
||||
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 super::Http1Transaction;
|
||||
use crate::service::Service;
|
||||
@@ -16,12 +15,8 @@ pub(crate) struct Dispatcher<D, Bs: Payload, I, T> {
|
||||
conn: Conn<I, Bs::Data, T>,
|
||||
dispatch: D,
|
||||
body_tx: Option<crate::body::Sender>,
|
||||
body_rx: Option<Bs>,
|
||||
body_rx: Pin<Box<Option<Bs>>>,
|
||||
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 {
|
||||
@@ -29,14 +24,14 @@ pub(crate) trait Dispatch {
|
||||
type PollBody;
|
||||
type PollError;
|
||||
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 poll_ready(&mut self) -> Poll<(), ()>;
|
||||
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>>;
|
||||
fn should_poll(&self) -> bool;
|
||||
}
|
||||
|
||||
pub struct Server<S: Service> {
|
||||
in_flight: Option<S::Future>,
|
||||
in_flight: Pin<Box<Option<S::Future>>>,
|
||||
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>
|
||||
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>>,
|
||||
I: AsyncRead + AsyncWrite,
|
||||
T: Http1Transaction,
|
||||
I: AsyncRead + AsyncWrite + Unpin,
|
||||
T: Http1Transaction + Unpin,
|
||||
Bs: Payload,
|
||||
{
|
||||
pub fn new(dispatch: D, conn: Conn<I, Bs::Data, T>) -> Self {
|
||||
@@ -60,9 +55,8 @@ where
|
||||
conn: conn,
|
||||
dispatch: dispatch,
|
||||
body_tx: None,
|
||||
body_rx: None,
|
||||
body_rx: Box::pin(None),
|
||||
is_closing: false,
|
||||
yield_now: YieldNow::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,55 +74,74 @@ where
|
||||
///
|
||||
/// This is useful for old-style HTTP upgrades, but ignores
|
||||
/// newer-style upgrade API.
|
||||
pub fn poll_without_shutdown(&mut self) -> Poll<(), crate::Error> {
|
||||
self.poll_catch(false)
|
||||
.map(|x| {
|
||||
x.map(|ds| if let Dispatched::Upgrade(pending) = ds {
|
||||
pending.manual();
|
||||
})
|
||||
})
|
||||
pub(crate) fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>>
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
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> {
|
||||
self.poll_inner(should_shutdown).or_else(|e| {
|
||||
fn poll_catch(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> {
|
||||
Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| {
|
||||
// An error means we're shutting down either way.
|
||||
// We just try to give the error to the user,
|
||||
// and close the connection with an Ok. If we
|
||||
// cannot give it to the user, then return the Err.
|
||||
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();
|
||||
|
||||
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 let Some(pending) = self.conn.pending_upgrade() {
|
||||
self.conn.take_error()?;
|
||||
return Ok(Async::Ready(Dispatched::Upgrade(pending)));
|
||||
return Poll::Ready(Ok(Dispatched::Upgrade(pending)));
|
||||
} 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()?;
|
||||
Ok(Async::Ready(Dispatched::Shutdown))
|
||||
Poll::Ready(Ok(Dispatched::Shutdown))
|
||||
} 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
|
||||
// often, so that other futures don't starve.
|
||||
//
|
||||
// 16 was chosen arbitrarily, as that is number of pipelined requests
|
||||
// benchmarks often use. Perhaps it should be a config option instead.
|
||||
for _ in 0..16 {
|
||||
self.poll_read()?;
|
||||
self.poll_write()?;
|
||||
self.poll_flush()?;
|
||||
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
|
||||
@@ -140,45 +153,39 @@ where
|
||||
// the Conn is noticeably faster in pipelined benchmarks.
|
||||
if !self.conn.wants_read_again() {
|
||||
//break;
|
||||
return Ok(Async::Ready(()));
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
}
|
||||
|
||||
trace!("poll_loop yielding (self = {:p})", self);
|
||||
|
||||
match self.yield_now.poll_yield() {
|
||||
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 {}
|
||||
}
|
||||
task::yield_now(cx).map(|never| match never {})
|
||||
}
|
||||
|
||||
fn poll_read(&mut self) -> Poll<(), crate::Error> {
|
||||
fn poll_read(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
|
||||
loop {
|
||||
if self.is_closing {
|
||||
return Ok(Async::Ready(()));
|
||||
return Poll::Ready(Ok(()));
|
||||
} 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() {
|
||||
if self.conn.can_read_body() {
|
||||
match body.poll_ready() {
|
||||
Ok(Async::Ready(())) => (),
|
||||
Ok(Async::NotReady) => {
|
||||
match body.poll_ready(cx) {
|
||||
Poll::Ready(Ok(())) => (),
|
||||
Poll::Pending => {
|
||||
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
|
||||
// so we should stop reading
|
||||
trace!("body receiver dropped before eof, closing");
|
||||
self.conn.close_read();
|
||||
return Ok(Async::Ready(()));
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
}
|
||||
match self.conn.read_body() {
|
||||
Ok(Async::Ready(Some(chunk))) => {
|
||||
match self.conn.poll_read_body(cx) {
|
||||
Poll::Ready(Some(Ok(chunk))) => {
|
||||
match body.send_data(chunk) {
|
||||
Ok(()) => {
|
||||
self.body_tx = Some(body);
|
||||
@@ -191,14 +198,14 @@ where
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(Async::Ready(None)) => {
|
||||
Poll::Ready(None) => {
|
||||
// just drop, the body will close automatically
|
||||
},
|
||||
Ok(Async::NotReady) => {
|
||||
Poll::Pending => {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -206,25 +213,24 @@ where
|
||||
// just drop, the body will close automatically
|
||||
}
|
||||
} 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?
|
||||
match self.dispatch.poll_ready() {
|
||||
Ok(Async::Ready(())) => (),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady), // service might not be ready
|
||||
match ready!(self.dispatch.poll_ready(cx)) {
|
||||
Ok(()) => (),
|
||||
Err(()) => {
|
||||
trace!("dispatch no longer receiving messages");
|
||||
self.close();
|
||||
return Ok(Async::Ready(()));
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
}
|
||||
// dispatch is ready for a message, try to read one
|
||||
match self.conn.read_head() {
|
||||
Ok(Async::Ready(Some((head, body_len, wants_upgrade)))) => {
|
||||
match ready!(self.conn.poll_read_head(cx)) {
|
||||
Some(Ok((head, body_len, wants_upgrade))) => {
|
||||
let mut body = match body_len {
|
||||
DecodedLength::ZERO => Body::empty(),
|
||||
other => {
|
||||
@@ -237,67 +243,78 @@ where
|
||||
body.set_on_upgrade(self.conn.on_upgrade());
|
||||
}
|
||||
self.dispatch.recv_msg(Ok((head, body)))?;
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
Ok(Async::Ready(None)) => {
|
||||
// read eof, conn will start to shutdown automatically
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Err(err) => {
|
||||
Poll::Ready(Ok(()))
|
||||
},
|
||||
Some(Err(err)) => {
|
||||
debug!("read_head error: {}", err);
|
||||
self.dispatch.recv_msg(Err(err))?;
|
||||
// if here, the dispatcher gave the user the error
|
||||
// somewhere else. we still need to shutdown, but
|
||||
// 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 {
|
||||
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() {
|
||||
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.
|
||||
//
|
||||
// If so, we can skip a bit of bookkeeping that streaming
|
||||
// bodies need to do.
|
||||
if let Some(full) = body.__hyper_full_data(FullDataArg(())).0 {
|
||||
self.conn.write_full_msg(head, full);
|
||||
return Ok(Async::Ready(()));
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
let body_type = if body.is_end_stream() {
|
||||
self.body_rx = None;
|
||||
self.body_rx.set(None);
|
||||
None
|
||||
} else {
|
||||
let btype = body.content_length()
|
||||
.map(BodyLength::Known)
|
||||
.or_else(|| Some(BodyLength::Unknown));
|
||||
self.body_rx = Some(body);
|
||||
self.body_rx.set(Some(body));
|
||||
btype
|
||||
};
|
||||
self.conn.write_head(head, body_type);
|
||||
} else {
|
||||
self.close();
|
||||
return Ok(Async::Ready(()));
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
} else if !self.conn.can_buffer_body() {
|
||||
try_ready!(self.poll_flush());
|
||||
} else if let Some(mut body) = self.body_rx.take() {
|
||||
if !self.conn.can_write_body() {
|
||||
trace!(
|
||||
"no more write body allowed, user body is_end_stream = {}",
|
||||
body.is_end_stream(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
match body.poll_data().map_err(crate::Error::new_user_body)? {
|
||||
Async::Ready(Some(chunk)) => {
|
||||
ready!(self.poll_flush(cx))?;
|
||||
} else {
|
||||
// A new scope is needed :(
|
||||
if let (Some(mut body), clear_body) = OptGuard::new(self.body_rx.as_mut()).guard_mut() {
|
||||
debug_assert!(!*clear_body, "opt guard defaults to keeping body");
|
||||
if !self.conn.can_write_body() {
|
||||
trace!(
|
||||
"no more write body allowed, user body is_end_stream = {}",
|
||||
body.is_end_stream(),
|
||||
);
|
||||
*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();
|
||||
if eos {
|
||||
*clear_body = true;
|
||||
if chunk.remaining() == 0 {
|
||||
trace!("discarding empty chunk");
|
||||
self.conn.end_body();
|
||||
@@ -305,30 +322,25 @@ where
|
||||
self.conn.write_body_and_end(chunk);
|
||||
}
|
||||
} else {
|
||||
self.body_rx = Some(body);
|
||||
if chunk.remaining() == 0 {
|
||||
trace!("discarding empty chunk");
|
||||
continue;
|
||||
}
|
||||
self.conn.write_body(chunk);
|
||||
}
|
||||
},
|
||||
Async::Ready(None) => {
|
||||
} else {
|
||||
*clear_body = true;
|
||||
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> {
|
||||
self.conn.flush().map_err(|err| {
|
||||
fn poll_flush(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
|
||||
self.conn.poll_flush(cx).map_err(|err| {
|
||||
debug!("error writing: {}", err);
|
||||
crate::Error::new_body_write(err)
|
||||
})
|
||||
@@ -360,35 +372,65 @@ where
|
||||
|
||||
impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T>
|
||||
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>>,
|
||||
I: AsyncRead + AsyncWrite,
|
||||
T: Http1Transaction,
|
||||
I: AsyncRead + AsyncWrite + Unpin,
|
||||
T: Http1Transaction + Unpin,
|
||||
Bs: Payload,
|
||||
{
|
||||
type Item = Dispatched;
|
||||
type Error = crate::Error;
|
||||
type Output = crate::Result<Dispatched>;
|
||||
|
||||
#[inline]
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
self.poll_catch(true)
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
|
||||
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<S> Server<S> where S: Service {
|
||||
impl<S> Server<S>
|
||||
where
|
||||
S: Service,
|
||||
{
|
||||
pub fn new(service: S) -> Server<S> {
|
||||
Server {
|
||||
in_flight: None,
|
||||
in_flight: Box::pin(None),
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_service(self) -> S {
|
||||
self.service
|
||||
}
|
||||
}
|
||||
|
||||
// Service is never pinned
|
||||
impl<S: Service> Unpin for Server<S> {}
|
||||
|
||||
impl<S, Bs> Dispatch for Server<S>
|
||||
where
|
||||
S: Service<ReqBody=Body, ResBody=Bs>,
|
||||
@@ -400,25 +442,23 @@ where
|
||||
type PollError = S::Error;
|
||||
type RecvItem = RequestHead;
|
||||
|
||||
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Self::PollBody)>, Self::PollError> {
|
||||
if let Some(mut fut) = self.in_flight.take() {
|
||||
let resp = match fut.poll()? {
|
||||
Async::Ready(res) => res,
|
||||
Async::NotReady => {
|
||||
self.in_flight = Some(fut);
|
||||
return Ok(Async::NotReady);
|
||||
}
|
||||
};
|
||||
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> {
|
||||
let ret = if let Some(ref mut fut) = self.in_flight.as_mut().as_pin_mut() {
|
||||
let resp = ready!(fut.as_mut().poll(cx)?);
|
||||
let (parts, body) = resp.into_parts();
|
||||
let head = MessageHead {
|
||||
version: parts.version,
|
||||
subject: parts.status,
|
||||
headers: parts.headers,
|
||||
};
|
||||
Ok(Async::Ready(Some((head, body))))
|
||||
Poll::Ready(Some(Ok((head, body))))
|
||||
} else {
|
||||
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<()> {
|
||||
@@ -428,15 +468,16 @@ where
|
||||
*req.uri_mut() = msg.subject.1;
|
||||
*req.headers_mut() = msg.headers;
|
||||
*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(())
|
||||
}
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), ()> {
|
||||
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> {
|
||||
if self.in_flight.is_some() {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
} else {
|
||||
self.service.poll_ready()
|
||||
self.service.poll_ready(cx)
|
||||
.map_err(|_e| {
|
||||
// FIXME: return error value.
|
||||
trace!("service closed");
|
||||
@@ -470,16 +511,16 @@ where
|
||||
type PollError = Never;
|
||||
type RecvItem = ResponseHead;
|
||||
|
||||
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Self::PollBody)>, Never> {
|
||||
match self.rx.poll() {
|
||||
Ok(Async::Ready(Some((req, mut cb)))) => {
|
||||
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> {
|
||||
match self.rx.poll_next(cx) {
|
||||
Poll::Ready(Some((req, mut cb))) => {
|
||||
// check that future hasn't been canceled already
|
||||
match cb.poll_cancel().expect("poll_cancel cannot error") {
|
||||
Async::Ready(()) => {
|
||||
match cb.poll_cancel(cx) {
|
||||
Poll::Ready(()) => {
|
||||
trace!("request canceled");
|
||||
Ok(Async::Ready(None))
|
||||
Poll::Ready(None)
|
||||
},
|
||||
Async::NotReady => {
|
||||
Poll::Pending => {
|
||||
let (parts, body) = req.into_parts();
|
||||
let head = RequestHead {
|
||||
version: parts.version,
|
||||
@@ -487,17 +528,16 @@ where
|
||||
headers: parts.headers,
|
||||
};
|
||||
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");
|
||||
// user has dropped sender handle
|
||||
Ok(Async::Ready(None))
|
||||
Poll::Ready(None)
|
||||
},
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Err(never) => match never {},
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,30 +562,32 @@ where
|
||||
if let Some(cb) = self.callback.take() {
|
||||
let _ = cb.send(Err((err, None)));
|
||||
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 {
|
||||
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 {
|
||||
Some(ref mut cb) => match cb.poll_cancel() {
|
||||
Ok(Async::Ready(())) => {
|
||||
Some(ref mut cb) => match cb.poll_cancel(cx) {
|
||||
Poll::Ready(()) => {
|
||||
trace!("callback receiver has dropped");
|
||||
Err(())
|
||||
Poll::Ready(Err(()))
|
||||
},
|
||||
Ok(Async::NotReady) => Ok(Async::Ready(())),
|
||||
Err(_) => unreachable!("oneshot poll_cancel cannot error"),
|
||||
Poll::Pending => Poll::Ready(Ok(())),
|
||||
},
|
||||
None => Err(()),
|
||||
None => Poll::Ready(Err(())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
use futures::{Async, Poll};
|
||||
use iovec::IoVec;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use crate::common::{Pin, Poll, Unpin, task};
|
||||
use super::{Http1Transaction, ParseContext, ParsedMessage};
|
||||
|
||||
/// The initial buffer size allocated before trying to read from IO.
|
||||
@@ -52,7 +52,7 @@ where
|
||||
|
||||
impl<T, B> Buffered<T, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
B: Buf,
|
||||
{
|
||||
pub fn new(io: T) -> Buffered<T, B> {
|
||||
@@ -135,57 +135,56 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse<S>(&mut self, ctx: ParseContext)
|
||||
-> Poll<ParsedMessage<S::Incoming>, crate::Error>
|
||||
pub(super) fn parse<S>(&mut self, cx: &mut task::Context<'_>, parse_ctx: ParseContext)
|
||||
-> Poll<crate::Result<ParsedMessage<S::Incoming>>>
|
||||
where
|
||||
S: Http1Transaction,
|
||||
{
|
||||
loop {
|
||||
match S::parse(&mut self.read_buf, ParseContext {
|
||||
cached_headers: ctx.cached_headers,
|
||||
req_method: ctx.req_method,
|
||||
cached_headers: parse_ctx.cached_headers,
|
||||
req_method: parse_ctx.req_method,
|
||||
})? {
|
||||
Some(msg) => {
|
||||
debug!("parsed {} headers", msg.head.headers.len());
|
||||
return Ok(Async::Ready(msg))
|
||||
return Poll::Ready(Ok(msg));
|
||||
},
|
||||
None => {
|
||||
let max = self.read_buf_strategy.max();
|
||||
if self.read_buf.len() >= 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 => {
|
||||
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;
|
||||
let next = self.read_buf_strategy.next();
|
||||
if self.read_buf.remaining_mut() < next {
|
||||
self.read_buf.reserve(next);
|
||||
}
|
||||
self.io.read_buf(&mut self.read_buf).map(|ok| {
|
||||
match ok {
|
||||
Async::Ready(n) => {
|
||||
match Pin::new(&mut self.io).poll_read_buf(cx, &mut self.read_buf) {
|
||||
Poll::Ready(Ok(n)) => {
|
||||
debug!("read {} bytes", n);
|
||||
self.read_buf_strategy.record(n);
|
||||
Async::Ready(n)
|
||||
Poll::Ready(Ok(n))
|
||||
},
|
||||
Async::NotReady => {
|
||||
self.read_blocked = true;
|
||||
Async::NotReady
|
||||
}
|
||||
Poll::Pending => {
|
||||
self.read_blocked = true;
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> (T, Bytes) {
|
||||
@@ -200,38 +199,37 @@ where
|
||||
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() {
|
||||
//Ok(())
|
||||
Poll::Ready(Ok(()))
|
||||
} else if self.write_buf.remaining() == 0 {
|
||||
try_nb!(self.io.flush());
|
||||
Pin::new(&mut self.io).poll_flush(cx)
|
||||
} else {
|
||||
match self.write_buf.strategy {
|
||||
WriteStrategy::Flatten => return self.flush_flattened(),
|
||||
WriteStrategy::Flatten => return self.poll_flush_flattened(cx),
|
||||
_ => (),
|
||||
}
|
||||
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);
|
||||
if self.write_buf.remaining() == 0 {
|
||||
break;
|
||||
} else if n == 0 {
|
||||
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.
|
||||
///
|
||||
/// Since all buffered bytes are flattened into the single headers buffer,
|
||||
/// 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 {
|
||||
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);
|
||||
self.write_buf.headers.advance(n);
|
||||
if self.write_buf.headers.remaining() == 0 {
|
||||
@@ -239,30 +237,33 @@ where
|
||||
break;
|
||||
} else if n == 0 {
|
||||
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());
|
||||
Ok(Async::Ready(()))
|
||||
Pin::new(&mut self.io).poll_flush(cx)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
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() {
|
||||
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 {
|
||||
let n = try_ready!(self.read_from_io());
|
||||
Ok(Async::Ready(self.read_buf.split_to(::std::cmp::min(len, n)).freeze()))
|
||||
let n = ready!(self.poll_read_from_io(cx))?;
|
||||
Poll::Ready(Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user