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