style(lib): run rustfmt and enforce in CI
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
1018
src/proto/h1/role.rs
1018
src/proto/h1/role.rs
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user