refactor(lib): convert to futures 0.2.0-beta (#1470)
This commit is contained in:
@@ -3,10 +3,10 @@ use std::io::{self};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures::{Async, AsyncSink, Poll, StartSend};
|
||||
use futures::task::Task;
|
||||
use futures::{Async, Poll};
|
||||
use futures::task;
|
||||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use http::{Method, Version};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use proto::{BodyLength, Chunk, Decode, Http1Transaction, MessageHead};
|
||||
use super::io::{Cursor, Buffered};
|
||||
@@ -113,14 +113,14 @@ where I: AsyncRead + AsyncWrite,
|
||||
T::should_error_on_parse_eof() && !self.state.is_idle()
|
||||
}
|
||||
|
||||
pub fn read_head(&mut self) -> Poll<Option<(MessageHead<T::Incoming>, bool)>, ::Error> {
|
||||
pub fn read_head(&mut self, cx: &mut task::Context) -> Poll<Option<(MessageHead<T::Incoming>, bool)>, ::Error> {
|
||||
debug_assert!(self.can_read_head());
|
||||
trace!("Conn::read_head");
|
||||
|
||||
loop {
|
||||
let (version, head) = match self.io.parse::<T>() {
|
||||
let (version, head) = match self.io.parse::<T>(cx) {
|
||||
Ok(Async::Ready(head)) => (head.version, head),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Ok(Async::Pending) => return Ok(Async::Pending),
|
||||
Err(e) => {
|
||||
// If we are currently waiting on a message, then an empty
|
||||
// message should be reported as an error. If not, it is just
|
||||
@@ -132,7 +132,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
return if was_mid_parse || must_error {
|
||||
debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len());
|
||||
self.on_parse_error(e)
|
||||
.map(|()| Async::NotReady)
|
||||
.map(|()| Async::Pending)
|
||||
} else {
|
||||
debug!("read eof");
|
||||
Ok(Async::Ready(None))
|
||||
@@ -169,7 +169,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
debug!("decoder error = {:?}", e);
|
||||
self.state.close_read();
|
||||
return self.on_parse_error(e)
|
||||
.map(|()| Async::NotReady);
|
||||
.map(|()| Async::Pending);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -193,20 +193,20 @@ where I: AsyncRead + AsyncWrite,
|
||||
self.state.reading = reading;
|
||||
}
|
||||
if !body {
|
||||
self.try_keep_alive();
|
||||
self.try_keep_alive(cx);
|
||||
}
|
||||
return Ok(Async::Ready(Some((head, body))));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_body(&mut self) -> Poll<Option<Chunk>, io::Error> {
|
||||
pub fn read_body(&mut self, cx: &mut task::Context) -> Poll<Option<Chunk>, io::Error> {
|
||||
debug_assert!(self.can_read_body());
|
||||
|
||||
trace!("Conn::read_body");
|
||||
|
||||
let (reading, ret) = match self.state.reading {
|
||||
Reading::Body(ref mut decoder) => {
|
||||
match decoder.decode(&mut self.io) {
|
||||
match decoder.decode(&mut self.io, cx) {
|
||||
Ok(Async::Ready(slice)) => {
|
||||
let (reading, chunk) = if !slice.is_empty() {
|
||||
return Ok(Async::Ready(Some(Chunk::from(slice))));
|
||||
@@ -222,7 +222,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
};
|
||||
(reading, Ok(Async::Ready(chunk)))
|
||||
},
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Ok(Async::Pending) => return Ok(Async::Pending),
|
||||
Err(e) => {
|
||||
trace!("decode stream error: {}", e);
|
||||
(Reading::Closed, Err(e))
|
||||
@@ -233,19 +233,19 @@ where I: AsyncRead + AsyncWrite,
|
||||
};
|
||||
|
||||
self.state.reading = reading;
|
||||
self.try_keep_alive();
|
||||
self.try_keep_alive(cx);
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn read_keep_alive(&mut self) -> Result<(), ::Error> {
|
||||
pub fn read_keep_alive(&mut self, cx: &mut task::Context) -> Result<(), ::Error> {
|
||||
debug_assert!(!self.can_read_head() && !self.can_read_body());
|
||||
|
||||
trace!("read_keep_alive; is_mid_message={}", self.is_mid_message());
|
||||
|
||||
if self.is_mid_message() {
|
||||
self.maybe_park_read();
|
||||
self.maybe_park_read(cx);
|
||||
} else {
|
||||
self.require_empty_read()?;
|
||||
self.require_empty_read(cx)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -257,18 +257,19 @@ where I: AsyncRead + AsyncWrite,
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_park_read(&mut self) {
|
||||
fn maybe_park_read(&mut self, cx: &mut task::Context) {
|
||||
if !self.io.is_read_blocked() {
|
||||
// the Io object is ready to read, which means it will never alert
|
||||
// us that it is ready until we drain it. However, we're currently
|
||||
// finished reading, so we need to park the task to be able to
|
||||
// wake back up later when more reading should happen.
|
||||
let current_waker = cx.waker();
|
||||
let park = self.state.read_task.as_ref()
|
||||
.map(|t| !t.will_notify_current())
|
||||
.map(|t| !t.will_wake(current_waker))
|
||||
.unwrap_or(true);
|
||||
if park {
|
||||
trace!("parking current task");
|
||||
self.state.read_task = Some(::futures::task::current());
|
||||
self.state.read_task = Some(current_waker.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,14 +278,14 @@ where I: AsyncRead + AsyncWrite,
|
||||
//
|
||||
// This should only be called for Clients wanting to enter the idle
|
||||
// state.
|
||||
fn require_empty_read(&mut self) -> io::Result<()> {
|
||||
fn require_empty_read(&mut self, cx: &mut task::Context) -> io::Result<()> {
|
||||
assert!(!self.can_read_head() && !self.can_read_body());
|
||||
|
||||
if !self.io.read_buf().is_empty() {
|
||||
debug!("received an unexpected {} bytes", self.io.read_buf().len());
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "unexpected bytes after message ended"))
|
||||
} else {
|
||||
match self.try_io_read()? {
|
||||
match self.try_io_read(cx)? {
|
||||
Async::Ready(0) => {
|
||||
// case handled in try_io_read
|
||||
Ok(())
|
||||
@@ -298,15 +299,15 @@ where I: AsyncRead + AsyncWrite,
|
||||
};
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, desc))
|
||||
},
|
||||
Async::NotReady => {
|
||||
Async::Pending => {
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_io_read(&mut self) -> Poll<usize, io::Error> {
|
||||
match self.io.read_from_io() {
|
||||
fn try_io_read(&mut self, cx: &mut task::Context) -> Poll<usize, io::Error> {
|
||||
match self.io.read_from_io(cx) {
|
||||
Ok(Async::Ready(0)) => {
|
||||
trace!("try_io_read; found EOF on connection: {:?}", self.state);
|
||||
let must_error = self.should_error_on_eof();
|
||||
@@ -328,8 +329,8 @@ where I: AsyncRead + AsyncWrite,
|
||||
Ok(Async::Ready(n)) => {
|
||||
Ok(Async::Ready(n))
|
||||
},
|
||||
Ok(Async::NotReady) => {
|
||||
Ok(Async::NotReady)
|
||||
Ok(Async::Pending) => {
|
||||
Ok(Async::Pending)
|
||||
},
|
||||
Err(e) => {
|
||||
self.state.close();
|
||||
@@ -339,8 +340,8 @@ where I: AsyncRead + AsyncWrite,
|
||||
}
|
||||
|
||||
|
||||
fn maybe_notify(&mut self) {
|
||||
// its possible that we returned NotReady from poll() without having
|
||||
fn maybe_notify(&mut self, cx: &mut task::Context) {
|
||||
// its possible that we returned Pending 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
|
||||
// would finish.
|
||||
@@ -366,9 +367,9 @@ where I: AsyncRead + AsyncWrite,
|
||||
|
||||
if !self.io.is_read_blocked() {
|
||||
if wants_read && self.io.read_buf().is_empty() {
|
||||
match self.io.read_from_io() {
|
||||
match self.io.read_from_io(cx) {
|
||||
Ok(Async::Ready(_)) => (),
|
||||
Ok(Async::NotReady) => {
|
||||
Ok(Async::Pending) => {
|
||||
trace!("maybe_notify; read_from_io blocked");
|
||||
return
|
||||
},
|
||||
@@ -380,16 +381,16 @@ where I: AsyncRead + AsyncWrite,
|
||||
}
|
||||
if let Some(ref task) = self.state.read_task {
|
||||
trace!("maybe_notify; notifying task");
|
||||
task.notify();
|
||||
task.wake();
|
||||
} else {
|
||||
trace!("maybe_notify; no task to notify");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_keep_alive(&mut self) {
|
||||
fn try_keep_alive(&mut self, cx: &mut task::Context) {
|
||||
self.state.try_keep_alive();
|
||||
self.maybe_notify();
|
||||
self.maybe_notify(cx);
|
||||
}
|
||||
|
||||
pub fn can_write_head(&self) -> bool {
|
||||
@@ -475,17 +476,15 @@ where I: AsyncRead + AsyncWrite,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_body(&mut self, chunk: Option<B>) -> StartSend<Option<B>, io::Error> {
|
||||
pub fn write_body(&mut self, _cx: &mut task::Context, chunk: Option<B>) -> Poll<(), io::Error> {
|
||||
debug_assert!(self.can_write_body());
|
||||
|
||||
if !self.can_buffer_body() {
|
||||
if let Async::NotReady = self.flush()? {
|
||||
// if chunk is Some(&[]), aka empty, whatever, just skip it
|
||||
if chunk.as_ref().map(|c| c.as_ref().is_empty()).unwrap_or(false) {
|
||||
return Ok(AsyncSink::Ready);
|
||||
} else {
|
||||
return Ok(AsyncSink::NotReady(chunk));
|
||||
}
|
||||
// if chunk is Some(&[]), aka empty, whatever, just skip it
|
||||
if chunk.as_ref().map(|c| c.as_ref().is_empty()).unwrap_or(true) {
|
||||
return Ok(Async::Ready(()));
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "tried to write chunk when body can't buffer"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,7 +492,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
Writing::Body(ref mut encoder) => {
|
||||
if let Some(chunk) = chunk {
|
||||
if chunk.as_ref().is_empty() {
|
||||
return Ok(AsyncSink::Ready);
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
|
||||
let encoded = encoder.encode(Cursor::new(chunk));
|
||||
@@ -506,7 +505,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
Writing::KeepAlive
|
||||
}
|
||||
} else {
|
||||
return Ok(AsyncSink::Ready);
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
} else {
|
||||
// end of stream, that means we should try to eof
|
||||
@@ -529,7 +528,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
};
|
||||
|
||||
self.state.writing = state;
|
||||
Ok(AsyncSink::Ready)
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
|
||||
// When we get a parse error, depending on what side we are, we might be able
|
||||
@@ -553,16 +552,16 @@ 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 flush(&mut self, cx: &mut task::Context) -> Poll<(), io::Error> {
|
||||
try_ready!(self.io.flush(cx));
|
||||
self.try_keep_alive(cx);
|
||||
trace!("flushed {:?}", self.state);
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) -> Poll<(), io::Error> {
|
||||
match self.io.io_mut().shutdown() {
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
pub fn shutdown(&mut self, cx: &mut task::Context) -> Poll<(), io::Error> {
|
||||
match self.io.io_mut().poll_close(cx) {
|
||||
Ok(Async::Pending) => Ok(Async::Pending),
|
||||
Ok(Async::Ready(())) => {
|
||||
trace!("shut down IO");
|
||||
Ok(Async::Ready(()))
|
||||
@@ -612,7 +611,7 @@ struct State {
|
||||
error: Option<::Error>,
|
||||
keep_alive: KA,
|
||||
method: Option<Method>,
|
||||
read_task: Option<Task>,
|
||||
read_task: Option<task::Waker>,
|
||||
reading: Reading,
|
||||
writing: Writing,
|
||||
version: Version,
|
||||
@@ -964,7 +963,7 @@ mod tests {
|
||||
}
|
||||
|
||||
match conn.poll() {
|
||||
Ok(Async::NotReady) => (),
|
||||
Ok(Async::Pending) => (),
|
||||
other => panic!("unexpected frame: {:?}", other)
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::usize;
|
||||
use std::io;
|
||||
|
||||
use futures::{Async, Poll};
|
||||
use futures::task;
|
||||
use bytes::Bytes;
|
||||
|
||||
use super::io::MemRead;
|
||||
@@ -84,7 +85,7 @@ impl Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode<R: MemRead>(&mut self, body: &mut R) -> Poll<Bytes, io::Error> {
|
||||
pub fn decode<R: MemRead>(&mut self, body: &mut R, cx: &mut task::Context) -> Poll<Bytes, io::Error> {
|
||||
trace!("decode; state={:?}", self.kind);
|
||||
match self.kind {
|
||||
Length(ref mut remaining) => {
|
||||
@@ -92,7 +93,7 @@ impl Decoder {
|
||||
Ok(Async::Ready(Bytes::new()))
|
||||
} else {
|
||||
let to_read = *remaining as usize;
|
||||
let buf = try_ready!(body.read_mem(to_read));
|
||||
let buf = try_ready!(body.read_mem(cx, to_read));
|
||||
let num = buf.as_ref().len() as u64;
|
||||
if num > *remaining {
|
||||
*remaining = 0;
|
||||
@@ -108,7 +109,7 @@ impl Decoder {
|
||||
loop {
|
||||
let mut buf = None;
|
||||
// advances the chunked state
|
||||
*state = try_ready!(state.step(body, size, &mut buf));
|
||||
*state = try_ready!(state.step(body, cx, size, &mut buf));
|
||||
if *state == ChunkedState::End {
|
||||
trace!("end of chunked");
|
||||
return Ok(Async::Ready(Bytes::new()));
|
||||
@@ -125,7 +126,7 @@ impl Decoder {
|
||||
// 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));
|
||||
let slice = try_ready!(body.read_mem(cx, 8192));
|
||||
*is_eof = slice.is_empty();
|
||||
Ok(Async::Ready(slice))
|
||||
}
|
||||
@@ -152,8 +153,8 @@ impl fmt::Display for Decoder {
|
||||
}
|
||||
|
||||
macro_rules! byte (
|
||||
($rdr:ident) => ({
|
||||
let buf = try_ready!($rdr.read_mem(1));
|
||||
($rdr:ident, $cx:ident) => ({
|
||||
let buf = try_ready!($rdr.read_mem($cx, 1));
|
||||
if !buf.is_empty() {
|
||||
buf[0]
|
||||
} else {
|
||||
@@ -166,27 +167,28 @@ macro_rules! byte (
|
||||
impl ChunkedState {
|
||||
fn step<R: MemRead>(&self,
|
||||
body: &mut R,
|
||||
cx: &mut task::Context,
|
||||
size: &mut u64,
|
||||
buf: &mut Option<Bytes>)
|
||||
-> Poll<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),
|
||||
Size => ChunkedState::read_size(body, cx, size),
|
||||
SizeLws => ChunkedState::read_size_lws(body, cx),
|
||||
Extension => ChunkedState::read_extension(body, cx),
|
||||
SizeLf => ChunkedState::read_size_lf(body, cx, *size),
|
||||
Body => ChunkedState::read_body(body, cx, size, buf),
|
||||
BodyCr => ChunkedState::read_body_cr(body, cx),
|
||||
BodyLf => ChunkedState::read_body_lf(body, cx),
|
||||
EndCr => ChunkedState::read_end_cr(body, cx),
|
||||
EndLf => ChunkedState::read_end_lf(body, cx),
|
||||
End => Ok(Async::Ready(ChunkedState::End)),
|
||||
}
|
||||
}
|
||||
fn read_size<R: MemRead>(rdr: &mut R, size: &mut u64) -> Poll<ChunkedState, io::Error> {
|
||||
fn read_size<R: MemRead>(rdr: &mut R, cx: &mut task::Context, size: &mut u64) -> Poll<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;
|
||||
@@ -209,9 +211,9 @@ impl ChunkedState {
|
||||
}
|
||||
Ok(Async::Ready(ChunkedState::Size))
|
||||
}
|
||||
fn read_size_lws<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> {
|
||||
fn read_size_lws<R: MemRead>(rdr: &mut R, cx: &mut task::Context) -> Poll<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)),
|
||||
@@ -222,16 +224,16 @@ impl ChunkedState {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn read_extension<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> {
|
||||
fn read_extension<R: MemRead>(rdr: &mut R, cx: &mut task::Context) -> Poll<ChunkedState, io::Error> {
|
||||
trace!("read_extension");
|
||||
match byte!(rdr) {
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)),
|
||||
_ => Ok(Async::Ready(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>(rdr: &mut R, cx: &mut task::Context, size: u64) -> Poll<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))
|
||||
@@ -244,7 +246,7 @@ impl ChunkedState {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_body<R: MemRead>(rdr: &mut R,
|
||||
fn read_body<R: MemRead>(rdr: &mut R, cx: &mut task::Context,
|
||||
rem: &mut u64,
|
||||
buf: &mut Option<Bytes>)
|
||||
-> Poll<ChunkedState, io::Error> {
|
||||
@@ -257,7 +259,7 @@ impl ChunkedState {
|
||||
};
|
||||
|
||||
let to_read = rem_cap;
|
||||
let slice = try_ready!(rdr.read_mem(to_read));
|
||||
let slice = try_ready!(rdr.read_mem(cx, to_read));
|
||||
let count = slice.len();
|
||||
|
||||
if count == 0 {
|
||||
@@ -273,27 +275,27 @@ impl ChunkedState {
|
||||
Ok(Async::Ready(ChunkedState::BodyCr))
|
||||
}
|
||||
}
|
||||
fn read_body_cr<R: MemRead>(rdr: &mut R) -> Poll<ChunkedState, io::Error> {
|
||||
match byte!(rdr) {
|
||||
fn read_body_cr<R: MemRead>(rdr: &mut R, cx: &mut task::Context) -> Poll<ChunkedState, io::Error> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::BodyLf)),
|
||||
_ => 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) {
|
||||
fn read_body_lf<R: MemRead>(rdr: &mut R, cx: &mut task::Context) -> Poll<ChunkedState, io::Error> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\n' => Ok(Async::Ready(ChunkedState::Size)),
|
||||
_ => 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) {
|
||||
fn read_end_cr<R: MemRead>(rdr: &mut R, cx: &mut task::Context) -> Poll<ChunkedState, io::Error> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Ok(Async::Ready(ChunkedState::EndLf)),
|
||||
_ => 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) {
|
||||
fn read_end_lf<R: MemRead>(rdr: &mut R, cx: &mut task::Context) -> Poll<ChunkedState, io::Error> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\n' => Ok(Async::Ready(ChunkedState::End)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF")),
|
||||
}
|
||||
@@ -323,11 +325,14 @@ mod tests {
|
||||
use super::ChunkedState;
|
||||
use super::super::io::MemRead;
|
||||
use futures::{Async, Poll};
|
||||
use futures::task;
|
||||
use futures::future::lazy;
|
||||
use futures::executor::block_on;
|
||||
use bytes::{BytesMut, Bytes};
|
||||
use mock::AsyncIo;
|
||||
|
||||
impl<'a> MemRead for &'a [u8] {
|
||||
fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error> {
|
||||
fn read_mem(&mut self, _cx: &mut task::Context, len: usize) -> Poll<Bytes, io::Error> {
|
||||
let n = ::std::cmp::min(len, self.len());
|
||||
if n > 0 {
|
||||
let (a, b) = self.split_at(n);
|
||||
@@ -347,7 +352,7 @@ mod tests {
|
||||
fn unwrap(self) -> Bytes {
|
||||
match self {
|
||||
Async::Ready(bytes) => bytes,
|
||||
Async::NotReady => panic!(),
|
||||
Async::Pending => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,7 +360,7 @@ mod tests {
|
||||
fn unwrap(self) -> ChunkedState {
|
||||
match self {
|
||||
Async::Ready(state) => state,
|
||||
Async::NotReady => panic!(),
|
||||
Async::Pending => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,12 +369,12 @@ mod tests {
|
||||
fn test_read_chunk_size() {
|
||||
use std::io::ErrorKind::{UnexpectedEof, InvalidInput};
|
||||
|
||||
fn read(s: &str) -> u64 {
|
||||
fn read(cx: &mut task::Context, s: &str) -> u64 {
|
||||
let mut state = ChunkedState::Size;
|
||||
let rdr = &mut s.as_bytes();
|
||||
let mut size = 0;
|
||||
loop {
|
||||
let result = state.step(rdr, &mut size, &mut None);
|
||||
let result = state.step(rdr, cx, &mut size, &mut None);
|
||||
let desc = format!("read_size failed for {:?}", s);
|
||||
state = result.expect(desc.as_str()).unwrap();
|
||||
if state == ChunkedState::Body || state == ChunkedState::EndCr {
|
||||
@@ -379,12 +384,12 @@ mod tests {
|
||||
size
|
||||
}
|
||||
|
||||
fn read_err(s: &str, expected_err: io::ErrorKind) {
|
||||
fn read_err(cx: &mut task::Context, s: &str, expected_err: io::ErrorKind) {
|
||||
let mut state = ChunkedState::Size;
|
||||
let rdr = &mut s.as_bytes();
|
||||
let mut size = 0;
|
||||
loop {
|
||||
let result = state.step(rdr, &mut size, &mut None);
|
||||
let result = state.step(rdr, cx, &mut size, &mut None);
|
||||
state = match result {
|
||||
Ok(s) => s.unwrap(),
|
||||
Err(e) => {
|
||||
@@ -399,90 +404,111 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(1, read("1\r\n"));
|
||||
assert_eq!(1, read("01\r\n"));
|
||||
assert_eq!(0, read("0\r\n"));
|
||||
assert_eq!(0, read("00\r\n"));
|
||||
assert_eq!(10, read("A\r\n"));
|
||||
assert_eq!(10, read("a\r\n"));
|
||||
assert_eq!(255, read("Ff\r\n"));
|
||||
assert_eq!(255, read("Ff \r\n"));
|
||||
// Missing LF or CRLF
|
||||
read_err("F\rF", InvalidInput);
|
||||
read_err("F", UnexpectedEof);
|
||||
// Invalid hex digit
|
||||
read_err("X\r\n", InvalidInput);
|
||||
read_err("1X\r\n", InvalidInput);
|
||||
read_err("-\r\n", InvalidInput);
|
||||
read_err("-1\r\n", InvalidInput);
|
||||
// Acceptable (if not fully valid) extensions do not influence the size
|
||||
assert_eq!(1, read("1;extension\r\n"));
|
||||
assert_eq!(10, read("a;ext name=value\r\n"));
|
||||
assert_eq!(1, read("1;extension;extension2\r\n"));
|
||||
assert_eq!(1, read("1;;; ;\r\n"));
|
||||
assert_eq!(2, read("2; extension...\r\n"));
|
||||
assert_eq!(3, read("3 ; extension=123\r\n"));
|
||||
assert_eq!(3, read("3 ;\r\n"));
|
||||
assert_eq!(3, read("3 ; \r\n"));
|
||||
// Invalid extensions cause an error
|
||||
read_err("1 invalid extension\r\n", InvalidInput);
|
||||
read_err("1 A\r\n", InvalidInput);
|
||||
read_err("1;no CRLF", UnexpectedEof);
|
||||
block_on(lazy(|cx| {
|
||||
assert_eq!(1, read(cx, "1\r\n"));
|
||||
assert_eq!(1, read(cx, "01\r\n"));
|
||||
assert_eq!(0, read(cx, "0\r\n"));
|
||||
assert_eq!(0, read(cx, "00\r\n"));
|
||||
assert_eq!(10, read(cx, "A\r\n"));
|
||||
assert_eq!(10, read(cx, "a\r\n"));
|
||||
assert_eq!(255, read(cx, "Ff\r\n"));
|
||||
assert_eq!(255, read(cx, "Ff \r\n"));
|
||||
// Missing LF or CRLF
|
||||
read_err(cx, "F\rF", InvalidInput);
|
||||
read_err(cx, "F", UnexpectedEof);
|
||||
// Invalid hex digit
|
||||
read_err(cx, "X\r\n", InvalidInput);
|
||||
read_err(cx, "1X\r\n", InvalidInput);
|
||||
read_err(cx, "-\r\n", InvalidInput);
|
||||
read_err(cx, "-1\r\n", InvalidInput);
|
||||
// Acceptable (if not fully valid) extensions do not influence the size
|
||||
assert_eq!(1, read(cx, "1;extension\r\n"));
|
||||
assert_eq!(10, read(cx, "a;ext name=value\r\n"));
|
||||
assert_eq!(1, read(cx, "1;extension;extension2\r\n"));
|
||||
assert_eq!(1, read(cx, "1;;; ;\r\n"));
|
||||
assert_eq!(2, read(cx, "2; extension...\r\n"));
|
||||
assert_eq!(3, read(cx, "3 ; extension=123\r\n"));
|
||||
assert_eq!(3, read(cx, "3 ;\r\n"));
|
||||
assert_eq!(3, read(cx, "3 ; \r\n"));
|
||||
// Invalid extensions cause an error
|
||||
read_err(cx, "1 invalid extension\r\n", InvalidInput);
|
||||
read_err(cx, "1 A\r\n", InvalidInput);
|
||||
read_err(cx, "1;no CRLF", UnexpectedEof);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_sized_early_eof() {
|
||||
let mut bytes = &b"foo bar"[..];
|
||||
let mut decoder = Decoder::length(10);
|
||||
assert_eq!(decoder.decode(&mut bytes).unwrap().unwrap().len(), 7);
|
||||
let e = decoder.decode(&mut bytes).unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
|
||||
block_on(lazy(|cx| {
|
||||
let mut bytes = &b"foo bar"[..];
|
||||
let mut decoder = Decoder::length(10);
|
||||
assert_eq!(decoder.decode(&mut bytes, cx).unwrap().unwrap().len(), 7);
|
||||
let e = decoder.decode(&mut bytes, cx).unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_early_eof() {
|
||||
let mut bytes = &b"\
|
||||
9\r\n\
|
||||
foo bar\
|
||||
"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
assert_eq!(decoder.decode(&mut bytes).unwrap().unwrap().len(), 7);
|
||||
let e = decoder.decode(&mut bytes).unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
|
||||
block_on(lazy(|cx| {
|
||||
let mut bytes = &b"\
|
||||
9\r\n\
|
||||
foo bar\
|
||||
"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
assert_eq!(decoder.decode(&mut bytes, cx).unwrap().unwrap().len(), 7);
|
||||
let e = decoder.decode(&mut bytes, cx).unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_single_read() {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
|
||||
let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode").unwrap();
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
block_on(lazy(|cx| {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
|
||||
let buf = Decoder::chunked().decode(&mut mock_buf, cx).expect("decode").unwrap();
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_after_eof() {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n\r\n"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
block_on(lazy(|cx| {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n\r\n"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
|
||||
// normal read
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap();
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
// normal read
|
||||
let buf = decoder.decode(&mut mock_buf, cx).expect("decode").unwrap();
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
|
||||
// eof read
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap();
|
||||
assert_eq!(0, buf.len());
|
||||
// eof read
|
||||
let buf = decoder.decode(&mut mock_buf, cx).expect("decode").unwrap();
|
||||
assert_eq!(0, buf.len());
|
||||
|
||||
// ensure read after eof also returns eof
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap();
|
||||
assert_eq!(0, buf.len());
|
||||
// ensure read after eof also returns eof
|
||||
let buf = decoder.decode(&mut mock_buf, cx).expect("decode").unwrap();
|
||||
assert_eq!(0, buf.len());
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
// perform an async read using a custom buffer size and causing a blocking
|
||||
// read at the specified byte
|
||||
fn read_async(mut decoder: Decoder,
|
||||
cx: &mut task::Context,
|
||||
content: &[u8],
|
||||
block_at: usize)
|
||||
-> String {
|
||||
@@ -490,14 +516,14 @@ mod tests {
|
||||
let mut ins = AsyncIo::new(content, block_at);
|
||||
let mut outs = Vec::new();
|
||||
loop {
|
||||
match decoder.decode(&mut ins).expect("unexpected decode error: {}") {
|
||||
match decoder.decode(&mut ins, cx).expect("unexpected decode error: {}") {
|
||||
Async::Ready(buf) => {
|
||||
if buf.is_empty() {
|
||||
break; // eof
|
||||
}
|
||||
outs.write(buf.as_ref()).expect("write buffer");
|
||||
},
|
||||
Async::NotReady => {
|
||||
Async::Pending => {
|
||||
ins.block_in(content_len); // we only block once
|
||||
}
|
||||
};
|
||||
@@ -508,11 +534,14 @@ mod tests {
|
||||
// iterate over the different ways that this async read could go.
|
||||
// tests blocking a read at each byte along the content - The shotgun approach
|
||||
fn all_async_cases(content: &str, expected: &str, decoder: Decoder) {
|
||||
let content_len = content.len();
|
||||
for block_at in 0..content_len {
|
||||
let actual = read_async(decoder.clone(), content.as_bytes(), block_at);
|
||||
assert_eq!(expected, &actual) //, "Failed async. Blocking at {}", block_at);
|
||||
}
|
||||
block_on(lazy(|cx| {
|
||||
let content_len = content.len();
|
||||
for block_at in 0..content_len {
|
||||
let actual = read_async(decoder.clone(), cx, content.as_bytes(), block_at);
|
||||
assert_eq!(expected, &actual) //, "Failed async. Blocking at {}", block_at);
|
||||
}
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -2,13 +2,15 @@ use std::io;
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures::{Async, Future, Poll, Stream};
|
||||
use futures::task;
|
||||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use http::{Request, Response, StatusCode};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_service::Service;
|
||||
|
||||
use proto::body::Entity;
|
||||
use proto::{Body, BodyLength, Conn, Http1Transaction, MessageHead, RequestHead, RequestLine, ResponseHead};
|
||||
|
||||
use ::service::Service;
|
||||
|
||||
pub struct Dispatcher<D, Bs, I, B, T> {
|
||||
conn: Conn<I, B, T>,
|
||||
dispatch: D,
|
||||
@@ -21,9 +23,9 @@ pub trait Dispatch {
|
||||
type PollItem;
|
||||
type PollBody;
|
||||
type RecvItem;
|
||||
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Option<Self::PollBody>)>, ::Error>;
|
||||
fn recv_msg(&mut self, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()>;
|
||||
fn poll_ready(&mut self) -> Poll<(), ()>;
|
||||
fn poll_msg(&mut self, cx: &mut task::Context) -> Poll<Option<(Self::PollItem, Option<Self::PollBody>)>, ::Error>;
|
||||
fn recv_msg(&mut self, cx: &mut task::Context, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()>;
|
||||
fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), ()>;
|
||||
fn should_poll(&self) -> bool;
|
||||
}
|
||||
|
||||
@@ -69,57 +71,57 @@ where
|
||||
|
||||
/// The "Future" poll function. Runs this dispatcher until the
|
||||
/// connection is shutdown, or an error occurs.
|
||||
pub fn poll_until_shutdown(&mut self) -> Poll<(), ::Error> {
|
||||
self.poll_catch(true)
|
||||
pub fn poll_until_shutdown(&mut self, cx: &mut task::Context) -> Poll<(), ::Error> {
|
||||
self.poll_catch(cx, true)
|
||||
}
|
||||
|
||||
/// Run this dispatcher until HTTP says this connection is done,
|
||||
/// but don't call `AsyncWrite::shutdown` on the underlying IO.
|
||||
///
|
||||
/// This is useful for HTTP upgrades.
|
||||
pub fn poll_without_shutdown(&mut self) -> Poll<(), ::Error> {
|
||||
self.poll_catch(false)
|
||||
pub fn poll_without_shutdown(&mut self, cx: &mut task::Context) -> Poll<(), ::Error> {
|
||||
self.poll_catch(cx, false)
|
||||
}
|
||||
|
||||
fn poll_catch(&mut self, should_shutdown: bool) -> Poll<(), ::Error> {
|
||||
self.poll_inner(should_shutdown).or_else(|e| {
|
||||
fn poll_catch(&mut self, cx: &mut task::Context, should_shutdown: bool) -> Poll<(), ::Error> {
|
||||
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)).map(Async::Ready)
|
||||
self.dispatch.recv_msg(cx, Err(e)).map(Async::Ready)
|
||||
})
|
||||
}
|
||||
|
||||
fn poll_inner(&mut self, should_shutdown: bool) -> Poll<(), ::Error> {
|
||||
self.poll_read()?;
|
||||
self.poll_write()?;
|
||||
self.poll_flush()?;
|
||||
fn poll_inner(&mut self, cx: &mut task::Context, should_shutdown: bool) -> Poll<(), ::Error> {
|
||||
self.poll_read(cx)?;
|
||||
self.poll_write(cx)?;
|
||||
self.poll_flush(cx)?;
|
||||
|
||||
if self.is_done() {
|
||||
if should_shutdown {
|
||||
try_ready!(self.conn.shutdown());
|
||||
try_ready!(self.conn.shutdown(cx));
|
||||
}
|
||||
self.conn.take_error()?;
|
||||
Ok(Async::Ready(()))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Ok(Async::Pending)
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_read(&mut self) -> Poll<(), ::Error> {
|
||||
fn poll_read(&mut self, cx: &mut task::Context) -> Poll<(), ::Error> {
|
||||
loop {
|
||||
if self.is_closing {
|
||||
return Ok(Async::Ready(()));
|
||||
} else if self.conn.can_read_head() {
|
||||
try_ready!(self.poll_read_head());
|
||||
try_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() {
|
||||
match body.poll_ready(cx) {
|
||||
Ok(Async::Ready(())) => (),
|
||||
Ok(Async::NotReady) => {
|
||||
Ok(Async::Pending) => {
|
||||
self.body_tx = Some(body);
|
||||
return Ok(Async::NotReady);
|
||||
return Ok(Async::Pending);
|
||||
},
|
||||
Err(_canceled) => {
|
||||
// user doesn't care about the body
|
||||
@@ -129,7 +131,7 @@ where
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
}
|
||||
match self.conn.read_body() {
|
||||
match self.conn.read_body(cx) {
|
||||
Ok(Async::Ready(Some(chunk))) => {
|
||||
match body.send_data(chunk) {
|
||||
Ok(()) => {
|
||||
@@ -147,9 +149,9 @@ where
|
||||
Ok(Async::Ready(None)) => {
|
||||
// just drop, the body will close automatically
|
||||
},
|
||||
Ok(Async::NotReady) => {
|
||||
Ok(Async::Pending) => {
|
||||
self.body_tx = Some(body);
|
||||
return Ok(Async::NotReady);
|
||||
return Ok(Async::Pending);
|
||||
}
|
||||
Err(e) => {
|
||||
body.send_error(::Error::Io(e));
|
||||
@@ -159,16 +161,16 @@ where
|
||||
// just drop, the body will close automatically
|
||||
}
|
||||
} else {
|
||||
return self.conn.read_keep_alive().map(Async::Ready);
|
||||
return self.conn.read_keep_alive(cx).map(Async::Ready);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_read_head(&mut self) -> Poll<(), ::Error> {
|
||||
fn poll_read_head(&mut self, cx: &mut task::Context) -> Poll<(), ::Error> {
|
||||
// can dispatch receive, or does it still care about, an incoming message?
|
||||
match self.dispatch.poll_ready() {
|
||||
match self.dispatch.poll_ready(cx) {
|
||||
Ok(Async::Ready(())) => (),
|
||||
Ok(Async::NotReady) => unreachable!("dispatch not ready when conn is"),
|
||||
Ok(Async::Pending) => unreachable!("dispatch not ready when conn is"),
|
||||
Err(()) => {
|
||||
trace!("dispatch no longer receiving messages");
|
||||
self.close();
|
||||
@@ -176,27 +178,27 @@ where
|
||||
}
|
||||
}
|
||||
// dispatch is ready for a message, try to read one
|
||||
match self.conn.read_head() {
|
||||
match self.conn.read_head(cx) {
|
||||
Ok(Async::Ready(Some((head, has_body)))) => {
|
||||
let body = if has_body {
|
||||
let (mut tx, rx) = Body::channel();
|
||||
let _ = tx.poll_ready(); // register this task if rx is dropped
|
||||
let _ = tx.poll_ready(cx); // register this task if rx is dropped
|
||||
self.body_tx = Some(tx);
|
||||
rx
|
||||
} else {
|
||||
Body::empty()
|
||||
};
|
||||
self.dispatch.recv_msg(Ok((head, body)))?;
|
||||
self.dispatch.recv_msg(cx, 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),
|
||||
Ok(Async::Pending) => Ok(Async::Pending),
|
||||
Err(err) => {
|
||||
debug!("read_head error: {}", err);
|
||||
self.dispatch.recv_msg(Err(err))?;
|
||||
self.dispatch.recv_msg(cx, Err(err))?;
|
||||
// if here, the dispatcher gave the user the error
|
||||
// somewhere else. we still need to shutdown, but
|
||||
// not as a second error.
|
||||
@@ -205,12 +207,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_write(&mut self) -> Poll<(), ::Error> {
|
||||
fn poll_write(&mut self, cx: &mut task::Context) -> Poll<(), ::Error> {
|
||||
loop {
|
||||
if self.is_closing {
|
||||
return Ok(Async::Ready(()));
|
||||
} else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() {
|
||||
if let Some((head, body)) = try_ready!(self.dispatch.poll_msg()) {
|
||||
if let Some((head, body)) = try_ready!(self.dispatch.poll_msg(cx)) {
|
||||
let body_type = body.as_ref().map(|body| {
|
||||
body.content_length()
|
||||
.map(BodyLength::Known)
|
||||
@@ -223,27 +225,27 @@ where
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
} else if !self.conn.can_buffer_body() {
|
||||
try_ready!(self.poll_flush());
|
||||
try_ready!(self.poll_flush(cx));
|
||||
} else if let Some(mut body) = self.body_rx.take() {
|
||||
let chunk = match body.poll_data()? {
|
||||
let chunk = match body.poll_data(cx)? {
|
||||
Async::Ready(Some(chunk)) => {
|
||||
self.body_rx = Some(body);
|
||||
chunk
|
||||
},
|
||||
Async::Ready(None) => {
|
||||
if self.conn.can_write_body() {
|
||||
self.conn.write_body(None)?;
|
||||
self.conn.write_body(cx, None)?;
|
||||
}
|
||||
continue;
|
||||
},
|
||||
Async::NotReady => {
|
||||
Async::Pending => {
|
||||
self.body_rx = Some(body);
|
||||
return Ok(Async::NotReady);
|
||||
return Ok(Async::Pending);
|
||||
}
|
||||
};
|
||||
|
||||
if self.conn.can_write_body() {
|
||||
assert!(self.conn.write_body(Some(chunk))?.is_ready());
|
||||
self.conn.write_body(cx, Some(chunk))?;
|
||||
// This allows when chunk is `None`, or `Some([])`.
|
||||
} else if chunk.as_ref().len() == 0 {
|
||||
// ok
|
||||
@@ -251,13 +253,13 @@ where
|
||||
warn!("unexpected chunk when body cannot write");
|
||||
}
|
||||
} else {
|
||||
return Ok(Async::NotReady);
|
||||
return Ok(Async::Pending);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(&mut self) -> Poll<(), ::Error> {
|
||||
self.conn.flush().map_err(|err| {
|
||||
fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), ::Error> {
|
||||
self.conn.flush(cx).map_err(|err| {
|
||||
debug!("error writing: {}", err);
|
||||
err.into()
|
||||
})
|
||||
@@ -300,8 +302,8 @@ where
|
||||
type Error = ::Error;
|
||||
|
||||
#[inline]
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
self.poll_until_shutdown()
|
||||
fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
|
||||
self.poll_until_shutdown(cx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,13 +327,13 @@ where
|
||||
type PollBody = Bs;
|
||||
type RecvItem = RequestHead;
|
||||
|
||||
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Option<Self::PollBody>)>, ::Error> {
|
||||
fn poll_msg(&mut self, cx: &mut task::Context) -> Poll<Option<(Self::PollItem, Option<Self::PollBody>)>, ::Error> {
|
||||
if let Some(mut fut) = self.in_flight.take() {
|
||||
let resp = match fut.poll()? {
|
||||
let resp = match fut.poll(cx)? {
|
||||
Async::Ready(res) => res,
|
||||
Async::NotReady => {
|
||||
Async::Pending => {
|
||||
self.in_flight = Some(fut);
|
||||
return Ok(Async::NotReady);
|
||||
return Ok(Async::Pending);
|
||||
}
|
||||
};
|
||||
let (parts, body) = resp.into_parts();
|
||||
@@ -351,7 +353,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn recv_msg(&mut self, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()> {
|
||||
fn recv_msg(&mut self, _cx: &mut task::Context, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()> {
|
||||
let (msg, body) = msg?;
|
||||
let mut req = Request::new(body);
|
||||
*req.method_mut() = msg.subject.0;
|
||||
@@ -362,9 +364,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), ()> {
|
||||
fn poll_ready(&mut self, _cx: &mut task::Context) -> Poll<(), ()> {
|
||||
if self.in_flight.is_some() {
|
||||
Ok(Async::NotReady)
|
||||
Ok(Async::Pending)
|
||||
} else {
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
@@ -395,16 +397,16 @@ where
|
||||
type PollBody = B;
|
||||
type RecvItem = ResponseHead;
|
||||
|
||||
fn poll_msg(&mut self) -> Poll<Option<(Self::PollItem, Option<Self::PollBody>)>, ::Error> {
|
||||
match self.rx.poll() {
|
||||
fn poll_msg(&mut self, cx: &mut task::Context) -> Poll<Option<(Self::PollItem, Option<Self::PollBody>)>, ::Error> {
|
||||
match self.rx.poll_next(cx) {
|
||||
Ok(Async::Ready(Some((req, mut cb)))) => {
|
||||
// check that future hasn't been canceled already
|
||||
match cb.poll_cancel().expect("poll_cancel cannot error") {
|
||||
match cb.poll_cancel(cx).expect("poll_cancel cannot error") {
|
||||
Async::Ready(()) => {
|
||||
trace!("request canceled");
|
||||
Ok(Async::Ready(None))
|
||||
},
|
||||
Async::NotReady => {
|
||||
Async::Pending => {
|
||||
let (parts, body) = req.into_parts();
|
||||
let head = RequestHead {
|
||||
version: parts.version,
|
||||
@@ -427,12 +429,12 @@ where
|
||||
// user has dropped sender handle
|
||||
Ok(Async::Ready(None))
|
||||
},
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Ok(Async::Pending) => return Ok(Async::Pending),
|
||||
Err(_) => unreachable!("receiver cannot error"),
|
||||
}
|
||||
}
|
||||
|
||||
fn recv_msg(&mut self, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()> {
|
||||
fn recv_msg(&mut self, cx: &mut task::Context, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()> {
|
||||
match msg {
|
||||
Ok((msg, body)) => {
|
||||
if let Some(cb) = self.callback.take() {
|
||||
@@ -450,7 +452,7 @@ 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() {
|
||||
} else if let Ok(Async::Ready(Some((req, cb)))) = self.rx.poll_next(cx) {
|
||||
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
|
||||
@@ -463,14 +465,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), ()> {
|
||||
fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), ()> {
|
||||
match self.callback {
|
||||
Some(ref mut cb) => match cb.poll_cancel() {
|
||||
Some(ref mut cb) => match cb.poll_cancel(cx) {
|
||||
Ok(Async::Ready(())) => {
|
||||
trace!("callback receiver has dropped");
|
||||
Err(())
|
||||
},
|
||||
Ok(Async::NotReady) => Ok(Async::Ready(())),
|
||||
Ok(Async::Pending) => Ok(Async::Ready(())),
|
||||
Err(_) => unreachable!("oneshot poll_cancel cannot error"),
|
||||
},
|
||||
None => Err(()),
|
||||
@@ -487,31 +489,32 @@ mod tests {
|
||||
extern crate pretty_env_logger;
|
||||
|
||||
use super::*;
|
||||
use futures::executor::block_on;
|
||||
use futures::future::lazy;
|
||||
use mock::AsyncIo;
|
||||
use proto::ClientTransaction;
|
||||
|
||||
#[test]
|
||||
fn client_read_bytes_before_writing_request() {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
::futures::lazy(|| {
|
||||
block_on(lazy(|cx| {
|
||||
let io = AsyncIo::new_buf(b"HTTP/1.1 200 OK\r\n\r\n".to_vec(), 100);
|
||||
let (mut tx, rx) = ::client::dispatch::channel();
|
||||
let conn = Conn::<_, ::Chunk, ClientTransaction>::new(io);
|
||||
let mut dispatcher = Dispatcher::new(Client::new(rx), conn);
|
||||
|
||||
let res_rx = tx.try_send(::Request::new(::Body::empty())).unwrap();
|
||||
let mut res_rx = tx.try_send(::Request::new(::Body::empty())).unwrap();
|
||||
|
||||
let a1 = dispatcher.poll().expect("error should be sent on channel");
|
||||
let a1 = dispatcher.poll(cx).expect("error should be sent on channel");
|
||||
assert!(a1.is_ready(), "dispatcher should be closed");
|
||||
let err = res_rx.wait()
|
||||
.expect("callback poll")
|
||||
.expect_err("callback response");
|
||||
let result = res_rx.poll(cx)
|
||||
.expect("callback poll");
|
||||
|
||||
match err {
|
||||
(::Error::Cancel(_), Some(_)) => (),
|
||||
other => panic!("expected Canceled, got {:?}", other),
|
||||
match result {
|
||||
Async::Ready(Err((::Error::Cancel(_), Some(_)))) => (),
|
||||
other => panic!("expected Err(Canceled), got {:?}", other),
|
||||
}
|
||||
Ok::<(), ()>(())
|
||||
}).wait().unwrap();
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
use futures::{Async, Poll};
|
||||
use futures::task;
|
||||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use iovec::IoVec;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use proto::{Http1Transaction, MessageHead};
|
||||
|
||||
@@ -108,7 +108,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse<S: Http1Transaction>(&mut self) -> Poll<MessageHead<S::Incoming>, ::Error> {
|
||||
pub fn parse<S: Http1Transaction>(&mut self, cx: &mut task::Context) -> Poll<MessageHead<S::Incoming>, ::Error> {
|
||||
loop {
|
||||
match try!(S::parse(&mut self.read_buf)) {
|
||||
Some((head, len)) => {
|
||||
@@ -122,7 +122,7 @@ where
|
||||
}
|
||||
},
|
||||
}
|
||||
match try_ready!(self.read_from_io()) {
|
||||
match try_ready!(self.read_from_io(cx)) {
|
||||
0 => {
|
||||
trace!("parse eof");
|
||||
return Err(::Error::Incomplete);
|
||||
@@ -132,21 +132,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_from_io(&mut self) -> Poll<usize, io::Error> {
|
||||
pub fn read_from_io(&mut self, cx: &mut task::Context) -> Poll<usize, io::Error> {
|
||||
use bytes::BufMut;
|
||||
self.read_blocked = false;
|
||||
if self.read_buf.remaining_mut() < INIT_BUFFER_SIZE {
|
||||
self.read_buf.reserve(INIT_BUFFER_SIZE);
|
||||
}
|
||||
self.io.read_buf(&mut self.read_buf).map(|ok| {
|
||||
read_buf(&mut self.io, cx, &mut self.read_buf).map(|ok| {
|
||||
match ok {
|
||||
Async::Ready(n) => {
|
||||
debug!("read {} bytes", n);
|
||||
Async::Ready(n)
|
||||
},
|
||||
Async::NotReady => {
|
||||
Async::Pending => {
|
||||
self.read_blocked = true;
|
||||
Async::NotReady
|
||||
Async::Pending
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -164,14 +164,14 @@ where
|
||||
self.read_blocked
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Poll<(), io::Error> {
|
||||
pub fn flush(&mut self, cx: &mut task::Context) -> Poll<(), io::Error> {
|
||||
if self.flush_pipeline && !self.read_buf.is_empty() {
|
||||
//Ok(())
|
||||
} else if self.write_buf.remaining() == 0 {
|
||||
try_nb!(self.io.flush());
|
||||
try_ready!(self.io.poll_flush(cx));
|
||||
} else {
|
||||
loop {
|
||||
let n = try_ready!(self.io.write_buf(&mut self.write_buf.auto()));
|
||||
let n = try_ready!(self.write_buf.poll_flush_into(&mut self.io, cx));
|
||||
debug!("flushed {} bytes", n);
|
||||
if self.write_buf.remaining() == 0 {
|
||||
break;
|
||||
@@ -180,14 +180,33 @@ where
|
||||
return Err(io::ErrorKind::WriteZero.into())
|
||||
}
|
||||
}
|
||||
try_nb!(self.io.flush())
|
||||
try_ready!(self.io.poll_flush(cx))
|
||||
}
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_buf<I: AsyncRead, B: BufMut>(io: &mut I, cx: &mut task::Context, buf: &mut B) -> Poll<usize, io::Error> {
|
||||
if !buf.has_remaining_mut() {
|
||||
return Ok(Async::Ready(0));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let n = {
|
||||
let b = buf.bytes_mut();
|
||||
|
||||
io.initializer().initialize(b);
|
||||
|
||||
try_ready!(io.poll_read(cx, b))
|
||||
};
|
||||
|
||||
buf.advance_mut(n);
|
||||
Ok(Async::Ready(n))
|
||||
}
|
||||
}
|
||||
|
||||
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<Bytes, io::Error>;
|
||||
}
|
||||
|
||||
impl<T, B> MemRead for Buffered<T, B>
|
||||
@@ -195,12 +214,12 @@ where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
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<Bytes, io::Error> {
|
||||
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()))
|
||||
} else {
|
||||
let n = try_ready!(self.read_from_io());
|
||||
let n = try_ready!(self.read_from_io(cx));
|
||||
Ok(Async::Ready(self.read_buf.split_to(::std::cmp::min(len, n)).freeze()))
|
||||
}
|
||||
}
|
||||
@@ -294,11 +313,6 @@ where
|
||||
self.strategy = strategy;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn auto(&mut self) -> WriteBufAuto<B> {
|
||||
WriteBufAuto::new(self)
|
||||
}
|
||||
|
||||
fn buffer(&mut self, buf: B) {
|
||||
match self.strategy {
|
||||
Strategy::Flatten => {
|
||||
@@ -343,6 +357,48 @@ where
|
||||
unreachable!("head_buf just pushed on back");
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush_into<I: AsyncWrite>(&mut self, io: &mut I, cx: &mut task::Context) -> Poll<usize, io::Error> {
|
||||
if !self.has_remaining() {
|
||||
return Ok(Async::Ready(0));
|
||||
}
|
||||
|
||||
let (num_bufs_avail, num_bytes_written, len_first_buf) = {
|
||||
static PLACEHOLDER: &[u8] = &[0];
|
||||
let mut bufs = [From::from(PLACEHOLDER); 64];
|
||||
let num_bufs_avail = self.bytes_vec(&mut bufs[..]);
|
||||
let num_bytes_written = try_ready!(io.poll_vectored_write(cx, &bufs[..num_bufs_avail]));
|
||||
(num_bufs_avail, num_bytes_written, bufs[0].len())
|
||||
};
|
||||
self.advance(num_bytes_written);
|
||||
|
||||
if let Strategy::Auto = self.strategy {
|
||||
if num_bufs_avail > 1 {
|
||||
// If there's more than one IoVec available, attempt to
|
||||
// determine the best buffering strategy based on whether
|
||||
// the underlying AsyncWrite object supports vectored I/O.
|
||||
if num_bytes_written == len_first_buf {
|
||||
// If only the first of many IoVec was written, we can assume
|
||||
// with some certainty that vectored I/O _is not_ supported.
|
||||
//
|
||||
// Switch to a flattening strategy for buffering data.
|
||||
trace!("detected no usage of vectored write, flattening");
|
||||
let mut vec = Vec::new();
|
||||
vec.put(&mut self.buf);
|
||||
self.buf.bufs.push_back(VecOrBuf::Vec(Cursor::new(vec)));
|
||||
self.strategy = Strategy::Flatten;
|
||||
} else if num_bytes_written > len_first_buf {
|
||||
// If more than the first IoVec was written, we can assume
|
||||
// with some certainty that vectored I/O _is_ supported.
|
||||
//
|
||||
// Switch to a queuing strategy for buffering data.
|
||||
self.strategy = Strategy::Queue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Async::Ready(num_bytes_written))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Buf> fmt::Debug for WriteBuf<B> {
|
||||
@@ -376,65 +432,6 @@ impl<B: Buf> Buf for WriteBuf<B> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects when wrapped `WriteBuf` is used for vectored IO, and
|
||||
/// adjusts the `WriteBuf` strategy if not.
|
||||
struct WriteBufAuto<'a, B: Buf + 'a> {
|
||||
bytes_called: Cell<bool>,
|
||||
bytes_vec_called: Cell<bool>,
|
||||
inner: &'a mut WriteBuf<B>,
|
||||
}
|
||||
|
||||
impl<'a, B: Buf> WriteBufAuto<'a, B> {
|
||||
fn new(inner: &'a mut WriteBuf<B>) -> WriteBufAuto<'a, B> {
|
||||
WriteBufAuto {
|
||||
bytes_called: Cell::new(false),
|
||||
bytes_vec_called: Cell::new(false),
|
||||
inner: inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Buf> Buf for WriteBufAuto<'a, B> {
|
||||
#[inline]
|
||||
fn remaining(&self) -> usize {
|
||||
self.inner.remaining()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes(&self) -> &[u8] {
|
||||
self.bytes_called.set(true);
|
||||
self.inner.bytes()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.inner.advance(cnt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
|
||||
self.bytes_vec_called.set(true);
|
||||
self.inner.bytes_vec(dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Buf + 'a> Drop for WriteBufAuto<'a, B> {
|
||||
fn drop(&mut self) {
|
||||
if let Strategy::Auto = self.inner.strategy {
|
||||
if self.bytes_vec_called.get() {
|
||||
self.inner.strategy = Strategy::Queue;
|
||||
} else if self.bytes_called.get() {
|
||||
trace!("detected no usage of vectored write, flattening");
|
||||
self.inner.strategy = Strategy::Flatten;
|
||||
let mut vec = Vec::new();
|
||||
vec.put(&mut self.inner.buf);
|
||||
self.inner.buf.bufs.push_back(VecOrBuf::Vec(Cursor::new(vec)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Strategy {
|
||||
Auto,
|
||||
@@ -568,51 +565,68 @@ impl<T: Buf> Buf for BufDeque<T> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::Read;
|
||||
use futures::task;
|
||||
use futures::future;
|
||||
use futures::executor::block_on;
|
||||
use futures::io::AsyncRead;
|
||||
use mock::AsyncIo;
|
||||
|
||||
#[cfg(test)]
|
||||
impl<T: Read> MemRead for ::mock::AsyncIo<T> {
|
||||
fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error> {
|
||||
fn read_mem(&mut self, cx: &mut task::Context, len: usize) -> Poll<Bytes, io::Error> {
|
||||
let mut v = vec![0; len];
|
||||
let n = try_nb!(self.read(v.as_mut_slice()));
|
||||
let n = try_ready!(self.poll_read(cx, v.as_mut_slice()));
|
||||
Ok(Async::Ready(BytesMut::from(&v[..n]).freeze()))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iobuf_write_empty_slice() {
|
||||
let mut mock = AsyncIo::new_buf(vec![], 256);
|
||||
mock.error(io::Error::new(io::ErrorKind::Other, "logic error"));
|
||||
block_on(future::lazy(|cx| {
|
||||
let mut mock = AsyncIo::new_buf(vec![], 256);
|
||||
mock.error(io::Error::new(io::ErrorKind::Other, "logic error"));
|
||||
|
||||
let mut io_buf = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
let mut io_buf = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
|
||||
// underlying io will return the logic error upon write,
|
||||
// so we are testing that the io_buf does not trigger a write
|
||||
// when there is nothing to flush
|
||||
io_buf.flush().expect("should short-circuit flush");
|
||||
// underlying io will return the logic error upon write,
|
||||
// so we are testing that the io_buf does not trigger a write
|
||||
// when there is nothing to flush
|
||||
io_buf.flush(cx).expect("should short-circuit flush");
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_reads_until_blocked() {
|
||||
// missing last line ending
|
||||
let raw = "HTTP/1.1 200 OK\r\n";
|
||||
block_on(future::lazy(|cx| {
|
||||
// missing last line ending
|
||||
let raw = "HTTP/1.1 200 OK\r\n";
|
||||
|
||||
let mock = AsyncIo::new_buf(raw, raw.len());
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
assert_eq!(buffered.parse::<::proto::ClientTransaction>().unwrap(), Async::NotReady);
|
||||
assert!(buffered.io.blocked());
|
||||
let mock = AsyncIo::new_buf(raw, raw.len());
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
|
||||
assert_eq!(buffered.parse::<::proto::ClientTransaction>(cx).unwrap(), Async::Pending);
|
||||
assert!(buffered.io.blocked());
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_buf_skips_empty_bufs() {
|
||||
let mut mock = AsyncIo::new_buf(vec![], 1024);
|
||||
mock.max_read_vecs(0); // disable vectored IO
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
block_on(future::lazy(|cx| {
|
||||
let mut mock = AsyncIo::new_buf(vec![], 1024);
|
||||
mock.max_read_vecs(0); // disable vectored IO
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
|
||||
buffered.buffer(Cursor::new(Vec::new()));
|
||||
buffered.buffer(Cursor::new(b"hello".to_vec()));
|
||||
buffered.flush().unwrap();
|
||||
assert_eq!(buffered.io, b"hello");
|
||||
buffered.buffer(Cursor::new(Vec::new()));
|
||||
buffered.buffer(Cursor::new(b"hello".to_vec()));
|
||||
buffered.flush(cx).unwrap();
|
||||
assert_eq!(buffered.io, b"hello");
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -620,17 +634,22 @@ mod tests {
|
||||
extern crate pretty_env_logger;
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let mock = AsyncIo::new_buf(vec![], 1024);
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
block_on(future::lazy(|cx| {
|
||||
let mock = AsyncIo::new_buf(vec![], 1024);
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's ");
|
||||
buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
buffered.flush().unwrap();
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's ");
|
||||
buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
assert_eq!(buffered.io.num_writes(), 0);
|
||||
buffered.flush(cx).unwrap();
|
||||
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 1);
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 1);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -638,27 +657,31 @@ mod tests {
|
||||
extern crate pretty_env_logger;
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let mock = AsyncIo::new_buf(vec![], 1024);
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
block_on(future::lazy(|cx| {
|
||||
let mock = AsyncIo::new_buf(vec![], 1024);
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
buffered.write_buf_mut().extend(b"world, ");
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
buffered.write_buf_mut().extend(b"world, ");
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
|
||||
// after flushing, reclaim the Vec
|
||||
buffered.flush().unwrap();
|
||||
assert_eq!(buffered.write_buf.remaining(), 0);
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
// after flushing, reclaim the Vec
|
||||
buffered.flush(cx).unwrap();
|
||||
assert_eq!(buffered.write_buf.remaining(), 0);
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
|
||||
// add a user buf in the way
|
||||
buffered.buffer(Cursor::new(b"it's ".to_vec()));
|
||||
// and then add more hyper bytes
|
||||
buffered.write_buf_mut().extend(b"hyper!");
|
||||
buffered.flush().unwrap();
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
// add a user buf in the way
|
||||
buffered.buffer(Cursor::new(b"it's ".to_vec()));
|
||||
// and then add more hyper bytes
|
||||
buffered.write_buf_mut().extend(b"hyper!");
|
||||
buffered.flush(cx).unwrap();
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -666,21 +689,25 @@ mod tests {
|
||||
extern crate pretty_env_logger;
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let mock = AsyncIo::new_buf(vec![], 1024);
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
buffered.write_buf.set_strategy(Strategy::Flatten);
|
||||
block_on(future::lazy(|cx| {
|
||||
let mock = AsyncIo::new_buf(vec![], 1024);
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
buffered.write_buf.set_strategy(Strategy::Flatten);
|
||||
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's ");
|
||||
buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's ");
|
||||
buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
|
||||
buffered.flush().unwrap();
|
||||
buffered.flush(cx).unwrap();
|
||||
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 1);
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 1);
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -688,22 +715,26 @@ mod tests {
|
||||
extern crate pretty_env_logger;
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let mut mock = AsyncIo::new_buf(vec![], 1024);
|
||||
mock.max_read_vecs(0); // disable vectored IO
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
block_on(future::lazy(|cx| {
|
||||
let mut mock = AsyncIo::new_buf(vec![], 1024);
|
||||
mock.max_read_vecs(0); // disable vectored IO
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
|
||||
// we have 4 buffers, but hope to detect that vectored IO isn't
|
||||
// being used, and switch to flattening automatically,
|
||||
// resulting in only 2 writes
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's hyper!");
|
||||
//buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
buffered.flush().unwrap();
|
||||
// we have 4 buffers, but hope to detect that vectored IO isn't
|
||||
// being used, and switch to flattening automatically,
|
||||
// resulting in only 2 writes
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's hyper!");
|
||||
//buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
buffered.flush(cx).unwrap();
|
||||
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 2);
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 2);
|
||||
assert_eq!(buffered.write_buf.buf.bufs.len(), 1);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -711,20 +742,24 @@ mod tests {
|
||||
extern crate pretty_env_logger;
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let mut mock = AsyncIo::new_buf(vec![], 1024);
|
||||
mock.max_read_vecs(0); // disable vectored IO
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
buffered.write_buf.set_strategy(Strategy::Queue);
|
||||
block_on(future::lazy(move |cx| {
|
||||
let mut mock = AsyncIo::new_buf(vec![], 1024);
|
||||
mock.max_read_vecs(0); // disable vectored IO
|
||||
let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);
|
||||
buffered.write_buf.set_strategy(Strategy::Queue);
|
||||
|
||||
// we have 4 buffers, and vec IO disabled, but explicitly said
|
||||
// don't try to auto detect (via setting strategy above)
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's ");
|
||||
buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
buffered.flush().unwrap();
|
||||
// we have 4 buffers, and vec IO disabled, but explicitly said
|
||||
// don't try to auto detect (via setting strategy above)
|
||||
buffered.write_buf_mut().extend(b"hello ");
|
||||
buffered.buffer(Cursor::new(b"world, ".to_vec()));
|
||||
buffered.write_buf_mut().extend(b"it's ");
|
||||
buffered.buffer(Cursor::new(b"hyper!".to_vec()));
|
||||
buffered.flush(cx).unwrap();
|
||||
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 4);
|
||||
assert_eq!(buffered.io, b"hello world, it's hyper!");
|
||||
assert_eq!(buffered.io.num_writes(), 4);
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user