style(lib): run rustfmt and enforce in CI

This commit is contained in:
Sean McArthur
2019-12-05 13:30:53 -08:00
parent b0060f277e
commit 0dc89680cd
69 changed files with 2982 additions and 2499 deletions

View File

@@ -3,16 +3,16 @@ use std::io::{self};
use std::marker::PhantomData;
use bytes::{Buf, Bytes};
use http::{HeaderMap, Method, Version};
use http::header::{HeaderValue, CONNECTION};
use http::{HeaderMap, Method, Version};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::Chunk;
use crate::common::{Pin, Poll, Unpin, task};
use crate::proto::{BodyLength, DecodedLength, MessageHead};
use super::io::Buffered;
use super::{/*Decode,*/ Decoder, Encode, EncodedBuf, Encoder, Http1Transaction, ParseContext,};
use crate::common::{task, Pin, Poll, Unpin};
use crate::headers::connection_keep_alive;
use super::io::{Buffered};
use super::{EncodedBuf, Encode, Encoder, /*Decode,*/ Decoder, Http1Transaction, ParseContext};
use crate::proto::{BodyLength, DecodedLength, MessageHead};
use crate::Chunk;
const H2_PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
@@ -26,13 +26,14 @@ 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<fn(T)>
_marker: PhantomData<fn(T)>,
}
impl<I, B, T> Conn<I, B, T>
where I: AsyncRead + AsyncWrite + Unpin,
B: Buf,
T: Http1Transaction,
where
I: AsyncRead + AsyncWrite + Unpin,
B: Buf,
T: Http1Transaction,
{
pub fn new(io: I) -> Conn<I, B, T> {
Conn {
@@ -107,7 +108,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
_ => true,
}
}
},
}
_ => false,
}
}
@@ -129,14 +130,20 @@ where I: AsyncRead + AsyncWrite + Unpin,
read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE
}
pub fn poll_read_head(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<(MessageHead<T::Incoming>, DecodedLength, bool)>>> {
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 ready!(self.io.parse::<T>(cx, ParseContext {
cached_headers: &mut self.state.cached_headers,
req_method: &mut self.state.method,
})) {
let msg = match ready!(self.io.parse::<T>(
cx,
ParseContext {
cached_headers: &mut self.state.cached_headers,
req_method: &mut self.state.method,
}
)) {
Ok(msg) => msg,
Err(e) => return self.on_read_head_error(e),
};
@@ -179,11 +186,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
let was_mid_parse = e.is_parse() || !self.io.read_buf().is_empty();
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());
debug!(
"parse error ({}) with {} bytes",
e,
self.io.read_buf().len()
);
match self.on_parse_error(e) {
Ok(()) => Poll::Pending, // XXX: wat?
Err(e) => Poll::Ready(Some(Err(e))),
}
} else {
debug!("read eof");
@@ -192,7 +202,10 @@ where I: AsyncRead + AsyncWrite + Unpin,
}
}
pub fn poll_read_body(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<io::Result<Chunk>>> {
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 {
@@ -201,11 +214,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
Poll::Ready(Ok(slice)) => {
let (reading, chunk) = if decoder.is_eof() {
debug!("incoming body completed");
(Reading::KeepAlive, if !slice.is_empty() {
Some(Ok(Chunk::from(slice)))
} else {
None
})
(
Reading::KeepAlive,
if !slice.is_empty() {
Some(Ok(Chunk::from(slice)))
} else {
None
},
)
} else if slice.is_empty() {
error!("incoming body unexpectedly ended");
// This should be unreachable, since all 3 decoders
@@ -216,14 +232,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
return Poll::Ready(Some(Ok(Chunk::from(slice))));
};
(reading, Poll::Ready(chunk))
},
}
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => {
debug!("incoming body decode error: {}", e);
(Reading::Closed, Poll::Ready(Some(Err(e))))
},
}
}
},
}
_ => unreachable!("read_body invalid state: {:?}", self.state.reading),
};
@@ -287,7 +303,10 @@ where I: AsyncRead + AsyncWrite + Unpin,
return ret;
}
debug!("received unexpected {} bytes on an idle connection", num_read);
debug!(
"received unexpected {} bytes on an idle connection",
num_read
);
Poll::Ready(Err(crate::Error::new_unexpected_message()))
}
@@ -318,30 +337,23 @@ where I: AsyncRead + AsyncWrite + Unpin,
trace!("force_io_read; io error = {:?}", e);
self.state.close();
e
}))
}))
}
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
// would finish.
match self.state.reading {
Reading::Body(..) |
Reading::KeepAlive |
Reading::Closed => return,
Reading::Body(..) | Reading::KeepAlive | Reading::Closed => return,
Reading::Init => (),
};
match self.state.writing {
Writing::Body(..) => return,
Writing::Init |
Writing::KeepAlive |
Writing::Closed => (),
Writing::Init | Writing::KeepAlive | Writing::Closed => (),
}
if !self.io.is_read_blocked() {
@@ -357,11 +369,11 @@ where I: AsyncRead + AsyncWrite + Unpin,
}
return;
}
},
}
Poll::Pending => {
trace!("maybe_notify; read_from_io blocked");
return
},
return;
}
Poll::Ready(Err(e)) => {
trace!("maybe_notify; read_from_io error: {}", e);
self.state.close();
@@ -382,21 +394,19 @@ where I: AsyncRead + AsyncWrite + Unpin,
if !T::should_read_first() {
match self.state.reading {
Reading::Closed => return false,
_ => {},
_ => {}
}
}
match self.state.writing {
Writing::Init => true,
_ => false
_ => false,
}
}
pub fn can_write_body(&self) -> bool {
match self.state.writing {
Writing::Body(..) => true,
Writing::Init |
Writing::KeepAlive |
Writing::Closed => false,
Writing::Init | Writing::KeepAlive | Writing::Closed => false,
}
}
@@ -417,7 +427,9 @@ where I: AsyncRead + AsyncWrite + Unpin,
}
pub fn write_full_msg(&mut self, head: MessageHead<T::Outgoing>, body: B) {
if let Some(encoder) = self.encode_head(head, Some(BodyLength::Known(body.remaining() as u64))) {
if let Some(encoder) =
self.encode_head(head, Some(BodyLength::Known(body.remaining() as u64)))
{
let is_last = encoder.is_last();
// Make sure we don't write a body if we weren't actually allowed
// to do so, like because its a HEAD request.
@@ -432,7 +444,11 @@ where I: AsyncRead + AsyncWrite + Unpin,
}
}
fn encode_head(&mut self, mut head: MessageHead<T::Outgoing>, body: Option<BodyLength>) -> Option<Encoder> {
fn encode_head(
&mut self,
mut head: MessageHead<T::Outgoing>,
body: Option<BodyLength>,
) -> Option<Encoder> {
debug_assert!(self.can_write_head());
if !T::should_read_first() {
@@ -442,24 +458,27 @@ where I: AsyncRead + AsyncWrite + Unpin,
self.enforce_version(&mut head);
let buf = self.io.headers_buf();
match T::encode(Encode {
head: &mut head,
body,
keep_alive: self.state.wants_keep_alive(),
req_method: &mut self.state.method,
title_case_headers: self.state.title_case_headers,
}, buf) {
match T::encode(
Encode {
head: &mut head,
body,
keep_alive: self.state.wants_keep_alive(),
req_method: &mut self.state.method,
title_case_headers: self.state.title_case_headers,
},
buf,
) {
Ok(encoder) => {
debug_assert!(self.state.cached_headers.is_none());
debug_assert!(head.headers.is_empty());
self.state.cached_headers = Some(head.headers);
Some(encoder)
},
}
Err(err) => {
self.state.error = Some(err);
self.state.writing = Writing::Closed;
None
},
}
}
}
@@ -478,10 +497,12 @@ where I: AsyncRead + AsyncWrite + Unpin,
Version::HTTP_10 => self.state.disable_keep_alive(),
// If response is version 1.1 and keep-alive is wanted, add
// Connection: keep-alive header when not present
Version::HTTP_11 => if self.state.wants_keep_alive() {
head.headers
.insert(CONNECTION, HeaderValue::from_static("keep-alive"));
},
Version::HTTP_11 => {
if self.state.wants_keep_alive() {
head.headers
.insert(CONNECTION, HeaderValue::from_static("keep-alive"));
}
}
_ => (),
}
}
@@ -490,7 +511,6 @@ where I: AsyncRead + AsyncWrite + Unpin,
// If we know the remote speaks an older version, we try to fix up any messages
// to work with our older peer.
fn enforce_version(&mut self, head: &mut MessageHead<T::Outgoing>) {
match self.state.version {
Version::HTTP_10 => {
// Fixes response or connection when keep-alive header is not present
@@ -498,7 +518,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
// If the remote only knows HTTP/1.0, we should force ourselves
// to do only speak HTTP/1.0 as well.
head.version = Version::HTTP_10;
},
}
_ => {
// If the remote speaks HTTP/1.1, then it *should* be fine with
// both HTTP/1.0 and HTTP/1.1 from us. So again, we just let
@@ -525,7 +545,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
} else {
return;
}
},
}
_ => unreachable!("write_body invalid state: {:?}", self.state.writing),
};
@@ -545,7 +565,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
} else {
Writing::Closed
}
},
}
_ => unreachable!("write_body invalid state: {:?}", self.state.writing),
};
@@ -568,15 +588,14 @@ where I: AsyncRead + AsyncWrite + Unpin,
} else {
Writing::KeepAlive
}
},
}
Err(_not_eof) => Writing::Closed,
}
},
}
_ => return,
};
self.state.writing = state;
}
// When we get a parse error, depending on what side we are, we might be able
@@ -585,11 +604,10 @@ where I: AsyncRead + AsyncWrite + Unpin,
// - Client: there is nothing we can do
// - Server: if Response hasn't been written yet, we can send a 4xx response
fn on_parse_error(&mut self, err: crate::Error) -> crate::Result<()> {
match self.state.writing {
Writing::Init => {
if self.has_h2_prefix() {
return Err(crate::Error::new_version_h2())
return Err(crate::Error::new_version_h2());
}
if let Some(msg) = T::on_error(&err) {
// Drop the cached headers so as to not trigger a debug
@@ -619,7 +637,7 @@ where I: AsyncRead + AsyncWrite + Unpin,
Ok(()) => {
trace!("shut down IO complete");
Poll::Ready(Ok(()))
},
}
Err(e) => {
debug!("error shutting down IO: {}", e);
Poll::Ready(Err(e))
@@ -741,9 +759,7 @@ impl fmt::Debug for Writing {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Writing::Init => f.write_str("Init"),
Writing::Body(ref enc) => f.debug_tuple("Body")
.field(enc)
.finish(),
Writing::Body(ref enc) => f.debug_tuple("Body").field(enc).finish(),
Writing::KeepAlive => f.write_str("KeepAlive"),
Writing::Closed => f.write_str("Closed"),
}
@@ -824,15 +840,18 @@ impl State {
if let KA::Busy = self.keep_alive.status() {
self.idle::<T>();
} else {
trace!("try_keep_alive({}): could keep-alive, but status = {:?}", T::LOG, self.keep_alive);
trace!(
"try_keep_alive({}): could keep-alive, but status = {:?}",
T::LOG,
self.keep_alive
);
self.close();
}
},
(&Reading::Closed, &Writing::KeepAlive) |
(&Reading::KeepAlive, &Writing::Closed) => {
}
(&Reading::Closed, &Writing::KeepAlive) | (&Reading::KeepAlive, &Writing::Closed) => {
self.close()
}
_ => ()
_ => (),
}
}
@@ -880,14 +899,14 @@ impl State {
fn is_read_closed(&self) -> bool {
match self.reading {
Reading::Closed => true,
_ => false
_ => false,
}
}
fn is_write_closed(&self) -> bool {
match self.writing {
Writing::Closed => true,
_ => false
_ => false,
}
}
@@ -929,11 +948,10 @@ mod tests {
let mut headers = x.0.headers;
headers.clear();
conn.state.cached_headers = Some(headers);
},
f => panic!("expected Ready(Some(Ok(..))): {:?}", f)
}
f => panic!("expected Ready(Some(Ok(..))): {:?}", f),
}
conn.io.read_buf_mut().reserve(1);
unsafe {
conn.io.read_buf_mut().set_len(len);

View File

@@ -24,8 +24,7 @@ pub(crate) fn update_and_header_value() -> HeaderValue {
CACHED.with(|cache| {
let mut cache = cache.borrow_mut();
cache.check();
HeaderValue::from_bytes(cache.buffer())
.expect("Date format should be valid HeaderValue")
HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
})
}

View File

@@ -1,16 +1,16 @@
use std::error::Error as StdError;
use std::fmt;
use std::usize;
use std::io;
use std::usize;
use bytes::Bytes;
use crate::common::{Poll, task};
use crate::common::{task, Poll};
use super::io::MemRead;
use super::{DecodedLength};
use super::DecodedLength;
use self::Kind::{Length, Chunked, Eof};
use self::Kind::{Chunked, Eof, Length};
/// Decoders to handle different Transfer-Encodings.
///
@@ -64,15 +64,21 @@ impl Decoder {
// constructors
pub fn length(x: u64) -> Decoder {
Decoder { kind: Kind::Length(x) }
Decoder {
kind: Kind::Length(x),
}
}
pub fn chunked() -> Decoder {
Decoder { kind: Kind::Chunked(ChunkedState::Size, 0) }
Decoder {
kind: Kind::Chunked(ChunkedState::Size, 0),
}
}
pub fn eof() -> Decoder {
Decoder { kind: Kind::Eof(false) }
Decoder {
kind: Kind::Eof(false),
}
}
pub(super) fn new(len: DecodedLength) -> Self {
@@ -87,14 +93,16 @@ impl Decoder {
pub fn is_eof(&self) -> bool {
match self.kind {
Length(0) |
Chunked(ChunkedState::End, _) |
Eof(true) => true,
Length(0) | Chunked(ChunkedState::End, _) | Eof(true) => true,
_ => false,
}
}
pub fn decode<R: MemRead>(&mut self, cx: &mut task::Context<'_>, body: &mut R) -> Poll<Result<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) => {
@@ -107,7 +115,10 @@ impl Decoder {
if num > *remaining {
*remaining = 0;
} else if num == 0 {
return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)));
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
IncompleteBody,
)));
} else {
*remaining -= num;
}
@@ -146,13 +157,10 @@ impl Decoder {
#[cfg(test)]
async fn decode_fut<R: MemRead>(&mut self, body: &mut R) -> Result<Bytes, io::Error> {
futures_util::future::poll_fn(move |cx| {
self.decode(cx, body)
}).await
futures_util::future::poll_fn(move |cx| self.decode(cx, body)).await
}
}
impl fmt::Debug for Decoder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.kind, f)
@@ -172,12 +180,13 @@ macro_rules! byte (
);
impl ChunkedState {
fn step<R: MemRead>(&self,
cx: &mut task::Context<'_>,
body: &mut R,
size: &mut u64,
buf: &mut Option<Bytes>)
-> Poll<Result<ChunkedState, io::Error>> {
fn step<R: MemRead>(
&self,
cx: &mut task::Context<'_>,
body: &mut R,
size: &mut u64,
buf: &mut Option<Bytes>,
) -> Poll<Result<ChunkedState, io::Error>> {
use self::ChunkedState::*;
match *self {
Size => ChunkedState::read_size(cx, body, size),
@@ -192,7 +201,11 @@ impl ChunkedState {
End => Poll::Ready(Ok(ChunkedState::End)),
}
}
fn read_size<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, size: &mut u64) -> Poll<Result<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, cx) {
@@ -212,33 +225,45 @@ impl ChunkedState {
b';' => return Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => {
return Poll::Ready(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",
)));
}
}
Poll::Ready(Ok(ChunkedState::Size))
}
fn read_size_lws<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<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, cx) {
// LWS can follow the chunk size, but no more digits can come
b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),
b';' => Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => {
Poll::Ready(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>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<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, cx) {
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
}
}
fn read_size_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R, size: u64) -> Poll<Result<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, cx) {
b'\n' => {
@@ -248,15 +273,20 @@ impl ChunkedState {
debug!("incoming chunked header: {0:#X} ({0} bytes)", size);
Poll::Ready(Ok(ChunkedState::Body))
}
},
_ => Poll::Ready(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>(cx: &mut task::Context<'_>, rdr: &mut R,
rem: &mut u64,
buf: &mut Option<Bytes>)
-> Poll<Result<ChunkedState, io::Error>> {
fn read_body<R: MemRead>(
cx: &mut task::Context<'_>,
rdr: &mut R,
rem: &mut u64,
buf: &mut Option<Bytes>,
) -> Poll<Result<ChunkedState, io::Error>> {
trace!("Chunked read, remaining={:?}", rem);
// cap remaining bytes at the max capacity of usize
@@ -271,7 +301,10 @@ impl ChunkedState {
if count == 0 {
*rem = 0;
return Poll::Ready(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;
@@ -282,29 +315,53 @@ impl ChunkedState {
Poll::Ready(Ok(ChunkedState::BodyCr))
}
}
fn read_body_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
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"))),
_ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk body CR",
))),
}
}
fn read_body_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
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"))),
_ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk body LF",
))),
}
}
fn read_end_cr<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
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"))),
_ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk end CR",
))),
}
}
fn read_end_lf<R: MemRead>(cx: &mut task::Context<'_>, rdr: &mut R) -> Poll<Result<ChunkedState, io::Error>> {
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"))),
_ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk end LF",
))),
}
}
}
@@ -326,10 +383,10 @@ impl StdError for IncompleteBody {
#[cfg(test)]
mod tests {
use std::time::Duration;
use std::pin::Pin;
use tokio::io::AsyncRead;
use super::*;
use std::pin::Pin;
use std::time::Duration;
use tokio::io::AsyncRead;
impl<'a> MemRead for &'a [u8] {
fn read_mem(&mut self, _: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {
@@ -363,19 +420,18 @@ mod tests {
use crate::mock::AsyncIo;
*/
#[tokio::test]
async fn test_read_chunk_size() {
use std::io::ErrorKind::{UnexpectedEof, InvalidInput};
use std::io::ErrorKind::{InvalidInput, UnexpectedEof};
async fn read(s: &str) -> u64 {
let mut state = ChunkedState::Size;
let rdr = &mut s.as_bytes();
let mut size = 0;
loop {
let result = futures_util::future::poll_fn(|cx| {
state.step(cx, rdr, &mut size, &mut None)
}).await;
let result =
futures_util::future::poll_fn(|cx| state.step(cx, rdr, &mut size, &mut None))
.await;
let desc = format!("read_size failed for {:?}", s);
state = result.expect(desc.as_str());
if state == ChunkedState::Body || state == ChunkedState::EndCr {
@@ -390,14 +446,19 @@ mod tests {
let rdr = &mut s.as_bytes();
let mut size = 0;
loop {
let result = futures_util::future::poll_fn(|cx| {
state.step(cx, rdr, &mut size, &mut None)
}).await;
let result =
futures_util::future::poll_fn(|cx| state.step(cx, rdr, &mut size, &mut None))
.await;
state = match result {
Ok(s) => s,
Err(e) => {
assert!(expected_err == e.kind(), "Reading {:?}, expected {:?}, but got {:?}",
s, expected_err, e.kind());
assert!(
expected_err == e.kind(),
"Reading {:?}, expected {:?}, but got {:?}",
s,
expected_err,
e.kind()
);
return;
}
};
@@ -462,7 +523,10 @@ mod tests {
#[tokio::test]
async fn test_read_chunked_single_read() {
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
let buf = Decoder::chunked().decode_fut(&mut mock_buf).await.expect("decode");
let buf = Decoder::chunked()
.decode_fut(&mut mock_buf)
.await
.expect("decode");
assert_eq!(16, buf.len());
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
assert_eq!("1234567890abcdef", &result);
@@ -490,10 +554,7 @@ mod tests {
// perform an async read using a custom buffer size and causing a blocking
// read at the specified byte
async fn read_async(mut decoder: Decoder,
content: &[u8],
block_at: usize)
-> String {
async fn read_async(mut decoder: Decoder, content: &[u8], block_at: usize) -> String {
let mut outs = Vec::new();
let mut ins = if block_at == 0 {

View File

@@ -4,10 +4,13 @@ use bytes::{Buf, Bytes};
use http::{Request, Response, StatusCode};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::body::{Body, Payload};
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::body::{Body, Payload};
use crate::common::{task, Future, Never, Pin, Poll, Unpin};
use crate::proto::{
BodyLength, Conn, DecodedLength, Dispatched, MessageHead, RequestHead, RequestLine,
ResponseHead,
};
use crate::service::HttpService;
pub(crate) struct Dispatcher<D, Bs: Payload, I, T> {
@@ -23,7 +26,10 @@ pub(crate) trait Dispatch {
type PollBody;
type PollError;
type RecvItem;
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(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, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>>;
fn should_poll(&self) -> bool;
@@ -44,7 +50,11 @@ 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>> + Unpin,
D: Dispatch<
PollItem = MessageHead<T::Outgoing>,
PollBody = Bs,
RecvItem = MessageHead<T::Incoming>,
> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite + Unpin,
T: Http1Transaction + Unpin,
@@ -77,7 +87,10 @@ where
///
/// This is useful for old-style HTTP upgrades, but ignores
/// newer-style upgrade API.
pub(crate) fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>>
pub(crate) fn poll_without_shutdown(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<crate::Result<()>>
where
Self: Unpin,
{
@@ -88,7 +101,11 @@ where
})
}
fn poll_catch(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> {
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,
@@ -99,7 +116,11 @@ where
}))
}
fn poll_inner(&mut self, cx: &mut task::Context<'_>, should_shutdown: bool) -> Poll<crate::Result<Dispatched>> {
fn poll_inner(
&mut self,
cx: &mut task::Context<'_>,
should_shutdown: bool,
) -> Poll<crate::Result<Dispatched>> {
T::update_date();
ready!(self.poll_loop(cx))?;
@@ -161,7 +182,7 @@ where
Poll::Pending => {
self.body_tx = Some(body);
return Poll::Pending;
},
}
Poll::Ready(Err(_canceled)) => {
// user doesn't care about the body
// so we should stop reading
@@ -171,22 +192,20 @@ where
}
}
match self.conn.poll_read_body(cx) {
Poll::Ready(Some(Ok(chunk))) => {
match body.try_send_data(chunk) {
Ok(()) => {
self.body_tx = Some(body);
},
Err(_canceled) => {
if self.conn.can_read_body() {
trace!("body receiver dropped before eof, closing");
self.conn.close_read();
}
Poll::Ready(Some(Ok(chunk))) => match body.try_send_data(chunk) {
Ok(()) => {
self.body_tx = Some(body);
}
Err(_canceled) => {
if self.conn.can_read_body() {
trace!("body receiver dropped before eof, closing");
self.conn.close_read();
}
}
},
Poll::Ready(None) => {
// just drop, the body will close automatically
},
}
Poll::Pending => {
self.body_tx = Some(body);
return Poll::Pending;
@@ -223,14 +242,14 @@ where
let (tx, rx) = Body::new_channel(other.into_opt());
self.body_tx = Some(tx);
rx
},
}
};
if wants_upgrade {
body.set_on_upgrade(self.conn.on_upgrade());
}
self.dispatch.recv_msg(Ok((head, body)))?;
Poll::Ready(Ok(()))
},
}
Some(Err(err)) => {
debug!("read_head error: {}", err);
self.dispatch.recv_msg(Err(err))?;
@@ -239,7 +258,7 @@ where
// not as a second error.
self.close();
Poll::Ready(Ok(()))
},
}
None => {
// read eof, the write side will have been closed too unless
// allow_read_close was set to true, in which case just do
@@ -257,7 +276,10 @@ where
loop {
if self.is_closing {
return Poll::Ready(Ok(()));
} else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() {
} else if self.body_rx.is_none()
&& self.conn.can_write_head()
&& self.dispatch.should_poll()
{
if let Some(msg) = ready!(self.dispatch.poll_msg(cx)) {
let (head, mut body) = msg.map_err(crate::Error::new_user_service)?;
@@ -274,7 +296,9 @@ where
self.body_rx.set(None);
None
} else {
let btype = body.size_hint().exact()
let btype = body
.size_hint()
.exact()
.map(BodyLength::Known)
.or_else(|| Some(BodyLength::Unknown));
self.body_rx.set(Some(body));
@@ -289,7 +313,9 @@ where
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() {
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!(
@@ -357,8 +383,8 @@ where
// a client that cannot read may was well be done.
true
} else {
let write_done = self.conn.is_write_closed() ||
(!self.dispatch.should_poll() && self.body_rx.is_none());
let write_done = self.conn.is_write_closed()
|| (!self.dispatch.should_poll() && self.body_rx.is_none());
read_done && write_done
}
}
@@ -366,7 +392,11 @@ 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>> + Unpin,
D: Dispatch<
PollItem = MessageHead<T::Outgoing>,
PollBody = Bs,
RecvItem = MessageHead<T::Incoming>,
> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: AsyncRead + AsyncWrite + Unpin,
T: Http1Transaction + Unpin,
@@ -427,7 +457,7 @@ impl<S: HttpService<B>, B> Unpin for Server<S, B> {}
impl<S, Bs> Dispatch for Server<S, Body>
where
S: HttpService<Body, ResBody=Bs>,
S: HttpService<Body, ResBody = Bs>,
S::Error: Into<Box<dyn StdError + Send + Sync>>,
Bs: Payload,
{
@@ -436,7 +466,10 @@ where
type PollError = S::Error;
type RecvItem = RequestHead;
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> {
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();
@@ -471,11 +504,10 @@ where
if self.in_flight.is_some() {
Poll::Pending
} else {
self.service.poll_ready(cx)
.map_err(|_e| {
// FIXME: return error value.
trace!("service closed");
})
self.service.poll_ready(cx).map_err(|_e| {
// FIXME: return error value.
trace!("service closed");
})
}
}
@@ -486,7 +518,6 @@ where
// ===== impl Client =====
impl<B> Client<B> {
pub fn new(rx: ClientRx<B>) -> Client<B> {
Client {
@@ -506,7 +537,10 @@ where
type PollError = Never;
type RecvItem = ResponseHead;
fn poll_msg(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> {
fn poll_msg(
&mut self,
cx: &mut task::Context<'_>,
) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> {
debug_assert!(!self.rx_closed);
match self.rx.poll_next(cx) {
Poll::Ready(Some((req, mut cb))) => {
@@ -515,7 +549,7 @@ where
Poll::Ready(()) => {
trace!("request canceled");
Poll::Ready(None)
},
}
Poll::Pending => {
let (parts, body) = req.into_parts();
let head = RequestHead {
@@ -527,13 +561,13 @@ where
Poll::Ready(Some(Ok((head, body))))
}
}
},
}
Poll::Ready(None) => {
// user has dropped sender handle
trace!("client tx closed");
self.rx_closed = true;
Poll::Ready(None)
},
}
Poll::Pending => Poll::Pending,
}
}
@@ -554,7 +588,7 @@ where
// full message!
Err(crate::Error::new_unexpected_message())
}
},
}
Err(err) => {
if let Some(cb) = self.callback.take() {
let _ = cb.send(Err((err, None)));
@@ -583,7 +617,7 @@ where
Poll::Ready(()) => {
trace!("callback receiver has dropped");
Poll::Ready(Err(()))
},
}
Poll::Pending => Poll::Ready(Ok(())),
},
None => Poll::Ready(Err(())),
@@ -597,18 +631,16 @@ where
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
use crate::proto::h1::ClientTransaction;
use std::time::Duration;
#[test]
fn client_read_bytes_before_writing_request() {
let _ = pretty_env_logger::try_init();
tokio_test::task::spawn(()).enter(|cx, _| {
let (io, mut handle) = tokio_test::io::Builder::new()
.build_with_handle();
let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
// Block at 0 for now, but we will release this response before
// the request is ready to write later...
@@ -624,7 +656,9 @@ mod tests {
//
handle.read(b"HTTP/1.1 200 OK\r\n\r\n");
let mut res_rx = tx.try_send(crate::Request::new(crate::Body::empty())).unwrap();
let mut res_rx = tx
.try_send(crate::Request::new(crate::Body::empty()))
.unwrap();
tokio_test::assert_ready_ok!(Pin::new(&mut dispatcher).poll(cx));
let err = tokio_test::assert_ready_ok!(Pin::new(&mut res_rx).poll(cx))

View File

@@ -1,8 +1,8 @@
use std::fmt;
use std::io::IoSlice;
use bytes::Buf;
use bytes::buf::ext::{BufExt, Chain, Take};
use bytes::Buf;
use super::io::WriteBuf;
@@ -68,7 +68,7 @@ impl Encoder {
pub fn is_eof(&self) -> bool {
match self.kind {
Kind::Length(0) => true,
_ => false
_ => false,
}
}
@@ -105,7 +105,7 @@ impl Encoder {
.chain(msg)
.chain(b"\r\n" as &'static [u8]);
BufKind::Chunked(buf)
},
}
Kind::Length(ref mut remaining) => {
trace!("sized write, len = {}", len);
if len as u64 > *remaining {
@@ -116,15 +116,13 @@ impl Encoder {
*remaining -= len as u64;
BufKind::Exact(msg)
}
},
}
Kind::CloseDelimited => {
trace!("close delimited write {}B", len);
BufKind::Exact(msg)
}
};
EncodedBuf {
kind,
}
EncodedBuf { kind }
}
pub(super) fn encode_and_end<B>(&self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>) -> bool
@@ -142,7 +140,7 @@ impl Encoder {
.chain(b"\r\n0\r\n\r\n" as &'static [u8]);
dst.buffer(buf);
!self.is_last
},
}
Kind::Length(remaining) => {
use std::cmp::Ordering;
@@ -151,17 +149,17 @@ impl Encoder {
Ordering::Equal => {
dst.buffer(msg);
!self.is_last
},
}
Ordering::Greater => {
dst.buffer(msg.take(remaining as usize));
!self.is_last
},
}
Ordering::Less => {
dst.buffer(msg);
false
}
}
},
}
Kind::CloseDelimited => {
trace!("close delimited write {}B", len);
dst.buffer(msg);
@@ -180,10 +178,13 @@ impl Encoder {
B: Buf,
{
debug_assert!(msg.remaining() > 0, "encode() called with empty buf");
debug_assert!(match self.kind {
Kind::Length(len) => len == msg.remaining() as u64,
_ => true,
}, "danger_full_buf length mismatches");
debug_assert!(
match self.kind {
Kind::Length(len) => len == msg.remaining() as u64,
_ => true,
},
"danger_full_buf length mismatches"
);
match self.kind {
Kind::Chunked => {
@@ -193,10 +194,10 @@ impl Encoder {
.chain(msg)
.chain(b"\r\n0\r\n\r\n" as &'static [u8]);
dst.buffer(buf);
},
}
_ => {
dst.buffer(msg);
},
}
}
}
}
@@ -246,7 +247,6 @@ where
}
}
#[cfg(target_pointer_width = "32")]
const USIZE_BYTES: usize = 4;
@@ -271,8 +271,7 @@ impl ChunkSize {
pos: 0,
len: 0,
};
write!(&mut size, "{:X}\r\n", len)
.expect("CHUNK_SIZE_MAX_BYTES should fit any usize");
write!(&mut size, "{:X}\r\n", len).expect("CHUNK_SIZE_MAX_BYTES should fit any usize");
size
}
}
@@ -285,7 +284,7 @@ impl Buf for ChunkSize {
#[inline]
fn bytes(&self) -> &[u8] {
&self.bytes[self.pos.into() .. self.len.into()]
&self.bytes[self.pos.into()..self.len.into()]
}
#[inline]
@@ -307,7 +306,8 @@ impl fmt::Debug for ChunkSize {
impl fmt::Write for ChunkSize {
fn write_str(&mut self, num: &str) -> fmt::Result {
use std::io::Write;
(&mut self.bytes[self.len.into()..]).write(num.as_bytes())
(&mut self.bytes[self.len.into()..])
.write(num.as_bytes())
.expect("&mut [u8].write() cannot error");
self.len += num.len() as u8; // safe because bytes is never bigger than 256
Ok(())
@@ -340,7 +340,7 @@ impl<B: Buf> From<Chain<Chain<ChunkSize, B>, StaticBuf>> for EncodedBuf<B> {
#[cfg(test)]
mod tests {
use bytes::{BufMut};
use bytes::BufMut;
use super::super::io::Cursor;
use super::Encoder;
@@ -364,7 +364,10 @@ mod tests {
let end = encoder.end::<Cursor<Vec<u8>>>().unwrap().unwrap();
dst.put(end);
assert_eq!(dst, b"7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n0\r\n\r\n".as_ref());
assert_eq!(
dst,
b"7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n0\r\n\r\n".as_ref()
);
}
#[test]
@@ -373,12 +376,10 @@ mod tests {
let mut encoder = Encoder::length(max_len as u64);
let mut dst = Vec::new();
let msg1 = b"foo bar".as_ref();
let buf1 = encoder.encode(msg1);
dst.put(buf1);
assert_eq!(dst, b"foo bar");
assert!(!encoder.is_eof());
encoder.end::<()>().unwrap_err();
@@ -398,12 +399,10 @@ mod tests {
let mut encoder = Encoder::close_delimited();
let mut dst = Vec::new();
let msg1 = b"foo bar".as_ref();
let buf1 = encoder.encode(msg1);
dst.put(buf1);
assert_eq!(dst, b"foo bar");
assert!(!encoder.is_eof());
encoder.end::<()>().unwrap_err();

View File

@@ -7,8 +7,8 @@ use std::io::{self, IoSlice};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::common::{Pin, Poll, Unpin, task};
use super::{Http1Transaction, ParseContext, ParsedMessage};
use crate::common::{task, Pin, Poll, Unpin};
/// The initial buffer size allocated before trying to read from IO.
pub(crate) const INIT_BUFFER_SIZE: usize = 8192;
@@ -140,34 +140,40 @@ where
}
}
pub(super) fn parse<S>(&mut self, cx: &mut task::Context<'_>, parse_ctx: ParseContext<'_>)
-> Poll<crate::Result<ParsedMessage<S::Incoming>>>
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: parse_ctx.cached_headers,
req_method: parse_ctx.req_method,
})? {
match S::parse(
&mut self.read_buf,
ParseContext {
cached_headers: parse_ctx.cached_headers,
req_method: parse_ctx.req_method,
},
)? {
Some(msg) => {
debug!("parsed {} headers", msg.head.headers.len());
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 Poll::Ready(Err(crate::Error::new_too_large()));
}
},
}
}
match ready!(self.poll_read_from_io(cx)).map_err(crate::Error::new_io)? {
0 => {
trace!("parse eof");
return Poll::Ready(Err(crate::Error::new_incomplete()));
}
_ => {},
_ => {}
}
}
}
@@ -180,10 +186,10 @@ where
}
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);
Poll::Ready(Ok(n))
},
debug!("read {} bytes", n);
self.read_buf_strategy.record(n);
Poll::Ready(Ok(n))
}
Poll::Pending => {
self.read_blocked = true;
Poll::Pending
@@ -215,12 +221,16 @@ where
_ => (),
}
loop {
let n = ready!(Pin::new(&mut self.io).poll_write_buf(cx, &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());
trace!(
"write returned zero, but {} bytes remaining",
self.write_buf.remaining()
);
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}
}
@@ -241,7 +251,10 @@ where
self.write_buf.headers.reset();
break;
} else if n == 0 {
trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining());
trace!(
"write returned zero, but {} bytes remaining",
self.write_buf.remaining()
);
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}
}
@@ -283,7 +296,7 @@ enum ReadStrategy {
Adaptive {
decrease_now: bool,
next: usize,
max: usize
max: usize,
},
Exact(usize),
}
@@ -313,7 +326,12 @@ impl ReadStrategy {
fn record(&mut self, bytes_read: usize) {
match *self {
ReadStrategy::Adaptive { ref mut decrease_now, ref mut next, max, .. } => {
ReadStrategy::Adaptive {
ref mut decrease_now,
ref mut next,
max,
..
} => {
if bytes_read >= *next {
*next = cmp::min(incr_power_of_two(*next), max);
*decrease_now = false;
@@ -334,7 +352,7 @@ impl ReadStrategy {
*decrease_now = false;
}
}
},
}
_ => (),
}
}
@@ -428,7 +446,6 @@ impl<B> WriteBuf<B> {
}
}
impl<B> WriteBuf<B>
where
B: Buf,
@@ -460,22 +477,19 @@ where
};
buf.advance(adv);
}
},
}
WriteStrategy::Auto | WriteStrategy::Queue => {
self.queue.bufs.push_back(buf.into());
},
}
}
}
fn can_buffer(&self) -> bool {
match self.strategy {
WriteStrategy::Flatten => {
self.remaining() < self.max_buf_size
},
WriteStrategy::Flatten => self.remaining() < self.max_buf_size,
WriteStrategy::Auto | WriteStrategy::Queue => {
self.queue.bufs.len() < MAX_BUF_LIST_BUFFERS
&& self.remaining() < self.max_buf_size
},
self.queue.bufs.len() < MAX_BUF_LIST_BUFFERS && self.remaining() < self.max_buf_size
}
}
}
@@ -587,7 +601,6 @@ impl<'a, B: Buf + 'a> Drop for WriteBufAuto<'a, B> {
}
}
#[derive(Debug)]
enum WriteStrategy {
Auto,
@@ -599,7 +612,6 @@ struct BufDeque<T> {
bufs: VecDeque<T>,
}
impl<T> BufDeque<T> {
fn new() -> BufDeque<T> {
BufDeque {
@@ -611,9 +623,7 @@ impl<T> BufDeque<T> {
impl<T: Buf> Buf for BufDeque<T> {
#[inline]
fn remaining(&self) -> usize {
self.bufs.iter()
.map(|buf| buf.remaining())
.sum()
self.bufs.iter().map(|buf| buf.remaining()).sum()
}
#[inline]
@@ -683,9 +693,11 @@ mod tests {
// First, let's just check that the Mock would normally return an
// error on an unexpected write, even if the buffer is empty...
let mut mock = Mock::new().build();
futures_util::future::poll_fn(|cx| Pin::new(&mut mock).poll_write_buf(cx, &mut Cursor::new(&[])))
.await
.expect_err("should be a broken pipe");
futures_util::future::poll_fn(|cx| {
Pin::new(&mut mock).poll_write_buf(cx, &mut Cursor::new(&[]))
})
.await
.expect_err("should be a broken pipe");
// underlying io will return the logic error upon write,
// so we are testing that the io_buf does not trigger a write
@@ -716,11 +728,17 @@ mod tests {
cached_headers: &mut None,
req_method: &mut None,
};
assert!(buffered.parse::<ClientTransaction>(cx, parse_ctx).is_pending());
assert!(buffered
.parse::<ClientTransaction>(cx, parse_ctx)
.is_pending());
Poll::Ready(())
}).await;
})
.await;
assert_eq!(buffered.read_buf, b"HTTP/1.1 200 OK\r\nServer: hyper\r\n"[..]);
assert_eq!(
buffered.read_buf,
b"HTTP/1.1 200 OK\r\nServer: hyper\r\n"[..]
);
}
#[test]
@@ -756,12 +774,20 @@ mod tests {
assert_eq!(strategy.next(), 16384);
strategy.record(1);
assert_eq!(strategy.next(), 16384, "first smaller record doesn't decrement yet");
assert_eq!(
strategy.next(),
16384,
"first smaller record doesn't decrement yet"
);
strategy.record(8192);
assert_eq!(strategy.next(), 16384, "record was with range");
strategy.record(1);
assert_eq!(strategy.next(), 16384, "in-range record should make this the 'first' again");
assert_eq!(
strategy.next(),
16384,
"in-range record should make this the 'first' again"
);
strategy.record(1);
assert_eq!(strategy.next(), 8192, "second smaller record decrements");
@@ -779,10 +805,18 @@ mod tests {
assert_eq!(strategy.next(), 16384);
strategy.record(8193);
assert_eq!(strategy.next(), 16384, "first smaller record doesn't decrement yet");
assert_eq!(
strategy.next(),
16384,
"first smaller record doesn't decrement yet"
);
strategy.record(8193);
assert_eq!(strategy.next(), 16384, "with current step does not decrement");
assert_eq!(
strategy.next(),
16384,
"with current step does not decrement"
);
}
#[test]

View File

@@ -1,11 +1,11 @@
use bytes::BytesMut;
use http::{HeaderMap, Method};
use crate::proto::{MessageHead, BodyLength, DecodedLength};
use crate::proto::{BodyLength, DecodedLength, MessageHead};
pub(crate) use self::conn::Conn;
pub(crate) use self::dispatch::Dispatcher;
pub use self::decode::Decoder;
pub(crate) use self::dispatch::Dispatcher;
pub use self::encode::{EncodedBuf, Encoder};
pub use self::io::Cursor; //TODO: move out of h1::io
pub use self::io::MINIMUM_MAX_BUFFER_SIZE;
@@ -18,7 +18,6 @@ mod encode;
mod io;
mod role;
pub(crate) type ServerTransaction = role::Server;
pub(crate) type ClientTransaction = role::Client;
@@ -75,4 +74,3 @@ pub(crate) struct Encode<'a, T> {
req_method: &'a mut Option<Method>,
title_case_headers: bool,
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
use futures_channel::{mpsc, oneshot};
use futures_util::future::{self, FutureExt as _, TryFutureExt as _, Either};
use futures_util::future::{self, Either, FutureExt as _, TryFutureExt as _};
use futures_util::stream::StreamExt as _;
use h2::client::{Builder, SendRequest};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::headers::content_length_parse_all;
use crate::body::Payload;
use crate::common::{Exec, Future, Never, Pin, Poll, task};
use crate::headers;
use crate::proto::Dispatched;
use super::{PipeToSendStream, SendBuf};
use crate::body::Payload;
use crate::common::{task, Exec, Future, Never, Pin, Poll};
use crate::headers;
use crate::headers::content_length_parse_all;
use crate::proto::Dispatched;
use crate::{Body, Request, Response};
type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>;
@@ -45,13 +45,10 @@ where
let (conn_drop_ref, rx) = mpsc::channel(1);
let (cancel_tx, conn_eof) = oneshot::channel();
let conn_drop_rx = rx.into_future()
.map(|(item, _rx)| {
match item {
Some(never) => match never {},
None => (),
}
});
let conn_drop_rx = rx.into_future().map(|(item, _rx)| match item {
Some(never) => match never {},
None => (),
});
let conn = conn.map_err(|e| debug!("connection error: {}", e));
@@ -138,12 +135,11 @@ where
};
if !eos {
let mut pipe = PipeToSendStream::new(body, body_tx)
.map(|res| {
if let Err(e) = res {
debug!("client request body error: {}", e);
}
});
let mut pipe = PipeToSendStream::new(body, body_tx).map(|res| {
if let Err(e) = res {
debug!("client request body error: {}", e);
}
});
// eagerly see if the body pipe is ready and
// can thus skip allocating in the executor
@@ -152,45 +148,39 @@ where
Poll::Pending => {
let conn_drop_ref = self.conn_drop_ref.clone();
let pipe = pipe.map(move |x| {
drop(conn_drop_ref);
x
});
drop(conn_drop_ref);
x
});
self.executor.execute(pipe);
}
}
}
let fut = fut
.map(move |result| {
match result {
Ok(res) => {
let content_length = content_length_parse_all(res.headers());
let res = res.map(|stream|
crate::Body::h2(stream, content_length));
Ok(res)
},
Err(err) => {
debug!("client response error: {}", err);
Err((crate::Error::new_h2(err), None))
}
}
});
let fut = fut.map(move |result| match result {
Ok(res) => {
let content_length = content_length_parse_all(res.headers());
let res = res.map(|stream| crate::Body::h2(stream, content_length));
Ok(res)
}
Err(err) => {
debug!("client response error: {}", err);
Err((crate::Error::new_h2(err), None))
}
});
self.executor.execute(cb.send_when(fut));
continue;
},
}
Poll::Ready(None) => {
trace!("client::dispatch::Sender dropped");
return Poll::Ready(Ok(Dispatched::Shutdown));
}
Poll::Pending => {
match ready!(Pin::new(&mut self.conn_eof).poll(cx)) {
Ok(never) => match never {},
Err(_conn_is_eof) => {
trace!("connection task is closed, closing dispatch task");
return Poll::Ready(Ok(Dispatched::Shutdown));
}
Poll::Pending => match ready!(Pin::new(&mut self.conn_eof).poll(cx)) {
Ok(never) => match never {},
Err(_conn_is_eof) => {
trace!("connection task is closed, closing dispatch task");
return Poll::Ready(Ok(Dispatched::Shutdown));
}
},
}

View File

@@ -1,5 +1,5 @@
use bytes::Buf;
use h2::{SendStream};
use h2::SendStream;
use http::header::{
HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER,
TRANSFER_ENCODING, UPGRADE,
@@ -7,7 +7,7 @@ use http::header::{
use http::HeaderMap;
use crate::body::Payload;
use crate::common::{Future, Pin, Poll, task};
use crate::common::{task, Future, Pin, Poll};
pub(crate) mod client;
pub(crate) mod server;
@@ -38,7 +38,11 @@ fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
}
if is_request {
if headers.get(TE).map(|te_header| te_header != "trailers").unwrap_or(false) {
if headers
.get(TE)
.map(|te_header| te_header != "trailers")
.unwrap_or(false)
{
warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
headers.remove(TE);
}
@@ -123,19 +127,24 @@ where
if self.body_tx.capacity() == 0 {
loop {
match ready!(self.body_tx.poll_capacity(cx)) {
Some(Ok(0)) => {},
Some(Ok(0)) => {}
Some(Ok(_)) => break,
Some(Err(e)) => return Poll::Ready(Err(crate::Error::new_body_write(e))) ,
Some(Err(e)) => {
return Poll::Ready(Err(crate::Error::new_body_write(e)))
}
None => return Poll::Ready(Err(crate::Error::new_canceled())),
}
}
} else {
if let Poll::Ready(reason) =
self.body_tx.poll_reset(cx).map_err(crate::Error::new_body_write)?
if let Poll::Ready(reason) = self
.body_tx
.poll_reset(cx)
.map_err(crate::Error::new_body_write)?
{
debug!("stream received RST_STREAM: {:?}", reason);
return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(reason))));
return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
reason,
))));
}
}
@@ -170,11 +179,15 @@ where
}
}
} else {
if let Poll::Ready(reason) =
self.body_tx.poll_reset(cx).map_err(|e| crate::Error::new_body_write(e))?
if let Poll::Ready(reason) = self
.body_tx
.poll_reset(cx)
.map_err(|e| crate::Error::new_body_write(e))?
{
debug!("stream received RST_STREAM: {:?}", reason);
return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(reason))));
return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
reason,
))));
}
match ready!(Pin::new(&mut self.stream).poll_trailers(cx)) {

View File

@@ -1,19 +1,19 @@
use std::error::Error as StdError;
use std::marker::Unpin;
use pin_project::{pin_project, project};
use h2::Reason;
use h2::server::{Builder, Connection, Handshake, SendResponse};
use h2::Reason;
use pin_project::{pin_project, project};
use tokio::io::{AsyncRead, AsyncWrite};
use super::{PipeToSendStream, SendBuf};
use crate::body::Payload;
use crate::common::exec::H2Exec;
use crate::common::{Future, Pin, Poll, task};
use crate::common::{task, Future, Pin, Poll};
use crate::headers;
use crate::headers::content_length_parse_all;
use crate::service::HttpService;
use crate::proto::Dispatched;
use super::{PipeToSendStream, SendBuf};
use crate::service::HttpService;
use crate::{Body, Response};
@@ -45,11 +45,10 @@ where
closing: Option<crate::Error>,
}
impl<T, S, B, E> Server<T, S, B, E>
where
T: AsyncRead + AsyncWrite + Unpin,
S: HttpService<Body, ResBody=B>,
S: HttpService<Body, ResBody = B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>,
B: Payload,
B::Data: Unpin,
@@ -69,13 +68,13 @@ where
match self.state {
State::Handshaking(..) => {
// fall-through, to replace state with Closed
},
}
State::Serving(ref mut srv) => {
if srv.closing.is_none() {
srv.conn.graceful_shutdown();
}
return;
},
}
State::Closed => {
return;
}
@@ -87,7 +86,7 @@ where
impl<T, S, B, E> Future for Server<T, S, B, E>
where
T: AsyncRead + AsyncWrite + Unpin,
S: HttpService<Body, ResBody=B>,
S: HttpService<Body, ResBody = B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>,
B: Payload,
B::Data: Unpin,
@@ -105,7 +104,7 @@ where
conn,
closing: None,
})
},
}
State::Serving(ref mut srv) => {
ready!(srv.poll_server(cx, &mut me.service, &mut me.exec))?;
return Poll::Ready(Ok(Dispatched::Shutdown));
@@ -127,12 +126,14 @@ where
B: Payload,
B::Data: Unpin,
{
fn poll_server<S, E>(&mut self, cx: &mut task::Context<'_>, service: &mut S, exec: &mut E) -> Poll<crate::Result<()>>
fn poll_server<S, E>(
&mut self,
cx: &mut task::Context<'_>,
service: &mut S,
exec: &mut E,
) -> Poll<crate::Result<()>>
where
S: HttpService<
Body,
ResBody=B,
>,
S: HttpService<Body, ResBody = B>,
S::Error: Into<Box<dyn StdError + Send + Sync>>,
E: H2Exec<S::Future, B>,
{
@@ -171,25 +172,26 @@ where
Some(Ok((req, respond))) => {
trace!("incoming request");
let content_length = content_length_parse_all(req.headers());
let req = req.map(|stream| {
crate::Body::h2(stream, content_length)
});
let req = req.map(|stream| crate::Body::h2(stream, content_length));
let fut = H2Stream::new(service.call(req), respond);
exec.execute_h2stream(fut);
},
}
Some(Err(e)) => {
return Poll::Ready(Err(crate::Error::new_h2(e)));
},
}
None => {
// no more incoming streams...
trace!("incoming connection complete");
return Poll::Ready(Ok(()));
},
}
}
}
}
debug_assert!(self.closing.is_some(), "poll_server broke loop without closing");
debug_assert!(
self.closing.is_some(),
"poll_server broke loop without closing"
);
ready!(self.conn.poll_closed(cx).map_err(crate::Error::new_h2))?;
@@ -230,7 +232,7 @@ where
}
macro_rules! reply {
($me:expr, $res:expr, $eos:expr) => ({
($me:expr, $res:expr, $eos:expr) => {{
match $me.reply.send_response($res, $eos) {
Ok(tx) => tx,
Err(e) => {
@@ -239,7 +241,7 @@ macro_rules! reply {
return Poll::Ready(Err(crate::Error::new_h2(e)));
}
}
})
}};
}
impl<F, B, E> H2Stream<F, B>
@@ -261,8 +263,10 @@ where
Poll::Pending => {
// Response is not yet ready, so we want to check if the client has sent a
// RST_STREAM frame which would cancel the current request.
if let Poll::Ready(reason) =
me.reply.poll_reset(cx).map_err(|e| crate::Error::new_h2(e))?
if let Poll::Ready(reason) = me
.reply
.poll_reset(cx)
.map_err(|e| crate::Error::new_h2(e))?
{
debug!("stream received RST_STREAM: {:?}", reason);
return Poll::Ready(Err(crate::Error::new_h2(reason.into())));
@@ -274,7 +278,7 @@ where
warn!("http2 service errored: {}", err);
me.reply.send_reset(err.h2_reason());
return Poll::Ready(Err(err));
},
}
};
let (head, body) = res.into_parts();
@@ -282,13 +286,10 @@ where
super::strip_connection_headers(res.headers_mut(), false);
// set Date header if it isn't already set...
res
.headers_mut()
res.headers_mut()
.entry(::http::header::DATE)
.or_insert_with(crate::proto::h1::date::update_and_header_value);
// automatically set Content-Length from body...
if let Some(len) = body.size_hint().exact() {
headers::set_content_length_if_missing(res.headers_mut(), len);
@@ -301,7 +302,7 @@ where
reply!(me, res, true);
return Poll::Ready(Ok(()));
}
},
}
H2StreamState::Body(ref mut pipe) => {
return Pin::new(pipe).poll(cx);
}

View File

@@ -1,8 +1,8 @@
//! Pieces pertaining to the HTTP message protocol.
use http::{HeaderMap, Method, StatusCode, Uri, Version};
pub(crate) use self::h1::{dispatch, Conn, ServerTransaction};
use self::body_length::DecodedLength;
pub(crate) use self::h1::{dispatch, Conn, ServerTransaction};
pub(crate) mod h1;
pub(crate) mod h2;
@@ -76,9 +76,8 @@ mod body_length {
/// Converts to an Option<u64> representing a Known or Unknown length.
pub(crate) fn into_opt(self) -> Option<u64> {
match self {
DecodedLength::CHUNKED |
DecodedLength::CLOSE_DELIMITED => None,
DecodedLength(known) => Some(known)
DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => None,
DecodedLength(known) => Some(known),
}
}