style(lib): run rustfmt and enforce in CI
This commit is contained in:
		
							
								
								
									
										113
									
								
								src/body/body.rs
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								src/body/body.rs
									
									
									
									
									
								
							| @@ -4,15 +4,15 @@ use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use futures_core::Stream; // for mpsc::Receiver | ||||
| use futures_channel::{mpsc, oneshot}; | ||||
| use futures_core::Stream; // for mpsc::Receiver | ||||
| #[cfg(feature = "stream")] | ||||
| use futures_util::TryStreamExt; | ||||
| use http_body::{SizeHint, Body as HttpBody}; | ||||
| use http::HeaderMap; | ||||
| use http_body::{Body as HttpBody, SizeHint}; | ||||
|  | ||||
| use crate::common::{Future, Never, Pin, Poll, task}; | ||||
| use super::Chunk; | ||||
| use crate::common::{task, Future, Never, Pin, Poll}; | ||||
| use crate::upgrade::OnUpgrade; | ||||
|  | ||||
| type BodySender = mpsc::Sender<Result<Chunk, crate::Error>>; | ||||
| @@ -44,7 +44,9 @@ enum Kind { | ||||
|     // | ||||
|     // See https://github.com/rust-lang/rust/issues/57017 | ||||
|     #[cfg(feature = "stream")] | ||||
|     Wrapped(Pin<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>>), | ||||
|     Wrapped( | ||||
|         Pin<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>>, | ||||
|     ), | ||||
| } | ||||
|  | ||||
| struct Extra { | ||||
| @@ -161,8 +163,7 @@ impl Body { | ||||
|     /// | ||||
|     /// See [the `upgrade` module](::upgrade) for more. | ||||
|     pub fn on_upgrade(self) -> OnUpgrade { | ||||
|         self | ||||
|             .extra | ||||
|         self.extra | ||||
|             .map(|ex| ex.on_upgrade) | ||||
|             .unwrap_or_else(OnUpgrade::none) | ||||
|     } | ||||
| @@ -193,54 +194,44 @@ impl Body { | ||||
|     } | ||||
|  | ||||
|     fn take_delayed_eof(&mut self) -> Option<DelayEof> { | ||||
|         self | ||||
|             .extra | ||||
|         self.extra | ||||
|             .as_mut() | ||||
|             .and_then(|extra| extra.delayed_eof.take()) | ||||
|     } | ||||
|  | ||||
|     fn extra_mut(&mut self) -> &mut Extra { | ||||
|         self | ||||
|             .extra | ||||
|             .get_or_insert_with(|| Box::new(Extra { | ||||
|         self.extra.get_or_insert_with(|| { | ||||
|             Box::new(Extra { | ||||
|                 delayed_eof: None, | ||||
|                 on_upgrade: OnUpgrade::none(), | ||||
|             })) | ||||
|             }) | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn poll_eof(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Chunk>>> { | ||||
|         match self.take_delayed_eof() { | ||||
|             Some(DelayEof::NotEof(mut delay)) => { | ||||
|                 match self.poll_inner(cx) { | ||||
|                     ok @ Poll::Ready(Some(Ok(..))) | | ||||
|                     ok @ Poll::Pending => { | ||||
|                         self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay)); | ||||
|                         ok | ||||
|                     }, | ||||
|                     Poll::Ready(None) => match Pin::new(&mut delay).poll(cx) { | ||||
|                         Poll::Ready(Ok(never)) => match never {}, | ||||
|                         Poll::Pending => { | ||||
|                             self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); | ||||
|                             Poll::Pending | ||||
|                         }, | ||||
|                         Poll::Ready(Err(_done)) => { | ||||
|                             Poll::Ready(None) | ||||
|                         }, | ||||
|                     }, | ||||
|                     Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))), | ||||
|             Some(DelayEof::NotEof(mut delay)) => match self.poll_inner(cx) { | ||||
|                 ok @ Poll::Ready(Some(Ok(..))) | ok @ Poll::Pending => { | ||||
|                     self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay)); | ||||
|                     ok | ||||
|                 } | ||||
|             }, | ||||
|             Some(DelayEof::Eof(mut delay)) => { | ||||
|                 match Pin::new(&mut delay).poll(cx) { | ||||
|                 Poll::Ready(None) => match Pin::new(&mut delay).poll(cx) { | ||||
|                     Poll::Ready(Ok(never)) => match never {}, | ||||
|                     Poll::Pending => { | ||||
|                         self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); | ||||
|                         Poll::Pending | ||||
|                     }, | ||||
|                     Poll::Ready(Err(_done)) => { | ||||
|                         Poll::Ready(None) | ||||
|                     }, | ||||
|                     } | ||||
|                     Poll::Ready(Err(_done)) => Poll::Ready(None), | ||||
|                 }, | ||||
|                 Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))), | ||||
|             }, | ||||
|             Some(DelayEof::Eof(mut delay)) => match Pin::new(&mut delay).poll(cx) { | ||||
|                 Poll::Ready(Ok(never)) => match never {}, | ||||
|                 Poll::Pending => { | ||||
|                     self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); | ||||
|                     Poll::Pending | ||||
|                 } | ||||
|                 Poll::Ready(Err(_done)) => Poll::Ready(None), | ||||
|             }, | ||||
|             None => self.poll_inner(cx), | ||||
|         } | ||||
| @@ -268,25 +259,23 @@ impl Body { | ||||
|                     } | ||||
|                     None => Poll::Ready(None), | ||||
|                 } | ||||
|             }, | ||||
|             } | ||||
|             Kind::H2 { | ||||
|                 recv: ref mut h2, .. | ||||
|             } => match ready!(h2.poll_data(cx)) { | ||||
|                 Some(Ok(bytes)) => { | ||||
|                     let _ = h2.flow_control().release_capacity(bytes.len()); | ||||
|                     Poll::Ready(Some(Ok(Chunk::from(bytes)))) | ||||
|                 }, | ||||
|                 } | ||||
|                 Some(Err(e)) => Poll::Ready(Some(Err(crate::Error::new_body(e)))), | ||||
|                 None => Poll::Ready(None), | ||||
|             }, | ||||
|  | ||||
|             #[cfg(feature = "stream")] | ||||
|             Kind::Wrapped(ref mut s) => { | ||||
|                 match ready!(s.as_mut().poll_next(cx)) { | ||||
|                     Some(res) => Poll::Ready(Some(res.map_err(crate::Error::new_body))), | ||||
|                     None => Poll::Ready(None), | ||||
|                 } | ||||
|             } | ||||
|             Kind::Wrapped(ref mut s) => match ready!(s.as_mut().poll_next(cx)) { | ||||
|                 Some(res) => Poll::Ready(Some(res.map_err(crate::Error::new_body))), | ||||
|                 None => Poll::Ready(None), | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -311,13 +300,21 @@ impl HttpBody for Body { | ||||
|     type Data = Chunk; | ||||
|     type Error = crate::Error; | ||||
|  | ||||
|     fn poll_data(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> { | ||||
|     fn poll_data( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<Result<Self::Data, Self::Error>>> { | ||||
|         self.poll_eof(cx) | ||||
|     } | ||||
|  | ||||
|     fn poll_trailers(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|     fn poll_trailers( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|         match self.kind { | ||||
|             Kind::H2 { recv: ref mut h2, .. } => match ready!(h2.poll_trailers(cx)) { | ||||
|             Kind::H2 { | ||||
|                 recv: ref mut h2, .. | ||||
|             } => match ready!(h2.poll_trailers(cx)) { | ||||
|                 Ok(t) => Poll::Ready(Ok(t)), | ||||
|                 Err(e) => Poll::Ready(Err(crate::Error::new_h2(e))), | ||||
|             }, | ||||
| @@ -341,10 +338,8 @@ impl HttpBody for Body { | ||||
|                 let mut hint = SizeHint::default(); | ||||
|                 hint.set_exact(val.len() as u64); | ||||
|                 hint | ||||
|             }, | ||||
|             Kind::Once(None) => { | ||||
|                 SizeHint::default() | ||||
|             }, | ||||
|             } | ||||
|             Kind::Once(None) => SizeHint::default(), | ||||
|             #[cfg(feature = "stream")] | ||||
|             Kind::Wrapped(..) => SizeHint::default(), | ||||
|             Kind::Chan { content_length, .. } | Kind::H2 { content_length, .. } => { | ||||
| @@ -355,7 +350,7 @@ impl HttpBody for Body { | ||||
|                 } | ||||
|  | ||||
|                 hint | ||||
|             }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -393,14 +388,12 @@ impl Stream for Body { | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// # Optional | ||||
| /// | ||||
| /// This function requires enabling the `stream` feature in your | ||||
| /// `Cargo.toml`. | ||||
| #[cfg(feature = "stream")] | ||||
| impl | ||||
|     From<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>> | ||||
| impl From<Box<dyn Stream<Item = Result<Chunk, Box<dyn StdError + Send + Sync>>> + Send + Sync>> | ||||
|     for Body | ||||
| { | ||||
|     #[inline] | ||||
| @@ -487,13 +480,17 @@ impl Sender { | ||||
|             Poll::Pending => (), // fallthrough | ||||
|         } | ||||
|  | ||||
|         self.tx.poll_ready(cx).map_err(|_| crate::Error::new_closed()) | ||||
|         self.tx | ||||
|             .poll_ready(cx) | ||||
|             .map_err(|_| crate::Error::new_closed()) | ||||
|     } | ||||
|  | ||||
|     /// Send data on this channel when it is ready. | ||||
|     pub async fn send_data(&mut self, chunk: Chunk) -> crate::Result<()> { | ||||
|         futures_util::future::poll_fn(|cx| self.poll_ready(cx)).await?; | ||||
|         self.tx.try_send(Ok(chunk)).map_err(|_| crate::Error::new_closed()) | ||||
|         self.tx | ||||
|             .try_send(Ok(chunk)) | ||||
|             .map_err(|_| crate::Error::new_closed()) | ||||
|     } | ||||
|  | ||||
|     /// Try to send data on this channel. | ||||
|   | ||||
| @@ -19,7 +19,6 @@ pub struct IntoIter { | ||||
|     inner: <Bytes as IntoIterator>::IntoIter, | ||||
| } | ||||
|  | ||||
|  | ||||
| impl Chunk { | ||||
|     /// Converts this `Chunk` directly into the `Bytes` type without copies. | ||||
|     /// | ||||
| @@ -82,9 +81,7 @@ impl From<&'static str> for Chunk { | ||||
| impl From<Bytes> for Chunk { | ||||
|     #[inline] | ||||
|     fn from(bytes: Bytes) -> Chunk { | ||||
|         Chunk { | ||||
|             bytes: bytes, | ||||
|         } | ||||
|         Chunk { bytes: bytes } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -176,4 +173,3 @@ mod tests { | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -59,4 +59,3 @@ fn _assert_send_sync() { | ||||
|     _assert_send::<Chunk>(); | ||||
|     _assert_sync::<Chunk>(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use std::error::Error as StdError; | ||||
| use bytes::Buf; | ||||
| use http::HeaderMap; | ||||
|  | ||||
| use crate::common::{Pin, Poll, task}; | ||||
| use crate::common::{task, Pin, Poll}; | ||||
| use http_body::{Body as HttpBody, SizeHint}; | ||||
|  | ||||
| /// This trait represents a streaming body of a `Request` or `Response`. | ||||
| @@ -21,14 +21,20 @@ pub trait Payload: sealed::Sealed + Send + 'static { | ||||
|     /// | ||||
|     /// Similar to `Stream::poll_next`, this yields `Some(Data)` until | ||||
|     /// the body ends, when it yields `None`. | ||||
|     fn poll_data(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>>; | ||||
|     fn poll_data( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<Result<Self::Data, Self::Error>>>; | ||||
|  | ||||
|     /// Poll for an optional **single** `HeaderMap` of trailers. | ||||
|     /// | ||||
|     /// This should **only** be called after `poll_data` has ended. | ||||
|     /// | ||||
|     /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. | ||||
|     fn poll_trailers(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|     fn poll_trailers( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|         drop(cx); | ||||
|         Poll::Ready(Ok(None)) | ||||
|     } | ||||
| @@ -61,7 +67,6 @@ pub trait Payload: sealed::Sealed + Send + 'static { | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<T> Payload for T | ||||
| where | ||||
|     T: HttpBody + Send + 'static, | ||||
| @@ -71,11 +76,17 @@ where | ||||
|     type Data = T::Data; | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn poll_data(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> { | ||||
|     fn poll_data( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<Result<Self::Data, Self::Error>>> { | ||||
|         HttpBody::poll_data(self, cx) | ||||
|     } | ||||
|  | ||||
|     fn poll_trailers(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|     fn poll_trailers( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|         HttpBody::poll_trailers(self, cx) | ||||
|     } | ||||
|  | ||||
| @@ -127,5 +138,3 @@ impl<E: Payload> Payload for Box<E> { | ||||
|     } | ||||
| } | ||||
| */ | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -17,19 +17,14 @@ use pin_project::{pin_project, project}; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
| use tower_service::Service; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{BoxSendFuture, Exec, Executor, Future, Pin, Poll, task}; | ||||
| use crate::upgrade::Upgraded; | ||||
| use crate::proto; | ||||
| use super::dispatch; | ||||
| use crate::body::Payload; | ||||
| use crate::common::{task, BoxSendFuture, Exec, Executor, Future, Pin, Poll}; | ||||
| use crate::proto; | ||||
| use crate::upgrade::Upgraded; | ||||
| use crate::{Body, Request, Response}; | ||||
|  | ||||
| type Http1Dispatcher<T, B, R> = proto::dispatch::Dispatcher< | ||||
|     proto::dispatch::Client<B>, | ||||
|     B, | ||||
|     T, | ||||
|     R, | ||||
| >; | ||||
| type Http1Dispatcher<T, B, R> = proto::dispatch::Dispatcher<proto::dispatch::Client<B>, B, T, R>; | ||||
|  | ||||
| #[pin_project] | ||||
| enum ProtoClient<T, B> | ||||
| @@ -46,18 +41,16 @@ where | ||||
| const DEFAULT_HTTP2_CONN_WINDOW: u32 = 1024 * 1024 * 5; // 5mb | ||||
| const DEFAULT_HTTP2_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb | ||||
|  | ||||
|  | ||||
|  | ||||
| /// Returns a handshake future over some IO. | ||||
| /// | ||||
| /// This is a shortcut for `Builder::new().handshake(io)`. | ||||
| pub async fn handshake<T>(io: T) -> crate::Result<(SendRequest<crate::Body>, Connection<T, crate::Body>)> | ||||
| pub async fn handshake<T>( | ||||
|     io: T, | ||||
| ) -> crate::Result<(SendRequest<crate::Body>, Connection<T, crate::Body>)> | ||||
| where | ||||
|     T: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
| { | ||||
|     Builder::new() | ||||
|         .handshake(io) | ||||
|         .await | ||||
|     Builder::new().handshake(io).await | ||||
| } | ||||
|  | ||||
| /// The sender side of an established connection. | ||||
| @@ -65,7 +58,6 @@ pub struct SendRequest<B> { | ||||
|     dispatch: dispatch::Sender<Request<B>, Response<Body>>, | ||||
| } | ||||
|  | ||||
|  | ||||
| /// A future that processes all HTTP state for the IO object. | ||||
| /// | ||||
| /// In most cases, this should just be spawned into an executor, so that it | ||||
| @@ -79,7 +71,6 @@ where | ||||
|     inner: Option<ProtoClient<T, B>>, | ||||
| } | ||||
|  | ||||
|  | ||||
| /// A builder to configure an HTTP connection. | ||||
| /// | ||||
| /// After setting options, the builder is used to create a handshake future. | ||||
| @@ -99,7 +90,7 @@ pub struct Builder { | ||||
| /// Yields a `Response` if successful. | ||||
| #[must_use = "futures do nothing unless polled"] | ||||
| pub struct ResponseFuture { | ||||
|     inner: ResponseFutureState | ||||
|     inner: ResponseFutureState, | ||||
| } | ||||
|  | ||||
| enum ResponseFutureState { | ||||
| @@ -139,8 +130,7 @@ pub(super) struct Http2SendRequest<B> { | ||||
|  | ||||
| // ===== impl SendRequest | ||||
|  | ||||
| impl<B> SendRequest<B> | ||||
| { | ||||
| impl<B> SendRequest<B> { | ||||
|     /// Polls to determine whether this sender can be used yet for a request. | ||||
|     /// | ||||
|     /// If the associated connection is closed, this returns an Error. | ||||
| @@ -148,7 +138,7 @@ impl<B> SendRequest<B> | ||||
|         self.dispatch.poll_ready(cx) | ||||
|     } | ||||
|  | ||||
|     pub(super) fn when_ready(self) -> impl Future<Output=crate::Result<Self>> { | ||||
|     pub(super) fn when_ready(self) -> impl Future<Output = crate::Result<Self>> { | ||||
|         let mut me = Some(self); | ||||
|         future::poll_fn(move |cx| { | ||||
|             ready!(me.as_mut().unwrap().poll_ready(cx))?; | ||||
| @@ -218,9 +208,7 @@ where | ||||
|     /// ``` | ||||
|     pub fn send_request(&mut self, req: Request<B>) -> ResponseFuture { | ||||
|         let inner = match self.dispatch.send(req) { | ||||
|             Ok(rx) => { | ||||
|                 ResponseFutureState::Waiting(rx) | ||||
|             }, | ||||
|             Ok(rx) => ResponseFutureState::Waiting(rx), | ||||
|             Err(_req) => { | ||||
|                 debug!("connection was not ready"); | ||||
|                 let err = crate::Error::new_canceled().with("connection was not ready"); | ||||
| @@ -228,12 +216,13 @@ where | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         ResponseFuture { | ||||
|             inner, | ||||
|         } | ||||
|         ResponseFuture { inner } | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> + Unpin | ||||
|     pub(crate) fn send_request_retryable( | ||||
|         &mut self, | ||||
|         req: Request<B>, | ||||
|     ) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> + Unpin | ||||
|     where | ||||
|         B: Send, | ||||
|     { | ||||
| @@ -247,7 +236,7 @@ where | ||||
|                         Err(_) => panic!("dispatch dropped without returning error"), | ||||
|                     } | ||||
|                 })) | ||||
|             }, | ||||
|             } | ||||
|             Err(req) => { | ||||
|                 debug!("connection was not ready"); | ||||
|                 let err = crate::Error::new_canceled().with("connection was not ready"); | ||||
| @@ -259,7 +248,8 @@ where | ||||
|  | ||||
| impl<B> Service<Request<B>> for SendRequest<B> | ||||
| where | ||||
|     B: Payload + 'static, { | ||||
|     B: Payload + 'static, | ||||
| { | ||||
|     type Response = Response<Body>; | ||||
|     type Error = crate::Error; | ||||
|     type Future = ResponseFuture; | ||||
| @@ -275,8 +265,7 @@ where | ||||
|  | ||||
| impl<B> fmt::Debug for SendRequest<B> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("SendRequest") | ||||
|             .finish() | ||||
|         f.debug_struct("SendRequest").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -296,7 +285,10 @@ impl<B> Http2SendRequest<B> | ||||
| where | ||||
|     B: Payload + 'static, | ||||
| { | ||||
|     pub(super) fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output=Result<Response<Body>, (crate::Error, Option<Request<B>>)>> | ||||
|     pub(super) fn send_request_retryable( | ||||
|         &mut self, | ||||
|         req: Request<B>, | ||||
|     ) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> | ||||
|     where | ||||
|         B: Send, | ||||
|     { | ||||
| @@ -310,7 +302,7 @@ where | ||||
|                         Err(_) => panic!("dispatch dropped without returning error"), | ||||
|                     } | ||||
|                 })) | ||||
|             }, | ||||
|             } | ||||
|             Err(req) => { | ||||
|                 debug!("connection was not ready"); | ||||
|                 let err = crate::Error::new_canceled().with("connection was not ready"); | ||||
| @@ -322,8 +314,7 @@ where | ||||
|  | ||||
| impl<B> fmt::Debug for Http2SendRequest<B> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Http2SendRequest") | ||||
|             .finish() | ||||
|         f.debug_struct("Http2SendRequest").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -374,18 +365,14 @@ where | ||||
|     /// to work with this function; or use the `without_shutdown` wrapper. | ||||
|     pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||
|         match self.inner.as_mut().expect("already upgraded") { | ||||
|             &mut ProtoClient::H1(ref mut h1) => { | ||||
|                 h1.poll_without_shutdown(cx) | ||||
|             }, | ||||
|             &mut ProtoClient::H2(ref mut h2) => { | ||||
|                 Pin::new(h2).poll(cx).map_ok(|_| ()) | ||||
|             } | ||||
|             &mut ProtoClient::H1(ref mut h1) => h1.poll_without_shutdown(cx), | ||||
|             &mut ProtoClient::H2(ref mut h2) => Pin::new(h2).poll(cx).map_ok(|_| ()), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Prevent shutdown of the underlying IO object at the end of service the request, | ||||
|     /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`. | ||||
|     pub fn without_shutdown(self) -> impl Future<Output=crate::Result<Parts<T>>> { | ||||
|     pub fn without_shutdown(self) -> impl Future<Output = crate::Result<Parts<T>>> { | ||||
|         let mut conn = Some(self); | ||||
|         future::poll_fn(move |cx| -> Poll<crate::Result<Parts<T>>> { | ||||
|             ready!(conn.as_mut().unwrap().poll_without_shutdown(cx))?; | ||||
| @@ -404,9 +391,7 @@ where | ||||
|  | ||||
|     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||
|         match ready!(Pin::new(self.inner.as_mut().unwrap()).poll(cx))? { | ||||
|             proto::Dispatched::Shutdown => { | ||||
|                 Poll::Ready(Ok(())) | ||||
|             }, | ||||
|             proto::Dispatched::Shutdown => Poll::Ready(Ok(())), | ||||
|             proto::Dispatched::Upgrade(pending) => { | ||||
|                 let h1 = match mem::replace(&mut self.inner, None) { | ||||
|                     Some(ProtoClient::H1(h1)) => h1, | ||||
| @@ -427,8 +412,7 @@ where | ||||
|     B: Payload + 'static, | ||||
| { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Connection") | ||||
|             .finish() | ||||
|         f.debug_struct("Connection").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -519,7 +503,10 @@ impl Builder { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|     pub fn http2_initial_connection_window_size( | ||||
|         &mut self, | ||||
|         sz: impl Into<Option<u32>>, | ||||
|     ) -> &mut Self { | ||||
|         if let Some(sz) = sz.into() { | ||||
|             self.h2_builder.initial_connection_window_size(sz); | ||||
|         } | ||||
| @@ -527,7 +514,10 @@ impl Builder { | ||||
|     } | ||||
|  | ||||
|     /// Constructs a connection with the configured options and IO. | ||||
|     pub fn handshake<T, B>(&self, io: T) -> impl Future<Output = crate::Result<(SendRequest<B>, Connection<T, B>)>> | ||||
|     pub fn handshake<T, B>( | ||||
|         &self, | ||||
|         io: T, | ||||
|     ) -> impl Future<Output = crate::Result<(SendRequest<B>, Connection<T, B>)>> | ||||
|     where | ||||
|         T: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|         B: Payload + 'static, | ||||
| @@ -563,12 +553,8 @@ impl Builder { | ||||
|             }; | ||||
|  | ||||
|             Ok(( | ||||
|                 SendRequest { | ||||
|                     dispatch: tx, | ||||
|                 }, | ||||
|                 Connection { | ||||
|                     inner: Some(proto), | ||||
|                 }, | ||||
|                 SendRequest { dispatch: tx }, | ||||
|                 Connection { inner: Some(proto) }, | ||||
|             )) | ||||
|         } | ||||
|     } | ||||
| @@ -588,7 +574,7 @@ impl Future for ResponseFuture { | ||||
|                     // this is definite bug if it happens, but it shouldn't happen! | ||||
|                     Err(_canceled) => panic!("dispatch dropped without returning error"), | ||||
|                 }) | ||||
|             }, | ||||
|             } | ||||
|             ResponseFutureState::Error(ref mut err) => { | ||||
|                 Poll::Ready(Err(err.take().expect("polled after ready"))) | ||||
|             } | ||||
| @@ -598,8 +584,7 @@ impl Future for ResponseFuture { | ||||
|  | ||||
| impl fmt::Debug for ResponseFuture { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("ResponseFuture") | ||||
|             .finish() | ||||
|         f.debug_struct("ResponseFuture").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -628,7 +613,6 @@ where | ||||
| trait AssertSend: Send {} | ||||
| trait AssertSendSync: Send + Sync {} | ||||
|  | ||||
|  | ||||
| #[doc(hidden)] | ||||
| impl<B: Send> AssertSendSync for SendRequest<B> {} | ||||
|  | ||||
| @@ -637,7 +621,8 @@ impl<T: Send, B: Send> AssertSend for Connection<T, B> | ||||
| where | ||||
|     T: AsyncRead + AsyncWrite + Send + 'static, | ||||
|     B: Payload + 'static, | ||||
| {} | ||||
| { | ||||
| } | ||||
|  | ||||
| #[doc(hidden)] | ||||
| impl<T: Send + Sync, B: Send + Sync> AssertSendSync for Connection<T, B> | ||||
| @@ -645,11 +630,11 @@ where | ||||
|     T: AsyncRead + AsyncWrite + Send + 'static, | ||||
|     B: Payload + 'static, | ||||
|     B::Data: Send + Sync + 'static, | ||||
| {} | ||||
| { | ||||
| } | ||||
|  | ||||
| #[doc(hidden)] | ||||
| impl AssertSendSync for Builder {} | ||||
|  | ||||
| #[doc(hidden)] | ||||
| impl AssertSend for ResponseFuture {} | ||||
|  | ||||
|   | ||||
| @@ -22,11 +22,11 @@ | ||||
| //! }); | ||||
| //! ``` | ||||
| use std::error::Error; | ||||
| use std::future::Future; | ||||
| use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; | ||||
| use std::pin::Pin; | ||||
| use std::str::FromStr; | ||||
| use std::task::{self, Poll}; | ||||
| use std::pin::Pin; | ||||
| use std::future::Future; | ||||
| use std::{fmt, io, vec}; | ||||
|  | ||||
| use tokio::task::JoinHandle; | ||||
| @@ -394,7 +394,8 @@ mod tests { | ||||
|         let dst = ::http::Uri::from_static("http://[::1]:8080/"); | ||||
|  | ||||
|         let mut addrs = | ||||
|             IpAddrs::try_parse(dst.host().expect("host"), dst.port_u16().expect("port")).expect("try_parse"); | ||||
|             IpAddrs::try_parse(dst.host().expect("host"), dst.port_u16().expect("port")) | ||||
|                 .expect("try_parse"); | ||||
|  | ||||
|         let expected = "[::1]:8080".parse::<SocketAddr>().expect("expected"); | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| use std::error::Error as StdError; | ||||
| use std::future::Future; | ||||
| use std::marker::PhantomData; | ||||
| use std::pin::Pin; | ||||
| use std::task::{self, Poll}; | ||||
| use std::fmt; | ||||
| use std::future::Future; | ||||
| use std::io; | ||||
| use std::marker::PhantomData; | ||||
| use std::net::{IpAddr, SocketAddr}; | ||||
| use std::pin::Pin; | ||||
| use std::sync::Arc; | ||||
| use std::task::{self, Poll}; | ||||
| use std::time::Duration; | ||||
|  | ||||
| use futures_util::future::Either; | ||||
| @@ -20,7 +20,6 @@ use super::dns::{self, resolve, GaiResolver, Resolve}; | ||||
| use super::{Connected, Connection}; | ||||
| //#[cfg(feature = "runtime")] use super::dns::TokioThreadpoolGaiResolver; | ||||
|  | ||||
|  | ||||
| /// A connector for the `http` scheme. | ||||
| /// | ||||
| /// Performs DNS resolution in a thread pool, and then connects over TCP. | ||||
| @@ -256,10 +255,7 @@ impl<R> HttpConnector<R> | ||||
| where | ||||
|     R: Resolve, | ||||
| { | ||||
|     async fn call_async( | ||||
|         &mut self, | ||||
|         dst: Uri, | ||||
|     ) -> Result<TcpStream, ConnectError> { | ||||
|     async fn call_async(&mut self, dst: Uri) -> Result<TcpStream, ConnectError> { | ||||
|         trace!( | ||||
|             "Http::connect; scheme={:?}, host={:?}, port={:?}", | ||||
|             dst.scheme(), | ||||
| @@ -292,7 +288,13 @@ where | ||||
|         }; | ||||
|         let port = match dst.port() { | ||||
|             Some(port) => port.as_u16(), | ||||
|             None => if dst.scheme() == Some(&Scheme::HTTPS) { 443 } else { 80 }, | ||||
|             None => { | ||||
|                 if dst.scheme() == Some(&Scheme::HTTPS) { | ||||
|                     443 | ||||
|                 } else { | ||||
|                     80 | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let config = &self.config; | ||||
| @@ -348,9 +350,7 @@ impl Connection for TcpStream { | ||||
|     fn connected(&self) -> Connected { | ||||
|         let connected = Connected::new(); | ||||
|         if let Ok(remote_addr) = self.peer_addr() { | ||||
|             connected.extra(HttpInfo { | ||||
|                 remote_addr, | ||||
|             }) | ||||
|             connected.extra(HttpInfo { remote_addr }) | ||||
|         } else { | ||||
|             connected | ||||
|         } | ||||
| @@ -389,7 +389,6 @@ impl<R: Resolve> Future for HttpConnecting<R> { | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| // Not publicly exported (so missing_docs doesn't trigger). | ||||
| pub struct ConnectError { | ||||
|     msg: Box<str>, | ||||
| @@ -531,14 +530,7 @@ impl ConnectingTcpRemote { | ||||
|         let mut err = None; | ||||
|         for addr in &mut self.addrs { | ||||
|             debug!("connecting to {}", addr); | ||||
|             match connect( | ||||
|                 &addr, | ||||
|                 local_addr, | ||||
|                 reuse_address, | ||||
|                 self.connect_timeout, | ||||
|             )? | ||||
|             .await | ||||
|             { | ||||
|             match connect(&addr, local_addr, reuse_address, self.connect_timeout)?.await { | ||||
|                 Ok(tcp) => { | ||||
|                     debug!("connected to {:?}", tcp.peer_addr().ok()); | ||||
|                     return Ok(tcp); | ||||
| @@ -606,13 +598,9 @@ impl ConnectingTcp { | ||||
|             .. | ||||
|         } = self; | ||||
|         match self.fallback { | ||||
|             None => { | ||||
|                 self.preferred | ||||
|                     .connect(local_addr, reuse_address) | ||||
|                     .await | ||||
|             } | ||||
|             None => self.preferred.connect(local_addr, reuse_address).await, | ||||
|             Some(mut fallback) => { | ||||
|                 let preferred_fut = self.preferred.connect(local_addr,  reuse_address); | ||||
|                 let preferred_fut = self.preferred.connect(local_addr, reuse_address); | ||||
|                 futures_util::pin_mut!(preferred_fut); | ||||
|  | ||||
|                 let fallback_fut = fallback.remote.connect(local_addr, reuse_address); | ||||
| @@ -652,10 +640,7 @@ mod tests { | ||||
|     use super::super::sealed::Connect; | ||||
|     use super::HttpConnector; | ||||
|  | ||||
|     async fn connect<C>( | ||||
|         connector: C, | ||||
|         dst: Uri, | ||||
|     ) -> Result<C::Transport, C::Error> | ||||
|     async fn connect<C>(connector: C, dst: Uri) -> Result<C::Transport, C::Error> | ||||
|     where | ||||
|         C: Connect, | ||||
|     { | ||||
| @@ -795,7 +780,6 @@ mod tests { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|  | ||||
|             let (start, stream) = rt | ||||
|                 .block_on(async move { | ||||
|                     let addrs = hosts | ||||
|   | ||||
| @@ -7,11 +7,14 @@ | ||||
| //! - Types to build custom connectors. | ||||
| use std::fmt; | ||||
|  | ||||
| use ::http::{Response}; | ||||
| use ::http::Response; | ||||
|  | ||||
| #[cfg(feature = "tcp")] pub mod dns; | ||||
| #[cfg(feature = "tcp")] mod http; | ||||
| #[cfg(feature = "tcp")] pub use self::http::{HttpConnector, HttpInfo}; | ||||
| #[cfg(feature = "tcp")] | ||||
| pub mod dns; | ||||
| #[cfg(feature = "tcp")] | ||||
| mod http; | ||||
| #[cfg(feature = "tcp")] | ||||
| pub use self::http::{HttpConnector, HttpInfo}; | ||||
|  | ||||
| /// Describes a type returned by a connector. | ||||
| pub trait Connection { | ||||
| @@ -115,8 +118,7 @@ impl Clone for Extra { | ||||
|  | ||||
| impl fmt::Debug for Extra { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Extra") | ||||
|             .finish() | ||||
|         f.debug_struct("Extra").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -133,7 +135,7 @@ struct ExtraEnvelope<T>(T); | ||||
|  | ||||
| impl<T> ExtraInner for ExtraEnvelope<T> | ||||
| where | ||||
|     T: Clone + Send + Sync + 'static | ||||
|     T: Clone + Send + Sync + 'static, | ||||
| { | ||||
|     fn clone_box(&self) -> Box<dyn ExtraInner> { | ||||
|         Box::new(self.clone()) | ||||
| @@ -154,7 +156,7 @@ impl<T: Clone> Clone for ExtraChain<T> { | ||||
|  | ||||
| impl<T> ExtraInner for ExtraChain<T> | ||||
| where | ||||
|     T: Clone + Send + Sync + 'static | ||||
|     T: Clone + Send + Sync + 'static, | ||||
| { | ||||
|     fn clone_box(&self) -> Box<dyn ExtraInner> { | ||||
|         Box::new(self.clone()) | ||||
| @@ -172,8 +174,8 @@ pub(super) mod sealed { | ||||
|     use ::http::Uri; | ||||
|     use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
|     use super::Connection; | ||||
|     use crate::common::{Future, Unpin}; | ||||
|     use super::{Connection}; | ||||
|  | ||||
|     /// Connect to a destination, returning an IO transport. | ||||
|     /// | ||||
| @@ -193,14 +195,14 @@ pub(super) mod sealed { | ||||
|         /// An error occured when trying to connect. | ||||
|         type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|         /// A Future that will resolve to the connected Transport. | ||||
|         type Future: Future<Output=Result<Self::Transport, Self::Error>>; | ||||
|         type Future: Future<Output = Result<Self::Transport, Self::Error>>; | ||||
|         #[doc(hidden)] | ||||
|         fn connect(self, internal_only: Internal, dst: Uri) -> Self::Future; | ||||
|     } | ||||
|  | ||||
|     impl<S, T> Connect for S | ||||
|     where | ||||
|         S: tower_service::Service<Uri, Response=T> + Send, | ||||
|         S: tower_service::Service<Uri, Response = T> + Send, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         S::Future: Unpin + Send, | ||||
|         T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static, | ||||
| @@ -215,11 +217,12 @@ pub(super) mod sealed { | ||||
|  | ||||
|     impl<S, T> Sealed for S | ||||
|     where | ||||
|         S: tower_service::Service<Uri, Response=T> + Send, | ||||
|         S: tower_service::Service<Uri, Response = T> + Send, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         S::Future: Unpin + Send, | ||||
|         T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static, | ||||
|     {} | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     pub trait Sealed {} | ||||
|     #[allow(missing_debug_implementations)] | ||||
| @@ -228,7 +231,7 @@ pub(super) mod sealed { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::{Connected}; | ||||
|     use super::Connected; | ||||
|  | ||||
|     #[derive(Clone, Debug, PartialEq)] | ||||
|     struct Ex1(usize); | ||||
| @@ -241,18 +244,13 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_connected_extra() { | ||||
|         let c1 = Connected::new() | ||||
|             .extra(Ex1(41)); | ||||
|         let c1 = Connected::new().extra(Ex1(41)); | ||||
|  | ||||
|         let mut res1 = crate::Response::new(crate::Body::empty()); | ||||
|  | ||||
|         assert_eq!(res1.extensions().get::<Ex1>(), None); | ||||
|  | ||||
|         c1 | ||||
|             .extra | ||||
|             .as_ref() | ||||
|             .expect("c1 extra") | ||||
|             .set(&mut res1); | ||||
|         c1.extra.as_ref().expect("c1 extra").set(&mut res1); | ||||
|  | ||||
|         assert_eq!(res1.extensions().get::<Ex1>(), Some(&Ex1(41))); | ||||
|     } | ||||
| @@ -273,11 +271,7 @@ mod tests { | ||||
|         assert_eq!(res1.extensions().get::<Ex2>(), None); | ||||
|         assert_eq!(res1.extensions().get::<Ex3>(), None); | ||||
|  | ||||
|         c1 | ||||
|             .extra | ||||
|             .as_ref() | ||||
|             .expect("c1 extra") | ||||
|             .set(&mut res1); | ||||
|         c1.extra.as_ref().expect("c1 extra").set(&mut res1); | ||||
|  | ||||
|         assert_eq!(res1.extensions().get::<Ex1>(), Some(&Ex1(45))); | ||||
|         assert_eq!(res1.extensions().get::<Ex2>(), Some(&Ex2("zoom"))); | ||||
| @@ -291,11 +285,7 @@ mod tests { | ||||
|  | ||||
|         let mut res2 = crate::Response::new(crate::Body::empty()); | ||||
|  | ||||
|         c2 | ||||
|             .extra | ||||
|             .as_ref() | ||||
|             .expect("c2 extra") | ||||
|             .set(&mut res2); | ||||
|         c2.extra.as_ref().expect("c2 extra").set(&mut res2); | ||||
|  | ||||
|         assert_eq!(res2.extensions().get::<Ex1>(), Some(&Ex1(99))); | ||||
|         assert_eq!(res2.extensions().get::<Ex2>(), Some(&Ex2("hiccup"))); | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| use futures_core::Stream; | ||||
| use futures_channel::{mpsc, oneshot}; | ||||
| use futures_core::Stream; | ||||
| use futures_util::future; | ||||
|  | ||||
| use crate::common::{Future, Pin, Poll, task}; | ||||
| use crate::common::{task, Future, Pin, Poll}; | ||||
|  | ||||
| pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>; | ||||
| pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>; | ||||
| @@ -52,7 +52,8 @@ pub struct UnboundedSender<T, U> { | ||||
|  | ||||
| impl<T, U> Sender<T, U> { | ||||
|     pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||
|         self.giver.poll_want(cx) | ||||
|         self.giver | ||||
|             .poll_want(cx) | ||||
|             .map_err(|_| crate::Error::new_closed()) | ||||
|     } | ||||
|  | ||||
| @@ -82,7 +83,8 @@ impl<T, U> Sender<T, U> { | ||||
|             return Err(val); | ||||
|         } | ||||
|         let (tx, rx) = oneshot::channel(); | ||||
|         self.inner.unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) | ||||
|         self.inner | ||||
|             .unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) | ||||
|             .map(move |_| rx) | ||||
|             .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) | ||||
|     } | ||||
| @@ -92,7 +94,8 @@ impl<T, U> Sender<T, U> { | ||||
|             return Err(val); | ||||
|         } | ||||
|         let (tx, rx) = oneshot::channel(); | ||||
|         self.inner.unbounded_send(Envelope(Some((val, Callback::NoRetry(tx))))) | ||||
|         self.inner | ||||
|             .unbounded_send(Envelope(Some((val, Callback::NoRetry(tx))))) | ||||
|             .map(move |_| rx) | ||||
|             .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) | ||||
|     } | ||||
| @@ -116,7 +119,8 @@ impl<T, U> UnboundedSender<T, U> { | ||||
|  | ||||
|     pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> { | ||||
|         let (tx, rx) = oneshot::channel(); | ||||
|         self.inner.unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) | ||||
|         self.inner | ||||
|             .unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) | ||||
|             .map(move |_| rx) | ||||
|             .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) | ||||
|     } | ||||
| @@ -137,15 +141,18 @@ pub struct Receiver<T, U> { | ||||
| } | ||||
|  | ||||
| impl<T, U> Receiver<T, U> { | ||||
|     pub(crate) fn poll_next(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<(T, Callback<T, U>)>> { | ||||
|     pub(crate) fn poll_next( | ||||
|         &mut self, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<(T, Callback<T, U>)>> { | ||||
|         match Pin::new(&mut self.inner).poll_next(cx) { | ||||
|             Poll::Ready(item) => Poll::Ready(item.map(|mut env| { | ||||
|                 env.0.take().expect("envelope not dropped") | ||||
|             })), | ||||
|             Poll::Ready(item) => { | ||||
|                 Poll::Ready(item.map(|mut env| env.0.take().expect("envelope not dropped"))) | ||||
|             } | ||||
|             Poll::Pending => { | ||||
|                 self.taker.want(); | ||||
|                 Poll::Pending | ||||
|             }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -176,7 +183,10 @@ struct Envelope<T, U>(Option<(T, Callback<T, U>)>); | ||||
| impl<T, U> Drop for Envelope<T, U> { | ||||
|     fn drop(&mut self) { | ||||
|         if let Some((val, cb)) = self.0.take() { | ||||
|             let _ = cb.send(Err((crate::Error::new_canceled().with("connection closed"), Some(val)))); | ||||
|             let _ = cb.send(Err(( | ||||
|                 crate::Error::new_canceled().with("connection closed"), | ||||
|                 Some(val), | ||||
|             ))); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -205,7 +215,7 @@ impl<T, U> Callback<T, U> { | ||||
|         match self { | ||||
|             Callback::Retry(tx) => { | ||||
|                 let _ = tx.send(val); | ||||
|             }, | ||||
|             } | ||||
|             Callback::NoRetry(tx) => { | ||||
|                 let _ = tx.send(val.map_err(|e| e.0)); | ||||
|             } | ||||
| @@ -214,29 +224,25 @@ impl<T, U> Callback<T, U> { | ||||
|  | ||||
|     pub(crate) fn send_when( | ||||
|         self, | ||||
|         mut when: impl Future<Output=Result<U, (crate::Error, Option<T>)>> + Unpin, | ||||
|     ) -> impl Future<Output=()> { | ||||
|         mut when: impl Future<Output = Result<U, (crate::Error, Option<T>)>> + Unpin, | ||||
|     ) -> impl Future<Output = ()> { | ||||
|         let mut cb = Some(self); | ||||
|  | ||||
|         // "select" on this callback being canceled, and the future completing | ||||
|         future::poll_fn(move |cx| { | ||||
|             match Pin::new(&mut when).poll(cx) { | ||||
|                 Poll::Ready(Ok(res)) => { | ||||
|                     cb.take() | ||||
|                         .expect("polled after complete") | ||||
|                         .send(Ok(res)); | ||||
|                     cb.take().expect("polled after complete").send(Ok(res)); | ||||
|                     Poll::Ready(()) | ||||
|                 }, | ||||
|                 } | ||||
|                 Poll::Pending => { | ||||
|                     // check if the callback is canceled | ||||
|                     ready!(cb.as_mut().unwrap().poll_canceled(cx)); | ||||
|                     trace!("send_when canceled"); | ||||
|                     Poll::Ready(()) | ||||
|                 }, | ||||
|                 } | ||||
|                 Poll::Ready(Err(err)) => { | ||||
|                     cb.take() | ||||
|                         .expect("polled after complete") | ||||
|                         .send(Err(err)); | ||||
|                     cb.take().expect("polled after complete").send(Err(err)); | ||||
|                     Poll::Ready(()) | ||||
|                 } | ||||
|             } | ||||
| @@ -253,7 +259,7 @@ mod tests { | ||||
|     use std::pin::Pin; | ||||
|     use std::task::{Context, Poll}; | ||||
|  | ||||
|     use super::{Callback, channel, Receiver}; | ||||
|     use super::{channel, Callback, Receiver}; | ||||
|  | ||||
|     #[derive(Debug)] | ||||
|     struct Custom(i32); | ||||
| @@ -271,14 +277,14 @@ mod tests { | ||||
|  | ||||
|     impl<F, T> Future for PollOnce<'_, F> | ||||
|     where | ||||
|         F: Future<Output = T> + Unpin | ||||
|         F: Future<Output = T> + Unpin, | ||||
|     { | ||||
|         type Output = Option<()>; | ||||
|  | ||||
|         fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||||
|             match Pin::new(&mut self.0).poll(cx) { | ||||
|                 Poll::Ready(_) => Poll::Ready(Some(())), | ||||
|                 Poll::Pending => Poll::Ready(None) | ||||
|                 Poll::Pending => Poll::Ready(None), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -357,7 +363,7 @@ mod tests { | ||||
|                     let poll_once = PollOnce(&mut rx); | ||||
|                     let opt = poll_once.await; | ||||
|                     if opt.is_none() { | ||||
|                         break | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|   | ||||
| @@ -64,17 +64,18 @@ use std::sync::Arc; | ||||
| use std::time::Duration; | ||||
|  | ||||
| use futures_channel::oneshot; | ||||
| use futures_util::future::{self, FutureExt as _, TryFutureExt as _, Either}; | ||||
| use http::{Method, Request, Response, Uri, Version}; | ||||
| use futures_util::future::{self, Either, FutureExt as _, TryFutureExt as _}; | ||||
| use http::header::{HeaderValue, HOST}; | ||||
| use http::uri::Scheme; | ||||
| use http::{Method, Request, Response, Uri, Version}; | ||||
|  | ||||
| use crate::body::{Body, Payload}; | ||||
| use crate::common::{lazy as hyper_lazy, BoxSendFuture, Executor, Lazy, Future, Pin, Poll, task}; | ||||
| use self::connect::{Alpn, sealed::Connect, Connected, Connection}; | ||||
| use self::connect::{sealed::Connect, Alpn, Connected, Connection}; | ||||
| use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation}; | ||||
| use crate::body::{Body, Payload}; | ||||
| use crate::common::{lazy as hyper_lazy, task, BoxSendFuture, Executor, Future, Lazy, Pin, Poll}; | ||||
|  | ||||
| #[cfg(feature = "tcp")] pub use self::connect::HttpConnector; | ||||
| #[cfg(feature = "tcp")] | ||||
| pub use self::connect::HttpConnector; | ||||
|  | ||||
| pub mod conn; | ||||
| pub mod connect; | ||||
| @@ -104,7 +105,7 @@ struct Config { | ||||
| /// This is returned by `Client::request` (and `Client::get`). | ||||
| #[must_use = "futures do nothing unless polled"] | ||||
| pub struct ResponseFuture { | ||||
|     inner: Pin<Box<dyn Future<Output=crate::Result<Response<Body>>> + Send>>, | ||||
|     inner: Pin<Box<dyn Future<Output = crate::Result<Response<Body>>> + Send>>, | ||||
| } | ||||
|  | ||||
| // ===== impl Client ===== | ||||
| @@ -157,11 +158,12 @@ impl Client<(), Body> { | ||||
| } | ||||
|  | ||||
| impl<C, B> Client<C, B> | ||||
| where C: Connect + Clone + Send + Sync + 'static, | ||||
|       C::Transport: Unpin + Send + 'static, | ||||
|       C::Future: Unpin + Send + 'static, | ||||
|       B: Payload + Unpin + Send + 'static, | ||||
|       B::Data: Send + Unpin, | ||||
| where | ||||
|     C: Connect + Clone + Send + Sync + 'static, | ||||
|     C::Transport: Unpin + Send + 'static, | ||||
|     C::Future: Unpin + Send + 'static, | ||||
|     B: Payload + Unpin + Send + 'static, | ||||
|     B::Data: Send + Unpin, | ||||
| { | ||||
|     /// Send a `GET` request to the supplied `Uri`. | ||||
|     /// | ||||
| @@ -223,13 +225,19 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|         let is_http_connect = req.method() == &Method::CONNECT; | ||||
|         match req.version() { | ||||
|             Version::HTTP_11 => (), | ||||
|             Version::HTTP_10 => if is_http_connect { | ||||
|                 warn!("CONNECT is not allowed for HTTP/1.0"); | ||||
|                 return ResponseFuture::new(Box::new(future::err(crate::Error::new_user_unsupported_request_method()))); | ||||
|             }, | ||||
|             other_h2 @ Version::HTTP_2 => if self.config.ver != Ver::Http2 { | ||||
|                 return ResponseFuture::error_version(other_h2); | ||||
|             }, | ||||
|             Version::HTTP_10 => { | ||||
|                 if is_http_connect { | ||||
|                     warn!("CONNECT is not allowed for HTTP/1.0"); | ||||
|                     return ResponseFuture::new(Box::new(future::err( | ||||
|                         crate::Error::new_user_unsupported_request_method(), | ||||
|                     ))); | ||||
|                 } | ||||
|             } | ||||
|             other_h2 @ Version::HTTP_2 => { | ||||
|                 if self.config.ver != Ver::Http2 { | ||||
|                     return ResponseFuture::error_version(other_h2); | ||||
|                 } | ||||
|             } | ||||
|             // completely unsupported HTTP version (like HTTP/0.9)! | ||||
|             other => return ResponseFuture::error_version(other), | ||||
|         }; | ||||
| @@ -245,7 +253,11 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|         ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key))) | ||||
|     } | ||||
|  | ||||
|     fn retryably_send_request(&self, req: Request<B>, pool_key: PoolKey) -> impl Future<Output=crate::Result<Response<Body>>> { | ||||
|     fn retryably_send_request( | ||||
|         &self, | ||||
|         req: Request<B>, | ||||
|         pool_key: PoolKey, | ||||
|     ) -> impl Future<Output = crate::Result<Response<Body>>> { | ||||
|         let client = self.clone(); | ||||
|         let uri = req.uri().clone(); | ||||
|  | ||||
| @@ -265,7 +277,10 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|                         return Poll::Ready(Err(reason)); | ||||
|                     } | ||||
|  | ||||
|                     trace!("unstarted request canceled, trying again (reason={:?})", reason); | ||||
|                     trace!( | ||||
|                         "unstarted request canceled, trying again (reason={:?})", | ||||
|                         reason | ||||
|                     ); | ||||
|                     *req.uri_mut() = uri.clone(); | ||||
|                     send_fut = client.send_request(req, pool_key.clone()); | ||||
|                 } | ||||
| @@ -273,7 +288,11 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn send_request(&self, mut req: Request<B>, pool_key: PoolKey) -> impl Future<Output=Result<Response<Body>, ClientError<B>>> + Unpin { | ||||
|     fn send_request( | ||||
|         &self, | ||||
|         mut req: Request<B>, | ||||
|         pool_key: PoolKey, | ||||
|     ) -> impl Future<Output = Result<Response<Body>, ClientError<B>>> + Unpin { | ||||
|         let conn = self.connection_for(req.uri().clone(), pool_key); | ||||
|  | ||||
|         let set_host = self.config.set_host; | ||||
| @@ -282,18 +301,16 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|             if pooled.is_http1() { | ||||
|                 if set_host { | ||||
|                     let uri = req.uri().clone(); | ||||
|                     req | ||||
|                         .headers_mut() | ||||
|                         .entry(HOST) | ||||
|                         .or_insert_with(|| { | ||||
|                             let hostname = uri.host().expect("authority implies host"); | ||||
|                             if let Some(port) = uri.port() { | ||||
|                                 let s = format!("{}:{}", hostname, port); | ||||
|                                 HeaderValue::from_str(&s) | ||||
|                             } else { | ||||
|                                 HeaderValue::from_str(hostname) | ||||
|                             }.expect("uri host is valid header value") | ||||
|                         }); | ||||
|                     req.headers_mut().entry(HOST).or_insert_with(|| { | ||||
|                         let hostname = uri.host().expect("authority implies host"); | ||||
|                         if let Some(port) = uri.port() { | ||||
|                             let s = format!("{}:{}", hostname, port); | ||||
|                             HeaderValue::from_str(&s) | ||||
|                         } else { | ||||
|                             HeaderValue::from_str(hostname) | ||||
|                         } | ||||
|                         .expect("uri host is valid header value") | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 // CONNECT always sends authority-form, so check it first... | ||||
| @@ -306,10 +323,13 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|                 }; | ||||
|             } else if req.method() == &Method::CONNECT { | ||||
|                 debug!("client does not support CONNECT requests over HTTP2"); | ||||
|                 return Either::Left(future::err(ClientError::Normal(crate::Error::new_user_unsupported_request_method()))); | ||||
|                 return Either::Left(future::err(ClientError::Normal( | ||||
|                     crate::Error::new_user_unsupported_request_method(), | ||||
|                 ))); | ||||
|             } | ||||
|  | ||||
|             let fut = pooled.send_request_retryable(req) | ||||
|             let fut = pooled | ||||
|                 .send_request_retryable(req) | ||||
|                 .map_err(ClientError::map_with_reused(pooled.is_reused())); | ||||
|  | ||||
|             // If the Connector included 'extra' info, add to Response... | ||||
| @@ -332,51 +352,46 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|                 return Either::Right(Either::Left(fut)); | ||||
|             } | ||||
|  | ||||
|             Either::Right(Either::Right(fut | ||||
|                 .map_ok(move |mut res| { | ||||
|                     // If pooled is HTTP/2, we can toss this reference immediately. | ||||
|                     // | ||||
|                     // when pooled is dropped, it will try to insert back into the | ||||
|                     // pool. To delay that, spawn a future that completes once the | ||||
|                     // sender is ready again. | ||||
|                     // | ||||
|                     // This *should* only be once the related `Connection` has polled | ||||
|                     // for a new request to start. | ||||
|                     // | ||||
|                     // It won't be ready if there is a body to stream. | ||||
|                     if pooled.is_http2() || !pooled.is_pool_enabled() || pooled.is_ready() { | ||||
|                         drop(pooled); | ||||
|                     } else if !res.body().is_end_stream() { | ||||
|                         let (delayed_tx, delayed_rx) = oneshot::channel(); | ||||
|                         res.body_mut().delayed_eof(delayed_rx); | ||||
|                         let on_idle = future::poll_fn(move |cx| { | ||||
|                             pooled.poll_ready(cx) | ||||
|                         }) | ||||
|                             .map(move |_| { | ||||
|                                 // At this point, `pooled` is dropped, and had a chance | ||||
|                                 // to insert into the pool (if conn was idle) | ||||
|                                 drop(delayed_tx); | ||||
|                             }); | ||||
|             Either::Right(Either::Right(fut.map_ok(move |mut res| { | ||||
|                 // If pooled is HTTP/2, we can toss this reference immediately. | ||||
|                 // | ||||
|                 // when pooled is dropped, it will try to insert back into the | ||||
|                 // pool. To delay that, spawn a future that completes once the | ||||
|                 // sender is ready again. | ||||
|                 // | ||||
|                 // This *should* only be once the related `Connection` has polled | ||||
|                 // for a new request to start. | ||||
|                 // | ||||
|                 // It won't be ready if there is a body to stream. | ||||
|                 if pooled.is_http2() || !pooled.is_pool_enabled() || pooled.is_ready() { | ||||
|                     drop(pooled); | ||||
|                 } else if !res.body().is_end_stream() { | ||||
|                     let (delayed_tx, delayed_rx) = oneshot::channel(); | ||||
|                     res.body_mut().delayed_eof(delayed_rx); | ||||
|                     let on_idle = future::poll_fn(move |cx| pooled.poll_ready(cx)).map(move |_| { | ||||
|                         // At this point, `pooled` is dropped, and had a chance | ||||
|                         // to insert into the pool (if conn was idle) | ||||
|                         drop(delayed_tx); | ||||
|                     }); | ||||
|  | ||||
|                         executor.execute(on_idle); | ||||
|                     } else { | ||||
|                         // There's no body to delay, but the connection isn't | ||||
|                         // ready yet. Only re-insert when it's ready | ||||
|                         let on_idle = future::poll_fn(move |cx| { | ||||
|                             pooled.poll_ready(cx) | ||||
|                         }) | ||||
|                             .map(|_| ()); | ||||
|                     executor.execute(on_idle); | ||||
|                 } else { | ||||
|                     // There's no body to delay, but the connection isn't | ||||
|                     // ready yet. Only re-insert when it's ready | ||||
|                     let on_idle = future::poll_fn(move |cx| pooled.poll_ready(cx)).map(|_| ()); | ||||
|  | ||||
|                         executor.execute(on_idle); | ||||
|                     } | ||||
|                     res | ||||
|                 }))) | ||||
|                     executor.execute(on_idle); | ||||
|                 } | ||||
|                 res | ||||
|             }))) | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn connection_for(&self, uri: Uri, pool_key: PoolKey) | ||||
|         -> impl Future<Output=Result<Pooled<PoolClient<B>>, ClientError<B>>> | ||||
|     { | ||||
|     fn connection_for( | ||||
|         &self, | ||||
|         uri: Uri, | ||||
|         pool_key: PoolKey, | ||||
|     ) -> impl Future<Output = Result<Pooled<PoolClient<B>>, ClientError<B>>> { | ||||
|         // This actually races 2 different futures to try to get a ready | ||||
|         // connection the fastest, and to reduce connection churn. | ||||
|         // | ||||
| @@ -395,67 +410,66 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|  | ||||
|         let executor = self.conn_builder.exec.clone(); | ||||
|         // The order of the `select` is depended on below... | ||||
|         future::select(checkout, connect) | ||||
|             .then(move |either| match either { | ||||
|                 // Checkout won, connect future may have been started or not. | ||||
|         future::select(checkout, connect).then(move |either| match either { | ||||
|             // Checkout won, connect future may have been started or not. | ||||
|             // | ||||
|             // If it has, let it finish and insert back into the pool, | ||||
|             // so as to not waste the socket... | ||||
|             Either::Left((Ok(checked_out), connecting)) => { | ||||
|                 // This depends on the `select` above having the correct | ||||
|                 // order, such that if the checkout future were ready | ||||
|                 // immediately, the connect future will never have been | ||||
|                 // started. | ||||
|                 // | ||||
|                 // If it has, let it finish and insert back into the pool, | ||||
|                 // so as to not waste the socket... | ||||
|                 Either::Left((Ok(checked_out), connecting)) => { | ||||
|                     // This depends on the `select` above having the correct | ||||
|                     // order, such that if the checkout future were ready | ||||
|                     // immediately, the connect future will never have been | ||||
|                     // started. | ||||
|                     // | ||||
|                     // If it *wasn't* ready yet, then the connect future will | ||||
|                     // have been started... | ||||
|                     if connecting.started() { | ||||
|                         let bg = connecting | ||||
|                             .map_err(|err| { | ||||
|                                 trace!("background connect error: {}", err); | ||||
|                             }) | ||||
|                             .map(|_pooled| { | ||||
|                                 // dropping here should just place it in | ||||
|                                 // the Pool for us... | ||||
|                             }); | ||||
|                         // An execute error here isn't important, we're just trying | ||||
|                         // to prevent a waste of a socket... | ||||
|                         let _ = executor.execute(bg); | ||||
|                     } | ||||
|                     Either::Left(future::ok(checked_out)) | ||||
|                 }, | ||||
|                 // Connect won, checkout can just be dropped. | ||||
|                 Either::Right((Ok(connected), _checkout)) => { | ||||
|                     Either::Left(future::ok(connected)) | ||||
|                 }, | ||||
|                 // Either checkout or connect could get canceled: | ||||
|                 // | ||||
|                 // 1. Connect is canceled if this is HTTP/2 and there is | ||||
|                 //    an outstanding HTTP/2 connecting task. | ||||
|                 // 2. Checkout is canceled if the pool cannot deliver an | ||||
|                 //    idle connection reliably. | ||||
|                 // | ||||
|                 // In both cases, we should just wait for the other future. | ||||
|                 Either::Left((Err(err), connecting)) => Either::Right(Either::Left({ | ||||
|                     if err.is_canceled() { | ||||
|                         Either::Left(connecting.map_err(ClientError::Normal)) | ||||
|                     } else { | ||||
|                         Either::Right(future::err(ClientError::Normal(err))) | ||||
|                     } | ||||
|                 })), | ||||
|                 Either::Right((Err(err), checkout)) => Either::Right(Either::Right({ | ||||
|                     if err.is_canceled() { | ||||
|                         Either::Left(checkout.map_err(ClientError::Normal)) | ||||
|                     } else { | ||||
|                         Either::Right(future::err(ClientError::Normal(err))) | ||||
|                     } | ||||
|                 })), | ||||
|             }) | ||||
|                 // If it *wasn't* ready yet, then the connect future will | ||||
|                 // have been started... | ||||
|                 if connecting.started() { | ||||
|                     let bg = connecting | ||||
|                         .map_err(|err| { | ||||
|                             trace!("background connect error: {}", err); | ||||
|                         }) | ||||
|                         .map(|_pooled| { | ||||
|                             // dropping here should just place it in | ||||
|                             // the Pool for us... | ||||
|                         }); | ||||
|                     // An execute error here isn't important, we're just trying | ||||
|                     // to prevent a waste of a socket... | ||||
|                     let _ = executor.execute(bg); | ||||
|                 } | ||||
|                 Either::Left(future::ok(checked_out)) | ||||
|             } | ||||
|             // Connect won, checkout can just be dropped. | ||||
|             Either::Right((Ok(connected), _checkout)) => Either::Left(future::ok(connected)), | ||||
|             // Either checkout or connect could get canceled: | ||||
|             // | ||||
|             // 1. Connect is canceled if this is HTTP/2 and there is | ||||
|             //    an outstanding HTTP/2 connecting task. | ||||
|             // 2. Checkout is canceled if the pool cannot deliver an | ||||
|             //    idle connection reliably. | ||||
|             // | ||||
|             // In both cases, we should just wait for the other future. | ||||
|             Either::Left((Err(err), connecting)) => Either::Right(Either::Left({ | ||||
|                 if err.is_canceled() { | ||||
|                     Either::Left(connecting.map_err(ClientError::Normal)) | ||||
|                 } else { | ||||
|                     Either::Right(future::err(ClientError::Normal(err))) | ||||
|                 } | ||||
|             })), | ||||
|             Either::Right((Err(err), checkout)) => Either::Right(Either::Right({ | ||||
|                 if err.is_canceled() { | ||||
|                     Either::Left(checkout.map_err(ClientError::Normal)) | ||||
|                 } else { | ||||
|                     Either::Right(future::err(ClientError::Normal(err))) | ||||
|                 } | ||||
|             })), | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn connect_to(&self, uri: Uri, pool_key: PoolKey) | ||||
|         -> impl Lazy<Output=crate::Result<Pooled<PoolClient<B>>>> + Unpin | ||||
|     { | ||||
|     fn connect_to( | ||||
|         &self, | ||||
|         uri: Uri, | ||||
|         pool_key: PoolKey, | ||||
|     ) -> impl Lazy<Output = crate::Result<Pooled<PoolClient<B>>>> + Unpin { | ||||
|         let executor = self.conn_builder.exec.clone(); | ||||
|         let pool = self.pool.clone(); | ||||
|         let mut conn_builder = self.conn_builder.clone(); | ||||
| @@ -472,68 +486,82 @@ where C: Connect + Clone + Send + Sync + 'static, | ||||
|             let connecting = match pool.connecting(&pool_key, ver) { | ||||
|                 Some(lock) => lock, | ||||
|                 None => { | ||||
|                     let canceled = crate::Error::new_canceled().with("HTTP/2 connection in progress"); | ||||
|                     let canceled = | ||||
|                         crate::Error::new_canceled().with("HTTP/2 connection in progress"); | ||||
|                     return Either::Right(future::err(canceled)); | ||||
|                 } | ||||
|             }; | ||||
|             Either::Left(connector.connect(connect::sealed::Internal, dst) | ||||
|                 .map_err(crate::Error::new_connect) | ||||
|                 .and_then(move |io| { | ||||
|                     let connected = io.connected(); | ||||
|                     // If ALPN is h2 and we aren't http2_only already, | ||||
|                     // then we need to convert our pool checkout into | ||||
|                     // a single HTTP2 one. | ||||
|                     let connecting = if connected.alpn == Alpn::H2 && !is_ver_h2 { | ||||
|                         match connecting.alpn_h2(&pool) { | ||||
|                             Some(lock) => { | ||||
|                                 trace!("ALPN negotiated h2, updating pool"); | ||||
|                                 lock | ||||
|                             }, | ||||
|                             None => { | ||||
|                                 // Another connection has already upgraded, | ||||
|                                 // the pool checkout should finish up for us. | ||||
|                                 let canceled = crate::Error::new_canceled().with("ALPN upgraded to HTTP/2"); | ||||
|                                 return Either::Right(future::err(canceled)); | ||||
|             Either::Left( | ||||
|                 connector | ||||
|                     .connect(connect::sealed::Internal, dst) | ||||
|                     .map_err(crate::Error::new_connect) | ||||
|                     .and_then(move |io| { | ||||
|                         let connected = io.connected(); | ||||
|                         // If ALPN is h2 and we aren't http2_only already, | ||||
|                         // then we need to convert our pool checkout into | ||||
|                         // a single HTTP2 one. | ||||
|                         let connecting = if connected.alpn == Alpn::H2 && !is_ver_h2 { | ||||
|                             match connecting.alpn_h2(&pool) { | ||||
|                                 Some(lock) => { | ||||
|                                     trace!("ALPN negotiated h2, updating pool"); | ||||
|                                     lock | ||||
|                                 } | ||||
|                                 None => { | ||||
|                                     // Another connection has already upgraded, | ||||
|                                     // the pool checkout should finish up for us. | ||||
|                                     let canceled = crate::Error::new_canceled() | ||||
|                                         .with("ALPN upgraded to HTTP/2"); | ||||
|                                     return Either::Right(future::err(canceled)); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } else { | ||||
|                         connecting | ||||
|                     }; | ||||
|                     let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2; | ||||
|                     Either::Left(Box::pin(conn_builder | ||||
|                         .http2_only(is_h2) | ||||
|                         .handshake(io) | ||||
|                         .and_then(move |(tx, conn)| { | ||||
|                             trace!("handshake complete, spawning background dispatcher task"); | ||||
|                             executor.execute(conn.map_err(|e| { | ||||
|                                 debug!("client connection error: {}", e) | ||||
|                             }).map(|_| ())); | ||||
|                         } else { | ||||
|                             connecting | ||||
|                         }; | ||||
|                         let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2; | ||||
|                         Either::Left(Box::pin( | ||||
|                             conn_builder | ||||
|                                 .http2_only(is_h2) | ||||
|                                 .handshake(io) | ||||
|                                 .and_then(move |(tx, conn)| { | ||||
|                                     trace!( | ||||
|                                         "handshake complete, spawning background dispatcher task" | ||||
|                                     ); | ||||
|                                     executor.execute( | ||||
|                                         conn.map_err(|e| debug!("client connection error: {}", e)) | ||||
|                                             .map(|_| ()), | ||||
|                                     ); | ||||
|  | ||||
|                             // Wait for 'conn' to ready up before we | ||||
|                             // declare this tx as usable | ||||
|                             tx.when_ready() | ||||
|                         }) | ||||
|                         .map_ok(move |tx| { | ||||
|                             pool.pooled(connecting, PoolClient { | ||||
|                                 conn_info: connected, | ||||
|                                 tx: if is_h2 { | ||||
|                                     PoolTx::Http2(tx.into_http2()) | ||||
|                                 } else { | ||||
|                                     PoolTx::Http1(tx) | ||||
|                                 }, | ||||
|                             }) | ||||
|                         }))) | ||||
|                 })) | ||||
|                                     // Wait for 'conn' to ready up before we | ||||
|                                     // declare this tx as usable | ||||
|                                     tx.when_ready() | ||||
|                                 }) | ||||
|                                 .map_ok(move |tx| { | ||||
|                                     pool.pooled( | ||||
|                                         connecting, | ||||
|                                         PoolClient { | ||||
|                                             conn_info: connected, | ||||
|                                             tx: if is_h2 { | ||||
|                                                 PoolTx::Http2(tx.into_http2()) | ||||
|                                             } else { | ||||
|                                                 PoolTx::Http1(tx) | ||||
|                                             }, | ||||
|                                         }, | ||||
|                                     ) | ||||
|                                 }), | ||||
|                         )) | ||||
|                     }), | ||||
|             ) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<C, B> tower_service::Service<Request<B>> for Client<C, B> | ||||
| where C: Connect + Clone + Send + Sync + 'static, | ||||
|       C::Transport: Unpin + Send + 'static, | ||||
|       C::Future: Unpin + Send + 'static, | ||||
|       B: Payload + Unpin + Send + 'static, | ||||
|       B::Data: Send + Unpin, | ||||
| where | ||||
|     C: Connect + Clone + Send + Sync + 'static, | ||||
|     C::Transport: Unpin + Send + 'static, | ||||
|     C::Future: Unpin + Send + 'static, | ||||
|     B: Payload + Unpin + Send + 'static, | ||||
|     B::Data: Send + Unpin, | ||||
| { | ||||
|     type Response = Response<Body>; | ||||
|     type Error = crate::Error; | ||||
| @@ -561,23 +589,22 @@ impl<C: Clone, B> Clone for Client<C, B> { | ||||
|  | ||||
| impl<C, B> fmt::Debug for Client<C, B> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Client") | ||||
|             .finish() | ||||
|         f.debug_struct("Client").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl ResponseFuture ===== | ||||
|  | ||||
| impl ResponseFuture { | ||||
|     fn new(fut: Box<dyn Future<Output=crate::Result<Response<Body>>> + Send>) -> Self { | ||||
|         Self { | ||||
|             inner: fut.into(), | ||||
|         } | ||||
|     fn new(fut: Box<dyn Future<Output = crate::Result<Response<Body>>> + Send>) -> Self { | ||||
|         Self { inner: fut.into() } | ||||
|     } | ||||
|  | ||||
|     fn error_version(ver: Version) -> Self { | ||||
|         warn!("Request has unsupported version \"{:?}\"", ver); | ||||
|         ResponseFuture::new(Box::new(future::err(crate::Error::new_user_unsupported_version()))) | ||||
|         ResponseFuture::new(Box::new(future::err( | ||||
|             crate::Error::new_user_unsupported_version(), | ||||
|         ))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -644,7 +671,10 @@ impl<B> PoolClient<B> { | ||||
| } | ||||
|  | ||||
| impl<B: Payload + 'static> PoolClient<B> { | ||||
|     fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> | ||||
|     fn send_request_retryable( | ||||
|         &mut self, | ||||
|         req: Request<B>, | ||||
|     ) -> impl Future<Output = Result<Response<Body>, (crate::Error, Option<Request<B>>)>> | ||||
|     where | ||||
|         B: Send, | ||||
|     { | ||||
| @@ -668,12 +698,10 @@ where | ||||
|  | ||||
|     fn reserve(self) -> Reservation<Self> { | ||||
|         match self.tx { | ||||
|             PoolTx::Http1(tx) => { | ||||
|                 Reservation::Unique(PoolClient { | ||||
|                     conn_info: self.conn_info, | ||||
|                     tx: PoolTx::Http1(tx), | ||||
|                 }) | ||||
|             }, | ||||
|             PoolTx::Http1(tx) => Reservation::Unique(PoolClient { | ||||
|                 conn_info: self.conn_info, | ||||
|                 tx: PoolTx::Http1(tx), | ||||
|             }), | ||||
|             PoolTx::Http2(tx) => { | ||||
|                 let b = PoolClient { | ||||
|                     conn_info: self.conn_info.clone(), | ||||
| @@ -703,13 +731,11 @@ enum ClientError<B> { | ||||
|         connection_reused: bool, | ||||
|         req: Request<B>, | ||||
|         reason: crate::Error, | ||||
|     } | ||||
|     }, | ||||
| } | ||||
|  | ||||
| impl<B> ClientError<B> { | ||||
|     fn map_with_reused(conn_reused: bool) | ||||
|         -> impl Fn((crate::Error, Option<Request<B>>)) -> Self | ||||
|     { | ||||
|     fn map_with_reused(conn_reused: bool) -> impl Fn((crate::Error, Option<Request<B>>)) -> Self { | ||||
|         move |(err, orig_req)| { | ||||
|             if let Some(req) = orig_req { | ||||
|                 ClientError::Canceled { | ||||
| @@ -737,7 +763,7 @@ fn origin_form(uri: &mut Uri) { | ||||
|             let mut parts = ::http::uri::Parts::default(); | ||||
|             parts.path_and_query = Some(path.clone()); | ||||
|             Uri::from_parts(parts).expect("path is valid uri") | ||||
|         }, | ||||
|         } | ||||
|         _none_or_just_slash => { | ||||
|             debug_assert!(Uri::default() == "/"); | ||||
|             Uri::default() | ||||
| @@ -748,7 +774,10 @@ fn origin_form(uri: &mut Uri) { | ||||
|  | ||||
| fn absolute_form(uri: &mut Uri) { | ||||
|     debug_assert!(uri.scheme().is_some(), "absolute_form needs a scheme"); | ||||
|     debug_assert!(uri.authority().is_some(), "absolute_form needs an authority"); | ||||
|     debug_assert!( | ||||
|         uri.authority().is_some(), | ||||
|         "absolute_form needs an authority" | ||||
|     ); | ||||
|     // If the URI is to HTTPS, and the connector claimed to be a proxy, | ||||
|     // then it *should* have tunneled, and so we don't want to send | ||||
|     // absolute-form in that case. | ||||
| @@ -763,10 +792,7 @@ fn authority_form(uri: &mut Uri) { | ||||
|             // `https://hyper.rs` would parse with `/` path, don't | ||||
|             // annoy people about that... | ||||
|             if path != "/" { | ||||
|                 warn!( | ||||
|                     "HTTP/1.1 CONNECT request stripping path: {:?}", | ||||
|                     path | ||||
|                 ); | ||||
|                 warn!("HTTP/1.1 CONNECT request stripping path: {:?}", path); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -775,7 +801,7 @@ fn authority_form(uri: &mut Uri) { | ||||
|             let mut parts = ::http::uri::Parts::default(); | ||||
|             parts.authority = Some(auth.clone()); | ||||
|             Uri::from_parts(parts).expect("authority is valid") | ||||
|         }, | ||||
|         } | ||||
|         None => { | ||||
|             unreachable!("authority_form with relative uri"); | ||||
|         } | ||||
| @@ -785,9 +811,7 @@ fn authority_form(uri: &mut Uri) { | ||||
| fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String> { | ||||
|     let uri_clone = uri.clone(); | ||||
|     match (uri_clone.scheme(), uri_clone.authority()) { | ||||
|         (Some(scheme), Some(auth)) => { | ||||
|             Ok(format!("{}://{}", scheme, auth)) | ||||
|         } | ||||
|         (Some(scheme), Some(auth)) => Ok(format!("{}://{}", scheme, auth)), | ||||
|         (None, Some(auth)) if is_http_connect => { | ||||
|             let scheme = match auth.port_u16() { | ||||
|                 Some(443) => { | ||||
| @@ -797,10 +821,10 @@ fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String> | ||||
|                 _ => { | ||||
|                     set_scheme(uri, Scheme::HTTP); | ||||
|                     "http" | ||||
|                 }, | ||||
|                 } | ||||
|             }; | ||||
|             Ok(format!("{}://{}", scheme, auth)) | ||||
|         }, | ||||
|         } | ||||
|         _ => { | ||||
|             debug!("Client requires absolute-form URIs, received: {:?}", uri); | ||||
|             Err(crate::Error::new_user_absolute_uri_required()) | ||||
| @@ -809,7 +833,10 @@ fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> crate::Result<String> | ||||
| } | ||||
|  | ||||
| fn set_scheme(uri: &mut Uri, scheme: Scheme) { | ||||
|     debug_assert!(uri.scheme().is_none(), "set_scheme expects no existing scheme"); | ||||
|     debug_assert!( | ||||
|         uri.scheme().is_none(), | ||||
|         "set_scheme expects no existing scheme" | ||||
|     ); | ||||
|     let old = mem::replace(uri, Uri::default()); | ||||
|     let mut parts: ::http::uri::Parts = old.into(); | ||||
|     parts.scheme = Some(scheme); | ||||
| @@ -946,11 +973,7 @@ impl Builder { | ||||
|     /// | ||||
|     /// Default is false. | ||||
|     pub fn http2_only(&mut self, val: bool) -> &mut Self { | ||||
|         self.client_config.ver = if val { | ||||
|             Ver::Http2 | ||||
|         } else { | ||||
|             Ver::Auto | ||||
|         }; | ||||
|         self.client_config.ver = if val { Ver::Http2 } else { Ver::Auto }; | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -963,7 +986,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE | ||||
|     pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|         self.conn_builder.http2_initial_stream_window_size(sz.into()); | ||||
|         self.conn_builder | ||||
|             .http2_initial_stream_window_size(sz.into()); | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -972,8 +996,12 @@ impl Builder { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|         self.conn_builder.http2_initial_connection_window_size(sz.into()); | ||||
|     pub fn http2_initial_connection_window_size( | ||||
|         &mut self, | ||||
|         sz: impl Into<Option<u32>>, | ||||
|     ) -> &mut Self { | ||||
|         self.conn_builder | ||||
|             .http2_initial_connection_window_size(sz.into()); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,8 @@ use futures_channel::oneshot; | ||||
| #[cfg(feature = "runtime")] | ||||
| use tokio::time::{Duration, Instant, Interval}; | ||||
|  | ||||
| use crate::common::{Exec, Future, Pin, Poll, Unpin, task}; | ||||
| use super::Ver; | ||||
| use crate::common::{task, Exec, Future, Pin, Poll, Unpin}; | ||||
|  | ||||
| // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||
| #[allow(missing_debug_implementations)] | ||||
| @@ -96,7 +96,7 @@ pub(super) struct Config { | ||||
| impl<T> Pool<T> { | ||||
|     pub fn new(config: Config, __exec: &Exec) -> Pool<T> { | ||||
|         let inner = if config.enabled { | ||||
|              Some(Arc::new(Mutex::new(PoolInner { | ||||
|             Some(Arc::new(Mutex::new(PoolInner { | ||||
|                 connecting: HashSet::new(), | ||||
|                 idle: HashMap::new(), | ||||
|                 #[cfg(feature = "runtime")] | ||||
| @@ -106,14 +106,12 @@ impl<T> Pool<T> { | ||||
|                 #[cfg(feature = "runtime")] | ||||
|                 exec: __exec.clone(), | ||||
|                 timeout: config.keep_alive_timeout, | ||||
|              }))) | ||||
|             }))) | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
|  | ||||
|         Pool { | ||||
|             inner, | ||||
|         } | ||||
|         Pool { inner } | ||||
|     } | ||||
|  | ||||
|     fn is_enabled(&self) -> bool { | ||||
| @@ -174,12 +172,7 @@ impl<T: Poolable> Pool<T> { | ||||
|  | ||||
|     #[cfg(test)] | ||||
|     fn locked(&self) -> ::std::sync::MutexGuard<'_, PoolInner<T>> { | ||||
|         self | ||||
|             .inner | ||||
|             .as_ref() | ||||
|             .expect("enabled") | ||||
|             .lock() | ||||
|             .expect("lock") | ||||
|         self.inner.as_ref().expect("enabled").lock().expect("lock") | ||||
|     } | ||||
|  | ||||
|     /* Used in client/tests.rs... | ||||
| @@ -216,13 +209,13 @@ impl<T: Poolable> Pool<T> { | ||||
|                     // Shared reservations don't need a reference to the pool, | ||||
|                     // since the pool always keeps a copy. | ||||
|                     (to_return, WeakOpt::none()) | ||||
|                 }, | ||||
|                 } | ||||
|                 Reservation::Unique(value) => { | ||||
|                     // Unique reservations must take a reference to the pool | ||||
|                     // since they hope to reinsert once the reservation is | ||||
|                     // completed | ||||
|                     (value, WeakOpt::downgrade(enabled)) | ||||
|                 }, | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             // If pool is not enabled, skip all the things... | ||||
| @@ -236,7 +229,7 @@ impl<T: Poolable> Pool<T> { | ||||
|             key: connecting.key.clone(), | ||||
|             is_reused: false, | ||||
|             pool: pool_ref, | ||||
|             value: Some(value) | ||||
|             value: Some(value), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -299,10 +292,8 @@ impl<'a, T: Poolable + 'a> IdlePopper<'a, T> { | ||||
|                         value: to_reinsert, | ||||
|                     }); | ||||
|                     to_checkout | ||||
|                 }, | ||||
|                 Reservation::Unique(unique) => { | ||||
|                     unique | ||||
|                 } | ||||
|                 Reservation::Unique(unique) => unique, | ||||
|             }; | ||||
|  | ||||
|             return Some(Idle { | ||||
| @@ -332,7 +323,7 @@ impl<T: Poolable> PoolInner<T> { | ||||
|                         Reservation::Shared(to_keep, to_send) => { | ||||
|                             value = Some(to_keep); | ||||
|                             to_send | ||||
|                         }, | ||||
|                         } | ||||
|                         Reservation::Unique(uniq) => uniq, | ||||
|                     }; | ||||
|                     match tx.send(reserved) { | ||||
| @@ -342,7 +333,7 @@ impl<T: Poolable> PoolInner<T> { | ||||
|                             } else { | ||||
|                                 continue; | ||||
|                             } | ||||
|                         }, | ||||
|                         } | ||||
|                         Err(e) => { | ||||
|                             value = Some(e); | ||||
|                         } | ||||
| @@ -361,10 +352,7 @@ impl<T: Poolable> PoolInner<T> { | ||||
|             Some(value) => { | ||||
|                 // borrow-check scope... | ||||
|                 { | ||||
|                     let idle_list = self | ||||
|                         .idle | ||||
|                         .entry(key.clone()) | ||||
|                         .or_insert(Vec::new()); | ||||
|                     let idle_list = self.idle.entry(key.clone()).or_insert(Vec::new()); | ||||
|                     if self.max_idle_per_host <= idle_list.len() { | ||||
|                         trace!("max idle per host for {:?}, dropping connection", key); | ||||
|                         return; | ||||
| @@ -390,10 +378,7 @@ impl<T: Poolable> PoolInner<T> { | ||||
|     /// but the lock is going away, so clean up. | ||||
|     fn connected(&mut self, key: &Key) { | ||||
|         let existed = self.connecting.remove(key); | ||||
|         debug_assert!( | ||||
|             existed, | ||||
|             "Connecting dropped, key not in pool.connecting" | ||||
|         ); | ||||
|         debug_assert!(existed, "Connecting dropped, key not in pool.connecting"); | ||||
|         // cancel any waiters. if there are any, it's because | ||||
|         // this Connecting task didn't complete successfully. | ||||
|         // those waiters would never receive a connection. | ||||
| @@ -412,7 +397,7 @@ impl<T: Poolable> PoolInner<T> { | ||||
|                 self.idle_interval_ref = Some(tx); | ||||
|                 (dur, rx) | ||||
|             } else { | ||||
|                 return | ||||
|                 return; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
| @@ -434,9 +419,7 @@ impl<T> PoolInner<T> { | ||||
|     fn clean_waiters(&mut self, key: &Key) { | ||||
|         let mut remove_waiters = false; | ||||
|         if let Some(waiters) = self.waiters.get_mut(key) { | ||||
|             waiters.retain(|tx| { | ||||
|                 !tx.is_canceled() | ||||
|             }); | ||||
|             waiters.retain(|tx| !tx.is_canceled()); | ||||
|             remove_waiters = waiters.is_empty(); | ||||
|         } | ||||
|         if remove_waiters { | ||||
| @@ -547,9 +530,7 @@ impl<T: Poolable> Drop for Pooled<T> { | ||||
|  | ||||
| impl<T: Poolable> fmt::Debug for Pooled<T> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Pooled") | ||||
|             .field("key", &self.key) | ||||
|             .finish() | ||||
|         f.debug_struct("Pooled").field("key", &self.key).finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -567,7 +548,10 @@ pub(super) struct Checkout<T> { | ||||
| } | ||||
|  | ||||
| impl<T: Poolable> Checkout<T> { | ||||
|     fn poll_waiter(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Pooled<T>>>> { | ||||
|     fn poll_waiter( | ||||
|         &mut self, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<crate::Result<Pooled<T>>>> { | ||||
|         static CANCELED: &str = "pool checkout failed"; | ||||
|         if let Some(mut rx) = self.waiter.take() { | ||||
|             match Pin::new(&mut rx).poll(cx) { | ||||
| @@ -577,12 +561,14 @@ impl<T: Poolable> Checkout<T> { | ||||
|                     } else { | ||||
|                         Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED)))) | ||||
|                     } | ||||
|                 }, | ||||
|                 } | ||||
|                 Poll::Pending => { | ||||
|                     self.waiter = Some(rx); | ||||
|                     Poll::Pending | ||||
|                 }, | ||||
|                 Poll::Ready(Err(_canceled)) => Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED)))), | ||||
|                 } | ||||
|                 Poll::Ready(Err(_canceled)) => { | ||||
|                     Poll::Ready(Some(Err(crate::Error::new_canceled().with(CANCELED)))) | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             Poll::Ready(None) | ||||
| @@ -593,20 +579,19 @@ impl<T: Poolable> Checkout<T> { | ||||
|         let entry = { | ||||
|             let mut inner = self.pool.inner.as_ref()?.lock().unwrap(); | ||||
|             let expiration = Expiration::new(inner.timeout); | ||||
|             let maybe_entry = inner.idle.get_mut(&self.key) | ||||
|                 .and_then(|list| { | ||||
|                     trace!("take? {:?}: expiration = {:?}", self.key, expiration.0); | ||||
|                     // A block to end the mutable borrow on list, | ||||
|                     // so the map below can check is_empty() | ||||
|                     { | ||||
|                         let popper = IdlePopper { | ||||
|                             key: &self.key, | ||||
|                             list, | ||||
|                         }; | ||||
|                         popper.pop(&expiration) | ||||
|                     } | ||||
|                         .map(|e| (e, list.is_empty())) | ||||
|                 }); | ||||
|             let maybe_entry = inner.idle.get_mut(&self.key).and_then(|list| { | ||||
|                 trace!("take? {:?}: expiration = {:?}", self.key, expiration.0); | ||||
|                 // A block to end the mutable borrow on list, | ||||
|                 // so the map below can check is_empty() | ||||
|                 { | ||||
|                     let popper = IdlePopper { | ||||
|                         key: &self.key, | ||||
|                         list, | ||||
|                     }; | ||||
|                     popper.pop(&expiration) | ||||
|                 } | ||||
|                 .map(|e| (e, list.is_empty())) | ||||
|             }); | ||||
|  | ||||
|             let (entry, empty) = if let Some((e, empty)) = maybe_entry { | ||||
|                 (Some(e), empty) | ||||
| @@ -764,9 +749,7 @@ impl<T> WeakOpt<T> { | ||||
|     } | ||||
|  | ||||
|     fn upgrade(&self) -> Option<Arc<T>> { | ||||
|         self.0 | ||||
|             .as_ref() | ||||
|             .and_then(Weak::upgrade) | ||||
|         self.0.as_ref().and_then(Weak::upgrade) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -776,8 +759,8 @@ mod tests { | ||||
|     use std::task::Poll; | ||||
|     use std::time::Duration; | ||||
|  | ||||
|     use crate::common::{Exec, Future, Pin, task}; | ||||
|     use super::{Connecting, Key, Poolable, Pool, Reservation, WeakOpt}; | ||||
|     use super::{Connecting, Key, Pool, Poolable, Reservation, WeakOpt}; | ||||
|     use crate::common::{task, Exec, Future, Pin}; | ||||
|  | ||||
|     /// Test unique reservations. | ||||
|     #[derive(Debug, PartialEq, Eq)] | ||||
| @@ -809,7 +792,8 @@ mod tests { | ||||
|     } | ||||
|  | ||||
|     fn pool_max_idle_no_timer<T>(max_idle: usize) -> Pool<T> { | ||||
|         let pool = Pool::new(super::Config { | ||||
|         let pool = Pool::new( | ||||
|             super::Config { | ||||
|                 enabled: true, | ||||
|                 keep_alive_timeout: Some(Duration::from_millis(100)), | ||||
|                 max_idle_per_host: max_idle, | ||||
| @@ -838,7 +822,8 @@ mod tests { | ||||
|     struct PollOnce<'a, F>(&'a mut F); | ||||
|  | ||||
|     impl<F, T, U> Future for PollOnce<'_, F> | ||||
|         where F: Future<Output = Result<T, U>> + Unpin | ||||
|     where | ||||
|         F: Future<Output = Result<T, U>> + Unpin, | ||||
|     { | ||||
|         type Output = Option<()>; | ||||
|  | ||||
| @@ -846,7 +831,7 @@ mod tests { | ||||
|             match Pin::new(&mut self.0).poll(cx) { | ||||
|                 Poll::Ready(Ok(_)) => Poll::Ready(Some(())), | ||||
|                 Poll::Ready(Err(_)) => Poll::Ready(Some(())), | ||||
|                 Poll::Pending => Poll::Ready(None) | ||||
|                 Poll::Pending => Poll::Ready(None), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -875,7 +860,10 @@ mod tests { | ||||
|         pool.pooled(c(key.clone()), Uniq(5)); | ||||
|         pool.pooled(c(key.clone()), Uniq(99)); | ||||
|  | ||||
|         assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(3)); | ||||
|         assert_eq!( | ||||
|             pool.locked().idle.get(&key).map(|entries| entries.len()), | ||||
|             Some(3) | ||||
|         ); | ||||
|         tokio::time::delay_for(pool.locked().timeout.unwrap()).await; | ||||
|  | ||||
|         let mut checkout = pool.checkout(key.clone()); | ||||
| @@ -895,7 +883,10 @@ mod tests { | ||||
|         pool.pooled(c(key.clone()), Uniq(99)); | ||||
|  | ||||
|         // pooled and dropped 3, max_idle should only allow 2 | ||||
|         assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(2)); | ||||
|         assert_eq!( | ||||
|             pool.locked().idle.get(&key).map(|entries| entries.len()), | ||||
|             Some(2) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "runtime")] | ||||
| @@ -904,7 +895,8 @@ mod tests { | ||||
|         let _ = pretty_env_logger::try_init(); | ||||
|         tokio::time::pause(); | ||||
|  | ||||
|         let pool = Pool::new(super::Config { | ||||
|         let pool = Pool::new( | ||||
|             super::Config { | ||||
|                 enabled: true, | ||||
|                 keep_alive_timeout: Some(Duration::from_millis(10)), | ||||
|                 max_idle_per_host: ::std::usize::MAX, | ||||
| @@ -918,7 +910,10 @@ mod tests { | ||||
|         pool.pooled(c(key.clone()), Uniq(5)); | ||||
|         pool.pooled(c(key.clone()), Uniq(99)); | ||||
|  | ||||
|         assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(3)); | ||||
|         assert_eq!( | ||||
|             pool.locked().idle.get(&key).map(|entries| entries.len()), | ||||
|             Some(3) | ||||
|         ); | ||||
|  | ||||
|         // Let the timer tick passed the expiration... | ||||
|         tokio::time::advance(Duration::from_millis(30)).await; | ||||
| @@ -937,17 +932,15 @@ mod tests { | ||||
|         let key = Arc::new("foo".to_string()); | ||||
|         let pooled = pool.pooled(c(key.clone()), Uniq(41)); | ||||
|  | ||||
|         let checkout = join( | ||||
|             pool.checkout(key), | ||||
|               async { | ||||
|                 // the checkout future will park first, | ||||
|                 // and then this lazy future will be polled, which will insert | ||||
|                 // the pooled back into the pool | ||||
|                 // | ||||
|                 // this test makes sure that doing so will unpark the checkout | ||||
|                 drop(pooled); | ||||
|             }, | ||||
|         ).map(|(entry, _)| entry); | ||||
|         let checkout = join(pool.checkout(key), async { | ||||
|             // the checkout future will park first, | ||||
|             // and then this lazy future will be polled, which will insert | ||||
|             // the pooled back into the pool | ||||
|             // | ||||
|             // this test makes sure that doing so will unpark the checkout | ||||
|             drop(pooled); | ||||
|         }) | ||||
|         .map(|(entry, _)| entry); | ||||
|  | ||||
|         assert_eq!(*checkout.await.unwrap(), Uniq(41)); | ||||
|     } | ||||
| @@ -1001,10 +994,13 @@ mod tests { | ||||
|     fn pooled_drop_if_closed_doesnt_reinsert() { | ||||
|         let pool = pool_no_timer(); | ||||
|         let key = Arc::new("localhost:12345".to_string()); | ||||
|         pool.pooled(c(key.clone()), CanClose { | ||||
|             val: 57, | ||||
|             closed: true, | ||||
|         }); | ||||
|         pool.pooled( | ||||
|             c(key.clone()), | ||||
|             CanClose { | ||||
|                 val: 57, | ||||
|                 closed: true, | ||||
|             }, | ||||
|         ); | ||||
|  | ||||
|         assert!(!pool.locked().idle.contains_key(&key)); | ||||
|     } | ||||
|   | ||||
| @@ -2,12 +2,16 @@ | ||||
| //! | ||||
| //! This module provides `Connect` which hook-ins into the Tower ecosystem. | ||||
|  | ||||
| use std::marker::PhantomData; | ||||
| use std::future::Future; | ||||
| use std::error::Error as StdError; | ||||
| use std::future::Future; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| use crate::{common::{Poll, task, Pin}, body::Payload, service::{MakeConnection, Service}}; | ||||
| use super::conn::{SendRequest, Builder}; | ||||
| use super::conn::{Builder, SendRequest}; | ||||
| use crate::{ | ||||
|     body::Payload, | ||||
|     common::{task, Pin, Poll}, | ||||
|     service::{MakeConnection, Service}, | ||||
| }; | ||||
|  | ||||
| /// Creates a connection via `SendRequest`. | ||||
| /// | ||||
| @@ -18,7 +22,7 @@ use super::conn::{SendRequest, Builder}; | ||||
| pub struct Connect<C, B, T> { | ||||
|     inner: C, | ||||
|     builder: Builder, | ||||
|     _pd: PhantomData<fn(T, B)> | ||||
|     _pd: PhantomData<fn(T, B)>, | ||||
| } | ||||
|  | ||||
| impl<C, B, T> Connect<C, B, T> { | ||||
| @@ -28,7 +32,7 @@ impl<C, B, T> Connect<C, B, T> { | ||||
|         Self { | ||||
|             inner, | ||||
|             builder, | ||||
|             _pd: PhantomData | ||||
|             _pd: PhantomData, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -44,10 +48,13 @@ where | ||||
| { | ||||
|     type Response = SendRequest<B>; | ||||
|     type Error = crate::Error; | ||||
|     type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>; | ||||
|     type Future = | ||||
|         Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>; | ||||
|  | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||
|         self.inner.poll_ready(cx).map_err(|e| crate::Error::new(crate::error::Kind::Connect).with(e.into())) | ||||
|         self.inner | ||||
|             .poll_ready(cx) | ||||
|             .map_err(|e| crate::Error::new(crate::error::Kind::Connect).with(e.into())) | ||||
|     } | ||||
|  | ||||
|     fn call(&mut self, req: T) -> Self::Future { | ||||
| @@ -56,18 +63,16 @@ where | ||||
|  | ||||
|         let fut = async move { | ||||
|             match io.await { | ||||
|                 Ok(io) => { | ||||
|                     match builder.handshake(io).await { | ||||
|                         Ok((sr, conn)) => { | ||||
|                             builder.exec.execute(async move { | ||||
|                                 if let Err(e) = conn.await { | ||||
|                                     debug!("connection error: {:?}", e); | ||||
|                                 } | ||||
|                             }); | ||||
|                             Ok(sr) | ||||
|                         }, | ||||
|                         Err(e) => Err(e) | ||||
|                 Ok(io) => match builder.handshake(io).await { | ||||
|                     Ok((sr, conn)) => { | ||||
|                         builder.exec.execute(async move { | ||||
|                             if let Err(e) = conn.await { | ||||
|                                 debug!("connection error: {:?}", e); | ||||
|                             } | ||||
|                         }); | ||||
|                         Ok(sr) | ||||
|                     } | ||||
|                     Err(e) => Err(e), | ||||
|                 }, | ||||
|                 Err(e) => { | ||||
|                     let err = crate::Error::new(crate::error::Kind::Connect).with(e.into()); | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| use std::mem; | ||||
|  | ||||
| use tokio::sync::{mpsc, watch}; | ||||
| use pin_project::pin_project; | ||||
| use tokio::sync::{mpsc, watch}; | ||||
|  | ||||
| use super::{Future, Never, Poll, Pin, task}; | ||||
| use super::{task, Future, Never, Pin, Poll}; | ||||
|  | ||||
| // Sentinel value signaling that the watch is still open | ||||
| #[derive(Clone, Copy)] | ||||
| @@ -21,10 +21,7 @@ pub fn channel() -> (Signal, Watch) { | ||||
|             drained_rx, | ||||
|             _tx: tx, | ||||
|         }, | ||||
|         Watch { | ||||
|             drained_tx, | ||||
|             rx, | ||||
|         }, | ||||
|         Watch { drained_tx, rx }, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @@ -107,17 +104,14 @@ where | ||||
|                         Poll::Ready(None) => { | ||||
|                             // Drain has been triggered! | ||||
|                             on_drain(me.future.as_mut()); | ||||
|                         }, | ||||
|                         Poll::Ready(Some(_/*State::Open*/)) | | ||||
|                         Poll::Pending => { | ||||
|                         } | ||||
|                         Poll::Ready(Some(_ /*State::Open*/)) | Poll::Pending => { | ||||
|                             *me.state = State::Watch(on_drain); | ||||
|                             return me.future.poll(cx); | ||||
|                         }, | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 State::Draining => { | ||||
|                     return me.future.poll(cx) | ||||
|                 }, | ||||
|                 } | ||||
|                 State::Draining => return me.future.poll(cx), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -236,4 +230,3 @@ mod tests { | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use std::future::Future; | ||||
| use std::pin::Pin; | ||||
| use std::sync::Arc; | ||||
|  | ||||
| use crate::body::{Payload, Body}; | ||||
| use crate::body::{Body, Payload}; | ||||
| use crate::proto::h2::server::H2Stream; | ||||
| use crate::server::conn::spawn_all::{NewSvcTask, Watcher}; | ||||
| use crate::service::HttpService; | ||||
| @@ -22,7 +22,7 @@ pub trait NewSvcExec<I, N, S: HttpService<Body>, E, W: Watcher<I, S, E>>: Clone | ||||
|     fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>); | ||||
| } | ||||
|  | ||||
| pub type BoxSendFuture = Pin<Box<dyn Future<Output=()> + Send>>; | ||||
| pub type BoxSendFuture = Pin<Box<dyn Future<Output = ()> + Send>>; | ||||
|  | ||||
| // Either the user provides an executor for background tasks, or we use | ||||
| // `tokio::spawn`. | ||||
| @@ -37,7 +37,7 @@ pub enum Exec { | ||||
| impl Exec { | ||||
|     pub(crate) fn execute<F>(&self, fut: F) | ||||
|     where | ||||
|         F: Future<Output=()> + Send + 'static, | ||||
|         F: Future<Output = ()> + Send + 'static, | ||||
|     { | ||||
|         match *self { | ||||
|             Exec::Default => { | ||||
| @@ -50,22 +50,20 @@ impl Exec { | ||||
|                     // If no runtime, we need an executor! | ||||
|                     panic!("executor must be set") | ||||
|                 } | ||||
|             }, | ||||
|             } | ||||
|             Exec::Executor(ref e) => { | ||||
|                 e.execute(Box::pin(fut)); | ||||
|             }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Exec { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Exec") | ||||
|             .finish() | ||||
|         f.debug_struct("Exec").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<F, B> H2Exec<F, B> for Exec | ||||
| where | ||||
|     H2Stream<F, B>: Future<Output = ()> + Send + 'static, | ||||
| @@ -78,7 +76,7 @@ where | ||||
|  | ||||
| impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec | ||||
| where | ||||
|     NewSvcTask<I, N, S, E, W>: Future<Output=()> + Send + 'static, | ||||
|     NewSvcTask<I, N, S, E, W>: Future<Output = ()> + Send + 'static, | ||||
|     S: HttpService<Body>, | ||||
|     W: Watcher<I, S, E>, | ||||
| { | ||||
| @@ -92,7 +90,7 @@ where | ||||
| impl<E, F, B> H2Exec<F, B> for E | ||||
| where | ||||
|     E: Executor<H2Stream<F, B>> + Clone, | ||||
|     H2Stream<F, B>: Future<Output=()>, | ||||
|     H2Stream<F, B>: Future<Output = ()>, | ||||
|     B: Payload, | ||||
| { | ||||
|     fn execute_h2stream(&mut self, fut: H2Stream<F, B>) { | ||||
| @@ -103,7 +101,7 @@ where | ||||
| impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E | ||||
| where | ||||
|     E: Executor<NewSvcTask<I, N, S, E, W>> + Clone, | ||||
|     NewSvcTask<I, N, S, E, W>: Future<Output=()>, | ||||
|     NewSvcTask<I, N, S, E, W>: Future<Output = ()>, | ||||
|     S: HttpService<Body>, | ||||
|     W: Watcher<I, S, E>, | ||||
| { | ||||
| @@ -111,4 +109,3 @@ where | ||||
|         self.execute(fut) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| use std::{cmp, io}; | ||||
| use std::marker::Unpin; | ||||
| use std::{cmp, io}; | ||||
|  | ||||
| use bytes::{Buf, Bytes}; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use crate::common::{Pin, Poll, task}; | ||||
| use crate::common::{task, Pin, Poll}; | ||||
|  | ||||
| /// Combine a buffer with an IO, rewinding reads to use the buffer. | ||||
| #[derive(Debug)] | ||||
| @@ -47,7 +47,11 @@ where | ||||
|         self.inner.prepare_uninitialized_buffer(buf) | ||||
|     } | ||||
|  | ||||
|     fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> { | ||||
|     fn poll_read( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|         buf: &mut [u8], | ||||
|     ) -> Poll<io::Result<usize>> { | ||||
|         if let Some(mut prefix) = self.pre.take() { | ||||
|             // If there are no remaining bytes, let the bytes get dropped. | ||||
|             if prefix.len() > 0 { | ||||
| @@ -69,7 +73,11 @@ impl<T> AsyncWrite for Rewind<T> | ||||
| where | ||||
|     T: AsyncWrite + Unpin, | ||||
| { | ||||
|     fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> { | ||||
|     fn poll_write( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|         buf: &[u8], | ||||
|     ) -> Poll<io::Result<usize>> { | ||||
|         Pin::new(&mut self.inner).poll_write(cx, buf) | ||||
|     } | ||||
|  | ||||
| @@ -82,7 +90,11 @@ where | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     fn poll_write_buf<B: Buf>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> { | ||||
|     fn poll_write_buf<B: Buf>( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|         buf: &mut B, | ||||
|     ) -> Poll<io::Result<usize>> { | ||||
|         Pin::new(&mut self.inner).poll_write_buf(cx, buf) | ||||
|     } | ||||
| } | ||||
| @@ -91,36 +103,27 @@ where | ||||
| mod tests { | ||||
|     // FIXME: re-implement tests with `async/await`, this import should | ||||
|     // trigger a warning to remind us | ||||
|     use super::Rewind; | ||||
|     use bytes::Bytes; | ||||
|     use tokio::io::AsyncReadExt; | ||||
|     use super::Rewind; | ||||
|  | ||||
|     #[tokio::test] | ||||
|     async fn partial_rewind() { | ||||
|         let underlying = [104, 101, 108, 108, 111]; | ||||
|  | ||||
|         let mock = tokio_test::io::Builder::new() | ||||
|             .read(&underlying) | ||||
|             .build(); | ||||
|         let mock = tokio_test::io::Builder::new().read(&underlying).build(); | ||||
|  | ||||
|         let mut stream = Rewind::new(mock); | ||||
|  | ||||
|         // Read off some bytes, ensure we filled o1 | ||||
|         let mut buf = [0; 2]; | ||||
|         stream | ||||
|             .read_exact(&mut buf) | ||||
|             .await | ||||
|             .expect("read1"); | ||||
|  | ||||
|         stream.read_exact(&mut buf).await.expect("read1"); | ||||
|  | ||||
|         // Rewind the stream so that it is as if we never read in the first place. | ||||
|         stream.rewind(Bytes::copy_from_slice(&buf[..])); | ||||
|  | ||||
|         let mut buf = [0; 5]; | ||||
|         stream | ||||
|             .read_exact(&mut buf) | ||||
|             .await | ||||
|             .expect("read1"); | ||||
|         stream.read_exact(&mut buf).await.expect("read1"); | ||||
|  | ||||
|         // At this point we should have read everything that was in the MockStream | ||||
|         assert_eq!(&buf, &underlying); | ||||
| @@ -130,26 +133,17 @@ mod tests { | ||||
|     async fn full_rewind() { | ||||
|         let underlying = [104, 101, 108, 108, 111]; | ||||
|  | ||||
|         let mock = tokio_test::io::Builder::new() | ||||
|             .read(&underlying) | ||||
|             .build(); | ||||
|         let mock = tokio_test::io::Builder::new().read(&underlying).build(); | ||||
|  | ||||
|         let mut stream = Rewind::new(mock); | ||||
|  | ||||
|         let mut buf = [0; 5]; | ||||
|         stream | ||||
|             .read_exact(&mut buf) | ||||
|             .await | ||||
|             .expect("read1"); | ||||
|  | ||||
|         stream.read_exact(&mut buf).await.expect("read1"); | ||||
|  | ||||
|         // Rewind the stream so that it is as if we never read in the first place. | ||||
|         stream.rewind(Bytes::copy_from_slice(&buf[..])); | ||||
|  | ||||
|         let mut buf = [0; 5]; | ||||
|         stream | ||||
|             .read_exact(&mut buf) | ||||
|             .await | ||||
|             .expect("read1"); | ||||
|         stream.read_exact(&mut buf).await.expect("read1"); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use std::mem; | ||||
|  | ||||
| use super::{Future, Pin, Poll, task}; | ||||
| use super::{task, Future, Pin, Poll}; | ||||
|  | ||||
| pub(crate) trait Started: Future { | ||||
|     fn started(&self) -> bool; | ||||
| @@ -19,7 +19,7 @@ where | ||||
| // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||
| #[allow(missing_debug_implementations)] | ||||
| pub(crate) struct Lazy<F, R> { | ||||
|     inner: Inner<F, R> | ||||
|     inner: Inner<F, R>, | ||||
| } | ||||
|  | ||||
| enum Inner<F, R> { | ||||
| @@ -36,8 +36,7 @@ where | ||||
|     fn started(&self) -> bool { | ||||
|         match self.inner { | ||||
|             Inner::Init(_) => false, | ||||
|             Inner::Fut(_) | | ||||
|             Inner::Empty => true, | ||||
|             Inner::Fut(_) | Inner::Empty => true, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -61,7 +60,7 @@ where | ||||
|                 let ret = Pin::new(&mut fut).poll(cx); | ||||
|                 self.inner = Inner::Fut(fut); | ||||
|                 ret | ||||
|             }, | ||||
|             } | ||||
|             _ => unreachable!("lazy state wrong"), | ||||
|         } | ||||
|     } | ||||
| @@ -69,4 +68,3 @@ where | ||||
|  | ||||
| // The closure `F` is never pinned | ||||
| impl<F, R: Unpin> Unpin for Lazy<F, R> {} | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| macro_rules! ready { | ||||
|     ($e:expr) => ( | ||||
|     ($e:expr) => { | ||||
|         match $e { | ||||
|             ::std::task::Poll::Ready(v) => v, | ||||
|             ::std::task::Poll::Pending => return ::std::task::Poll::Pending, | ||||
|         } | ||||
|     ) | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pub(crate) mod drain; | ||||
| @@ -14,16 +14,11 @@ mod lazy; | ||||
| mod never; | ||||
| pub(crate) mod task; | ||||
|  | ||||
| pub(crate) use self::exec::{BoxSendFuture, Exec}; | ||||
| pub use self::exec::Executor; | ||||
| pub(crate) use self::exec::{BoxSendFuture, Exec}; | ||||
| pub(crate) use self::lazy::{lazy, Started as Lazy}; | ||||
| pub use self::never::Never; | ||||
| pub(crate) use self::task::Poll; | ||||
|  | ||||
| // group up types normally needed for `Future` | ||||
| pub(crate) use std::{ | ||||
|     future::Future, | ||||
|     marker::Unpin, | ||||
|     pin::Pin, | ||||
| }; | ||||
|  | ||||
| pub(crate) use std::{future::Future, marker::Unpin, pin::Pin}; | ||||
|   | ||||
| @@ -19,4 +19,3 @@ impl Error for Never { | ||||
|         match *self {} | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| pub(crate) use std::task::{Context, Poll}; | ||||
| use super::Never; | ||||
| pub(crate) use std::task::{Context, Poll}; | ||||
|  | ||||
| /// A function to help "yield" a future, such that it is re-scheduled immediately. | ||||
| /// | ||||
|   | ||||
							
								
								
									
										26
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								src/error.rs
									
									
									
									
									
								
							| @@ -140,10 +140,7 @@ impl Error { | ||||
|  | ||||
|     pub(crate) fn new(kind: Kind) -> Error { | ||||
|         Error { | ||||
|             inner: Box::new(ErrorImpl { | ||||
|                 kind, | ||||
|                 cause: None, | ||||
|             }), | ||||
|             inner: Box::new(ErrorImpl { kind, cause: None }), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -162,9 +159,7 @@ impl Error { | ||||
|         let mut cause = self.source(); | ||||
|         while let Some(err) = cause { | ||||
|             if let Some(h2_err) = err.downcast_ref::<h2::Error>() { | ||||
|                 return h2_err | ||||
|                     .reason() | ||||
|                     .unwrap_or(h2::Reason::INTERNAL_ERROR); | ||||
|                 return h2_err.reason().unwrap_or(h2::Reason::INTERNAL_ERROR); | ||||
|             } | ||||
|             cause = err.source(); | ||||
|         } | ||||
| @@ -335,7 +330,9 @@ impl StdError for Error { | ||||
|             Kind::User(User::UnexpectedHeader) => "user sent unexpected header", | ||||
|             Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version", | ||||
|             Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method", | ||||
|             Kind::User(User::UnsupportedStatusCode) => "response has 1xx status code, not supported by server", | ||||
|             Kind::User(User::UnsupportedStatusCode) => { | ||||
|                 "response has 1xx status code, not supported by server" | ||||
|             } | ||||
|             Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs", | ||||
|             Kind::User(User::NoUpgrade) => "no upgrade available", | ||||
|             Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use", | ||||
| @@ -343,8 +340,7 @@ impl StdError for Error { | ||||
|     } | ||||
|  | ||||
|     fn source(&self) -> Option<&(dyn StdError + 'static)> { | ||||
|         self | ||||
|             .inner | ||||
|         self.inner | ||||
|             .cause | ||||
|             .as_ref() | ||||
|             .map(|cause| &**cause as &(dyn StdError + 'static)) | ||||
| @@ -361,10 +357,10 @@ impl From<Parse> for Error { | ||||
| impl From<httparse::Error> for Parse { | ||||
|     fn from(err: httparse::Error) -> Parse { | ||||
|         match err { | ||||
|             httparse::Error::HeaderName | | ||||
|             httparse::Error::HeaderValue | | ||||
|             httparse::Error::NewLine | | ||||
|             httparse::Error::Token => Parse::Header, | ||||
|             httparse::Error::HeaderName | ||||
|             | httparse::Error::HeaderValue | ||||
|             | httparse::Error::NewLine | ||||
|             | httparse::Error::Token => Parse::Header, | ||||
|             httparse::Error::Status => Parse::Status, | ||||
|             httparse::Error::TooManyHeaders => Parse::TooLarge, | ||||
|             httparse::Error::Version => Parse::Version, | ||||
| @@ -403,8 +399,8 @@ impl AssertSendSync for Error {} | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use std::mem; | ||||
|     use super::*; | ||||
|     use std::mem; | ||||
|  | ||||
|     #[test] | ||||
|     fn error_size_of() { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use bytes::BytesMut; | ||||
| use http::HeaderMap; | ||||
| use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; | ||||
| use http::header::{HeaderValue, OccupiedEntry, ValueIter}; | ||||
| use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; | ||||
| use http::HeaderMap; | ||||
|  | ||||
| pub fn connection_keep_alive(value: &HeaderValue) -> bool { | ||||
|     connection_has(value, "keep-alive") | ||||
| @@ -23,10 +23,7 @@ fn connection_has(value: &HeaderValue, needle: &str) -> bool { | ||||
| } | ||||
|  | ||||
| pub fn content_length_parse(value: &HeaderValue) -> Option<u64> { | ||||
|     value | ||||
|         .to_str() | ||||
|         .ok() | ||||
|         .and_then(|s| s.parse().ok()) | ||||
|     value.to_str().ok().and_then(|s| s.parse().ok()) | ||||
| } | ||||
|  | ||||
| pub fn content_length_parse_all(headers: &HeaderMap) -> Option<u64> { | ||||
| @@ -38,23 +35,20 @@ pub fn content_length_parse_all_values(values: ValueIter<'_, HeaderValue>) -> Op | ||||
|     // be alright if they all contain the same value, and all parse | ||||
|     // correctly. If not, then it's an error. | ||||
|  | ||||
|     let folded = values | ||||
|         .fold(None, |prev, line| match prev { | ||||
|             Some(Ok(prev)) => { | ||||
|                 Some(line | ||||
|                     .to_str() | ||||
|                     .map_err(|_| ()) | ||||
|                     .and_then(|s| s.parse().map_err(|_| ())) | ||||
|                     .and_then(|n| if prev == n { Ok(n) } else { Err(()) })) | ||||
|             }, | ||||
|             None => { | ||||
|                 Some(line | ||||
|                     .to_str() | ||||
|                     .map_err(|_| ()) | ||||
|                     .and_then(|s| s.parse().map_err(|_| ()))) | ||||
|             }, | ||||
|             Some(Err(())) => Some(Err(())), | ||||
|         }); | ||||
|     let folded = values.fold(None, |prev, line| match prev { | ||||
|         Some(Ok(prev)) => Some( | ||||
|             line.to_str() | ||||
|                 .map_err(|_| ()) | ||||
|                 .and_then(|s| s.parse().map_err(|_| ())) | ||||
|                 .and_then(|n| if prev == n { Ok(n) } else { Err(()) }), | ||||
|         ), | ||||
|         None => Some( | ||||
|             line.to_str() | ||||
|                 .map_err(|_| ()) | ||||
|                 .and_then(|s| s.parse().map_err(|_| ())), | ||||
|         ), | ||||
|         Some(Err(())) => Some(Err(())), | ||||
|     }); | ||||
|  | ||||
|     if let Some(Ok(n)) = folded { | ||||
|         Some(n) | ||||
|   | ||||
							
								
								
									
										27
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -29,38 +29,31 @@ | ||||
| //!   TCP (using tokio). | ||||
| //! - `stream` (*enabled by default*): Provides `futures::Stream` capabilities. | ||||
|  | ||||
| #[doc(hidden)] pub use http; | ||||
| #[macro_use] extern crate log; | ||||
| #[doc(hidden)] | ||||
| pub use http; | ||||
| #[macro_use] | ||||
| extern crate log; | ||||
|  | ||||
| #[cfg(all(test, feature = "nightly"))] | ||||
| extern crate test; | ||||
|  | ||||
| pub use http::{ | ||||
|     header, | ||||
|     HeaderMap, | ||||
|     Method, | ||||
|     Request, | ||||
|     Response, | ||||
|     StatusCode, | ||||
|     Uri, | ||||
|     Version, | ||||
| }; | ||||
| pub use http::{header, HeaderMap, Method, Request, Response, StatusCode, Uri, Version}; | ||||
|  | ||||
| pub use crate::client::Client; | ||||
| pub use crate::error::{Result, Error}; | ||||
| pub use crate::body::{Body, Chunk}; | ||||
| pub use crate::client::Client; | ||||
| pub use crate::error::{Error, Result}; | ||||
| pub use crate::server::Server; | ||||
|  | ||||
| #[macro_use] | ||||
| mod common; | ||||
| #[cfg(test)] | ||||
| mod mock; | ||||
| pub mod body; | ||||
| pub mod client; | ||||
| pub mod error; | ||||
| mod headers; | ||||
| #[cfg(test)] | ||||
| mod mock; | ||||
| mod proto; | ||||
| pub mod rt; | ||||
| pub mod server; | ||||
| pub mod service; | ||||
| pub mod rt; | ||||
| pub mod upgrade; | ||||
|   | ||||
| @@ -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), | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,10 @@ | ||||
| #[cfg(feature = "stream")] | ||||
| use futures_core::Stream; | ||||
|  | ||||
| use crate::common::{Pin, task::{self, Poll}}; | ||||
| use crate::common::{ | ||||
|     task::{self, Poll}, | ||||
|     Pin, | ||||
| }; | ||||
|  | ||||
| /// Asynchronously accept incoming connections. | ||||
| pub trait Accept { | ||||
| @@ -19,8 +22,10 @@ pub trait Accept { | ||||
|     type Error; | ||||
|  | ||||
|     /// Poll to accept the next connection. | ||||
|     fn poll_accept(self: Pin<&mut Self>, cx: &mut task::Context<'_>) | ||||
|         -> Poll<Option<Result<Self::Conn, Self::Error>>>; | ||||
|     fn poll_accept( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<Result<Self::Conn, Self::Error>>>; | ||||
| } | ||||
|  | ||||
| /// Create an `Accept` with a polling function. | ||||
| @@ -54,12 +59,11 @@ where | ||||
|     { | ||||
|         type Conn = IO; | ||||
|         type Error = E; | ||||
|         fn poll_accept(self: Pin<&mut Self>, cx: &mut task::Context<'_>) | ||||
|             -> Poll<Option<Result<Self::Conn, Self::Error>>> | ||||
|         { | ||||
|             unsafe { | ||||
|                 (self.get_unchecked_mut().0)(cx) | ||||
|             } | ||||
|         fn poll_accept( | ||||
|             self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|         ) -> Poll<Option<Result<Self::Conn, Self::Error>>> { | ||||
|             unsafe { (self.get_unchecked_mut().0)(cx) } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -85,13 +89,11 @@ where | ||||
|     { | ||||
|         type Conn = IO; | ||||
|         type Error = E; | ||||
|         fn poll_accept(self: Pin<&mut Self>, cx: &mut task::Context<'_>) | ||||
|             -> Poll<Option<Result<Self::Conn, Self::Error>>> | ||||
|         { | ||||
|             unsafe { | ||||
|                 Pin::new_unchecked(&mut self.get_unchecked_mut().0) | ||||
|                     .poll_next(cx) | ||||
|             } | ||||
|         fn poll_accept( | ||||
|             self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|         ) -> Poll<Option<Result<Self::Conn, Self::Error>>> { | ||||
|             unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0).poll_next(cx) } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -11,29 +11,31 @@ | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| use std::mem; | ||||
| #[cfg(feature = "tcp")] use std::net::SocketAddr; | ||||
| #[cfg(feature = "tcp")] | ||||
| use std::net::SocketAddr; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use futures_core::Stream; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
| use pin_project::{pin_project, project}; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use super::Accept; | ||||
| use crate::body::{Body, Payload}; | ||||
| use crate::common::exec::{Exec, H2Exec, NewSvcExec}; | ||||
| use crate::common::io::Rewind; | ||||
| use crate::common::{Future, Pin, Poll, Unpin, task}; | ||||
| use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
| use crate::error::{Kind, Parse}; | ||||
| use crate::proto; | ||||
| use crate::service::{MakeServiceRef, HttpService}; | ||||
| use crate::service::{HttpService, MakeServiceRef}; | ||||
| use crate::upgrade::Upgraded; | ||||
| use super::Accept; | ||||
|  | ||||
| pub(super) use self::spawn_all::NoopWatcher; | ||||
| use self::spawn_all::NewSvcTask; | ||||
| pub(super) use self::spawn_all::NoopWatcher; | ||||
| pub(super) use self::spawn_all::Watcher; | ||||
| pub(super) use self::upgrades::UpgradeableConnection; | ||||
|  | ||||
| #[cfg(feature = "tcp")] pub use super::tcp::{AddrIncoming, AddrStream}; | ||||
| #[cfg(feature = "tcp")] | ||||
| pub use super::tcp::{AddrIncoming, AddrStream}; | ||||
|  | ||||
| // Our defaults are chosen for the "majority" case, which usually are not | ||||
| // resource contrained, and so the spec default of 64kb can be too limiting | ||||
| @@ -161,7 +163,7 @@ impl<E> Unpin for Fallback<E> {} | ||||
| /// This allows taking apart a `Connection` at a later time, in order to | ||||
| /// reclaim the IO object, and additional related pieces. | ||||
| #[derive(Debug)] | ||||
| pub struct Parts<T, S>  { | ||||
| pub struct Parts<T, S> { | ||||
|     /// The original IO object used in the handshake. | ||||
|     pub io: T, | ||||
|     /// A buffer of bytes that have been read but not processed as HTTP. | ||||
| @@ -274,7 +276,10 @@ impl<E> Http<E> { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     pub fn http2_initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|     pub fn http2_initial_connection_window_size( | ||||
|         &mut self, | ||||
|         sz: impl Into<Option<u32>>, | ||||
|     ) -> &mut Self { | ||||
|         if let Some(sz) = sz.into() { | ||||
|             self.h2_builder.initial_connection_window_size(sz); | ||||
|         } | ||||
| @@ -374,7 +379,7 @@ impl<E> Http<E> { | ||||
|     /// ``` | ||||
|     pub fn serve_connection<S, I, Bd>(&self, io: I, service: S) -> Connection<I, S, E> | ||||
|     where | ||||
|         S: HttpService<Body, ResBody=Bd>, | ||||
|         S: HttpService<Body, ResBody = Bd>, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         Bd: Payload, | ||||
|         Bd::Data: Unpin, | ||||
| @@ -402,7 +407,8 @@ impl<E> Http<E> { | ||||
|             } | ||||
|             ConnectionMode::H2Only => { | ||||
|                 let rewind_io = Rewind::new(io); | ||||
|                 let h2 = proto::h2::Server::new(rewind_io, service, &self.h2_builder, self.exec.clone()); | ||||
|                 let h2 = | ||||
|                     proto::h2::Server::new(rewind_io, service, &self.h2_builder, self.exec.clone()); | ||||
|                 ProtoServer::H2(h2) | ||||
|             } | ||||
|         }; | ||||
| @@ -419,14 +425,10 @@ impl<E> Http<E> { | ||||
|  | ||||
|     pub(super) fn serve<I, IO, IE, S, Bd>(&self, incoming: I, make_service: S) -> Serve<I, S, E> | ||||
|     where | ||||
|         I: Accept<Conn=IO, Error=IE>, | ||||
|         I: Accept<Conn = IO, Error = IE>, | ||||
|         IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         IO: AsyncRead + AsyncWrite + Unpin, | ||||
|         S: MakeServiceRef< | ||||
|             IO, | ||||
|             Body, | ||||
|             ResBody=Bd, | ||||
|         >, | ||||
|         S: MakeServiceRef<IO, Body, ResBody = Bd>, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         Bd: Payload, | ||||
|         E: H2Exec<<S::Service as HttpService<Body>>::Future, Bd>, | ||||
| @@ -439,12 +441,11 @@ impl<E> Http<E> { | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| // ===== impl Connection ===== | ||||
|  | ||||
| impl<I, B, S, E> Connection<I, S, E> | ||||
| where | ||||
|     S: HttpService<Body, ResBody=B>, | ||||
|     S: HttpService<Body, ResBody = B>, | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     I: AsyncRead + AsyncWrite + Unpin, | ||||
|     B: Payload + 'static, | ||||
| @@ -459,7 +460,7 @@ where | ||||
|         match self.project().conn.as_mut().unwrap() { | ||||
|             ProtoServer::H1(ref mut h1) => { | ||||
|                 h1.disable_keep_alive(); | ||||
|             }, | ||||
|             } | ||||
|             ProtoServer::H2(ref mut h2) => { | ||||
|                 h2.graceful_shutdown(); | ||||
|             } | ||||
| @@ -476,7 +477,8 @@ where | ||||
|     /// # Panics | ||||
|     /// This method will panic if this connection is using an h2 protocol. | ||||
|     pub fn into_parts(self) -> Parts<I, S> { | ||||
|         self.try_into_parts().unwrap_or_else(|| panic!("h2 cannot into_inner")) | ||||
|         self.try_into_parts() | ||||
|             .unwrap_or_else(|| panic!("h2 cannot into_inner")) | ||||
|     } | ||||
|  | ||||
|     /// Return the inner IO object, and additional information, if available. | ||||
| @@ -492,7 +494,7 @@ where | ||||
|                     service: dispatch.into_service(), | ||||
|                     _inner: (), | ||||
|                 }) | ||||
|             }, | ||||
|             } | ||||
|             ProtoServer::H2(_h2) => None, | ||||
|         } | ||||
|     } | ||||
| @@ -521,22 +523,20 @@ where | ||||
|             }; | ||||
|             match ready!(polled) { | ||||
|                 Ok(x) => return Poll::Ready(Ok(x)), | ||||
|                 Err(e) => { | ||||
|                     match *e.kind() { | ||||
|                         Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                             self.upgrade_h2(); | ||||
|                             continue; | ||||
|                         } | ||||
|                         _ => return Poll::Ready(Err(e)), | ||||
|                 Err(e) => match *e.kind() { | ||||
|                     Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                         self.upgrade_h2(); | ||||
|                         continue; | ||||
|                     } | ||||
|                 } | ||||
|                     _ => return Poll::Ready(Err(e)), | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Prevent shutdown of the underlying IO object at the end of service the request, | ||||
|     /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`. | ||||
|     pub fn without_shutdown(self) -> impl Future<Output=crate::Result<Parts<I, S>>> | ||||
|     pub fn without_shutdown(self) -> impl Future<Output = crate::Result<Parts<I, S>>> | ||||
|     where | ||||
|         S: Unpin, | ||||
|         S::Future: Unpin, | ||||
| @@ -554,9 +554,7 @@ where | ||||
|         let conn = self.conn.take(); | ||||
|  | ||||
|         let (io, read_buf, dispatch) = match conn.unwrap() { | ||||
|             ProtoServer::H1(h1) => { | ||||
|                 h1.into_inner() | ||||
|             }, | ||||
|             ProtoServer::H1(h1) => h1.into_inner(), | ||||
|             ProtoServer::H2(_h2) => { | ||||
|                 panic!("h2 cannot into_inner"); | ||||
|             } | ||||
| @@ -567,12 +565,7 @@ where | ||||
|             Fallback::ToHttp2(ref builder, ref exec) => (builder, exec), | ||||
|             Fallback::Http1Only => unreachable!("upgrade_h2 with Fallback::Http1Only"), | ||||
|         }; | ||||
|         let h2 = proto::h2::Server::new( | ||||
|             rewind_io, | ||||
|             dispatch.into_service(), | ||||
|             builder, | ||||
|             exec.clone(), | ||||
|         ); | ||||
|         let h2 = proto::h2::Server::new(rewind_io, dispatch.into_service(), builder, exec.clone()); | ||||
|  | ||||
|         debug_assert!(self.conn.is_none()); | ||||
|         self.conn = Some(ProtoServer::H2(h2)); | ||||
| @@ -585,15 +578,13 @@ where | ||||
|     where | ||||
|         I: Send, | ||||
|     { | ||||
|         UpgradeableConnection { | ||||
|             inner: self, | ||||
|         } | ||||
|         UpgradeableConnection { inner: self } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<I, B, S, E> Future for Connection<I, S, E> | ||||
| where | ||||
|     S: HttpService<Body, ResBody=B>, | ||||
|     S: HttpService<Body, ResBody = B>, | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     I: AsyncRead + AsyncWrite + Unpin + 'static, | ||||
|     B: Payload + 'static, | ||||
| @@ -614,16 +605,14 @@ where | ||||
|                         pending.manual(); | ||||
|                     } | ||||
|                     return Poll::Ready(Ok(())); | ||||
|                 }, | ||||
|                 Err(e) => { | ||||
|                     match *e.kind() { | ||||
|                         Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                             self.upgrade_h2(); | ||||
|                             continue; | ||||
|                         } | ||||
|                         _ => return Poll::Ready(Err(e)), | ||||
|                     } | ||||
|                 } | ||||
|                 Err(e) => match *e.kind() { | ||||
|                     Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                         self.upgrade_h2(); | ||||
|                         continue; | ||||
|                     } | ||||
|                     _ => return Poll::Ready(Err(e)), | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -634,8 +623,7 @@ where | ||||
|     S: HttpService<Body>, | ||||
| { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Connection") | ||||
|             .finish() | ||||
|         f.debug_struct("Connection").finish() | ||||
|     } | ||||
| } | ||||
| // ===== impl Serve ===== | ||||
| @@ -655,25 +643,23 @@ impl<I, S, E> Serve<I, S, E> { | ||||
|  | ||||
|     /// Spawn all incoming connections onto the executor in `Http`. | ||||
|     pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> { | ||||
|         SpawnAll { | ||||
|             serve: self, | ||||
|         } | ||||
|         SpawnAll { serve: self } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| impl<I, IO, IE, S, B, E> Serve<I, S, E> | ||||
| where | ||||
|     I: Accept<Conn=IO, Error=IE>, | ||||
|     I: Accept<Conn = IO, Error = IE>, | ||||
|     IO: AsyncRead + AsyncWrite + Unpin, | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody=B>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     B: Payload, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
| { | ||||
|     fn poll_next_(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<crate::Result<Connecting<IO, S::Future, E>>>> { | ||||
|     fn poll_next_( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<crate::Result<Connecting<IO, S::Future, E>>>> { | ||||
|         let me = self.project(); | ||||
|         match ready!(me.make_service.poll_ready_ref(cx)) { | ||||
|             Ok(()) => (), | ||||
| @@ -700,10 +686,10 @@ where | ||||
| // deprecated | ||||
| impl<I, IO, IE, S, B, E> Stream for Serve<I, S, E> | ||||
| where | ||||
|     I: Accept<Conn=IO, Error=IE>, | ||||
|     I: Accept<Conn = IO, Error = IE>, | ||||
|     IO: AsyncRead + AsyncWrite + Unpin, | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody=B>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     B: Payload, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
| { | ||||
| @@ -716,12 +702,11 @@ where | ||||
|  | ||||
| // ===== impl Connecting ===== | ||||
|  | ||||
|  | ||||
| impl<I, F, S, FE, E, B> Future for Connecting<I, F, E> | ||||
| where | ||||
|     I: AsyncRead + AsyncWrite + Unpin, | ||||
|     F: Future<Output=Result<S, FE>>, | ||||
|     S: HttpService<Body, ResBody=B>, | ||||
|     F: Future<Output = Result<S, FE>>, | ||||
|     S: HttpService<Body, ResBody = B>, | ||||
|     B: Payload, | ||||
|     B::Data: Unpin, | ||||
|     E: H2Exec<S::Future, B>, | ||||
| @@ -753,18 +738,18 @@ impl<I, S, E> SpawnAll<I, S, E> { | ||||
|  | ||||
| impl<I, IO, IE, S, B, E> SpawnAll<I, S, E> | ||||
| where | ||||
|     I: Accept<Conn=IO, Error=IE>, | ||||
|     I: Accept<Conn = IO, Error = IE>, | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     IO: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|     S: MakeServiceRef< | ||||
|         IO, | ||||
|         Body, | ||||
|         ResBody=B, | ||||
|     >, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     B: Payload, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
| { | ||||
|     pub(super) fn poll_watch<W>(self: Pin<&mut Self>, cx: &mut task::Context<'_>, watcher: &W) -> Poll<crate::Result<()>> | ||||
|     pub(super) fn poll_watch<W>( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|         watcher: &W, | ||||
|     ) -> Poll<crate::Result<()>> | ||||
|     where | ||||
|         E: NewSvcExec<IO, S::Future, S::Service, E, W>, | ||||
|         W: Watcher<IO, S::Service, E>, | ||||
| @@ -773,7 +758,12 @@ where | ||||
|         loop { | ||||
|             if let Some(connecting) = ready!(me.serve.as_mut().poll_next_(cx)?) { | ||||
|                 let fut = NewSvcTask::new(connecting, watcher.clone()); | ||||
|                 me.serve.as_mut().project().protocol.exec.execute_new_svc(fut); | ||||
|                 me.serve | ||||
|                     .as_mut() | ||||
|                     .project() | ||||
|                     .protocol | ||||
|                     .exec | ||||
|                     .execute_new_svc(fut); | ||||
|             } else { | ||||
|                 return Poll::Ready(Ok(())); | ||||
|             } | ||||
| @@ -808,11 +798,11 @@ pub(crate) mod spawn_all { | ||||
|     use std::error::Error as StdError; | ||||
|     use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
|     use super::{Connecting, UpgradeableConnection}; | ||||
|     use crate::body::{Body, Payload}; | ||||
|     use crate::common::exec::H2Exec; | ||||
|     use crate::common::{Future, Pin, Poll, Unpin, task}; | ||||
|     use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
|     use crate::service::HttpService; | ||||
|     use super::{Connecting, UpgradeableConnection}; | ||||
|     use pin_project::{pin_project, project}; | ||||
|  | ||||
|     // Used by `SpawnAll` to optionally watch a `Connection` future. | ||||
| @@ -881,9 +871,9 @@ pub(crate) mod spawn_all { | ||||
|     impl<I, N, S, NE, B, E, W> Future for NewSvcTask<I, N, S, E, W> | ||||
|     where | ||||
|         I: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|         N: Future<Output=Result<S, NE>>, | ||||
|         N: Future<Output = Result<S, NE>>, | ||||
|         NE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         S: HttpService<Body, ResBody=B>, | ||||
|         S: HttpService<Body, ResBody = B>, | ||||
|         B: Payload, | ||||
|         B::Data: Unpin, | ||||
|         E: H2Exec<S::Future, B>, | ||||
| @@ -914,15 +904,13 @@ pub(crate) mod spawn_all { | ||||
|                             }; | ||||
|                             let connected = watcher.watch(conn.with_upgrades()); | ||||
|                             State::Connected(connected) | ||||
|                         }, | ||||
|                         } | ||||
|                         State::Connected(future) => { | ||||
|                             return future | ||||
|                                 .poll(cx) | ||||
|                                 .map(|res| { | ||||
|                                     if let Err(err) = res { | ||||
|                                         debug!("connection error: {}", err); | ||||
|                                     } | ||||
|                                 }); | ||||
|                             return future.poll(cx).map(|res| { | ||||
|                                 if let Err(err) = res { | ||||
|                                     debug!("connection error: {}", err); | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                     } | ||||
|                 }; | ||||
| @@ -951,7 +939,7 @@ mod upgrades { | ||||
|  | ||||
|     impl<I, B, S, E> UpgradeableConnection<I, S, E> | ||||
|     where | ||||
|         S: HttpService<Body, ResBody=B>, | ||||
|         S: HttpService<Body, ResBody = B>, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         I: AsyncRead + AsyncWrite + Unpin, | ||||
|         B: Payload + 'static, | ||||
| @@ -969,7 +957,7 @@ mod upgrades { | ||||
|  | ||||
|     impl<I, B, S, E> Future for UpgradeableConnection<I, S, E> | ||||
|     where | ||||
|         S: HttpService<Body, ResBody=B>, | ||||
|         S: HttpService<Body, ResBody = B>, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         I: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|         B: Payload + 'static, | ||||
| @@ -991,19 +979,16 @@ mod upgrades { | ||||
|                         let (io, buf, _) = h1.into_inner(); | ||||
|                         pending.fulfill(Upgraded::new(Box::new(io), buf)); | ||||
|                         return Poll::Ready(Ok(())); | ||||
|                     }, | ||||
|                     Err(e) => { | ||||
|                         match *e.kind() { | ||||
|                             Kind::Parse(Parse::VersionH2) if self.inner.fallback.to_h2() => { | ||||
|                                 self.inner.upgrade_h2(); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             _ => return Poll::Ready(Err(e)), | ||||
|                         } | ||||
|                     } | ||||
|                     Err(e) => match *e.kind() { | ||||
|                         Kind::Parse(Parse::VersionH2) if self.inner.fallback.to_h2() => { | ||||
|                             self.inner.upgrade_h2(); | ||||
|                             continue; | ||||
|                         } | ||||
|                         _ => return Poll::Ready(Err(e)), | ||||
|                     }, | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -51,27 +51,31 @@ | ||||
| pub mod accept; | ||||
| pub mod conn; | ||||
| mod shutdown; | ||||
| #[cfg(feature = "tcp")] mod tcp; | ||||
| #[cfg(feature = "tcp")] | ||||
| mod tcp; | ||||
|  | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| #[cfg(feature = "tcp")] use std::net::{SocketAddr, TcpListener as StdTcpListener}; | ||||
| #[cfg(feature = "tcp")] | ||||
| use std::net::{SocketAddr, TcpListener as StdTcpListener}; | ||||
|  | ||||
| #[cfg(feature = "tcp")] use std::time::Duration; | ||||
| #[cfg(feature = "tcp")] | ||||
| use std::time::Duration; | ||||
|  | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
| use pin_project::pin_project; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use self::accept::Accept; | ||||
| use crate::body::{Body, Payload}; | ||||
| use crate::common::exec::{Exec, H2Exec, NewSvcExec}; | ||||
| use crate::common::{Future, Pin, Poll, Unpin, task}; | ||||
| use crate::service::{MakeServiceRef, HttpService}; | ||||
| use self::accept::Accept; | ||||
| use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
| use crate::service::{HttpService, MakeServiceRef}; | ||||
| // Renamed `Http` as `Http_` for now so that people upgrading don't see an | ||||
| // error that `hyper::server::Http` is private... | ||||
| use self::conn::{Http as Http_, NoopWatcher, SpawnAll}; | ||||
| use self::shutdown::{Graceful, GracefulWatcher}; | ||||
| #[cfg(feature = "tcp")] use self::tcp::AddrIncoming; | ||||
| #[cfg(feature = "tcp")] | ||||
| use self::tcp::AddrIncoming; | ||||
|  | ||||
| /// A listening HTTP server that accepts connections in both HTTP1 and HTTP2 by default. | ||||
| /// | ||||
| @@ -113,23 +117,20 @@ impl Server<AddrIncoming, ()> { | ||||
|     /// This method will panic if binding to the address fails. For a method | ||||
|     /// to bind to an address and return a `Result`, see `Server::try_bind`. | ||||
|     pub fn bind(addr: &SocketAddr) -> Builder<AddrIncoming> { | ||||
|         let incoming = AddrIncoming::new(addr) | ||||
|             .unwrap_or_else(|e| { | ||||
|                 panic!("error binding to {}: {}", addr, e); | ||||
|             }); | ||||
|         let incoming = AddrIncoming::new(addr).unwrap_or_else(|e| { | ||||
|             panic!("error binding to {}: {}", addr, e); | ||||
|         }); | ||||
|         Server::builder(incoming) | ||||
|     } | ||||
|  | ||||
|     /// Tries to bind to the provided address, and returns a [`Builder`](Builder). | ||||
|     pub fn try_bind(addr: &SocketAddr) -> crate::Result<Builder<AddrIncoming>> { | ||||
|         AddrIncoming::new(addr) | ||||
|             .map(Server::builder) | ||||
|         AddrIncoming::new(addr).map(Server::builder) | ||||
|     } | ||||
|  | ||||
|     /// Create a new instance from a `std::net::TcpListener` instance. | ||||
|     pub fn from_tcp(listener: StdTcpListener) -> Result<Builder<AddrIncoming>, crate::Error> { | ||||
|         AddrIncoming::from_std(listener) | ||||
|             .map(Server::builder) | ||||
|         AddrIncoming::from_std(listener).map(Server::builder) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -143,10 +144,10 @@ impl<S, E> Server<AddrIncoming, S, E> { | ||||
|  | ||||
| impl<I, IO, IE, S, E, B> Server<I, S, E> | ||||
| where | ||||
|     I: Accept<Conn=IO, Error=IE>, | ||||
|     I: Accept<Conn = IO, Error = IE>, | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     IO: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|     S: MakeServiceRef<IO, Body, ResBody=B>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     B: Payload, | ||||
|     B::Data: Unpin, | ||||
| @@ -191,7 +192,7 @@ where | ||||
|     /// ``` | ||||
|     pub fn with_graceful_shutdown<F>(self, signal: F) -> Graceful<I, S, F, E> | ||||
|     where | ||||
|         F: Future<Output=()> | ||||
|         F: Future<Output = ()>, | ||||
|     { | ||||
|         Graceful::new(self.spawn_all, signal) | ||||
|     } | ||||
| @@ -199,10 +200,10 @@ where | ||||
|  | ||||
| impl<I, IO, IE, S, B, E> Future for Server<I, S, E> | ||||
| where | ||||
|     I: Accept<Conn=IO, Error=IE>, | ||||
|     I: Accept<Conn = IO, Error = IE>, | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     IO: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|     S: MakeServiceRef<IO, Body, ResBody=B>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     B: Payload, | ||||
|     B::Data: Unpin, | ||||
| @@ -231,10 +232,7 @@ impl<I, E> Builder<I, E> { | ||||
|     /// | ||||
|     /// For a more convenient constructor, see [`Server::bind`](Server::bind). | ||||
|     pub fn new(incoming: I, protocol: Http_<E>) -> Self { | ||||
|         Builder { | ||||
|             incoming, | ||||
|             protocol, | ||||
|         } | ||||
|         Builder { incoming, protocol } | ||||
|     } | ||||
|  | ||||
|     /// Sets whether to use keep-alive for HTTP/1 connections. | ||||
| @@ -245,7 +243,6 @@ impl<I, E> Builder<I, E> { | ||||
|         self | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// Set whether HTTP/1 connections should support half-closures. | ||||
|     /// | ||||
|     /// Clients can chose to shutdown their write-side while waiting | ||||
| @@ -319,7 +316,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     pub fn http2_initial_connection_window_size(mut self, sz: impl Into<Option<u32>>) -> Self { | ||||
|         self.protocol.http2_initial_connection_window_size(sz.into()); | ||||
|         self.protocol | ||||
|             .http2_initial_connection_window_size(sz.into()); | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -387,7 +385,7 @@ impl<I, E> Builder<I, E> { | ||||
|         I: Accept, | ||||
|         I::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         I::Conn: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|         S: MakeServiceRef<I::Conn, Body, ResBody=B>, | ||||
|         S: MakeServiceRef<I::Conn, Body, ResBody = B>, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         B: Payload, | ||||
|         B::Data: Unpin, | ||||
| @@ -396,9 +394,7 @@ impl<I, E> Builder<I, E> { | ||||
|     { | ||||
|         let serve = self.protocol.serve(self.incoming, new_service); | ||||
|         let spawn_all = serve.spawn_all(); | ||||
|         Server { | ||||
|             spawn_all, | ||||
|         } | ||||
|         Server { spawn_all } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -440,4 +436,3 @@ impl<E> Builder<AddrIncoming, E> { | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| use std::error::Error as StdError; | ||||
|  | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
| use pin_project::{pin_project, project}; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; | ||||
| use super::Accept; | ||||
| use crate::body::{Body, Payload}; | ||||
| use crate::common::drain::{self, Draining, Signal, Watch, Watching}; | ||||
| use crate::common::exec::{H2Exec, NewSvcExec}; | ||||
| use crate::common::{Future, Pin, Poll, Unpin, task}; | ||||
| use crate::service::{MakeServiceRef, HttpService}; | ||||
| use super::Accept; | ||||
| use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; | ||||
| use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
| use crate::service::{HttpService, MakeServiceRef}; | ||||
|  | ||||
| #[allow(missing_debug_implementations)] | ||||
| #[pin_project] | ||||
| @@ -43,17 +43,16 @@ impl<I, S, F, E> Graceful<I, S, F, E> { | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<I, IO, IE, S, B, F, E> Future for Graceful<I, S, F, E> | ||||
| where | ||||
|     I: Accept<Conn=IO, Error=IE>, | ||||
|     I: Accept<Conn = IO, Error = IE>, | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     IO: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|     S: MakeServiceRef<IO, Body, ResBody=B>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     B: Payload, | ||||
|     B::Data: Unpin, | ||||
|     F: Future<Output=()>, | ||||
|     F: Future<Output = ()>, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: NewSvcExec<IO, S::Future, S::Service, E, GracefulWatcher>, | ||||
| { | ||||
| @@ -73,20 +72,13 @@ where | ||||
|                     } => match signal.poll(cx) { | ||||
|                         Poll::Ready(()) => { | ||||
|                             debug!("signal received, starting graceful shutdown"); | ||||
|                             let sig = drain | ||||
|                                 .take() | ||||
|                                 .expect("drain channel") | ||||
|                                 .0; | ||||
|                             let sig = drain.take().expect("drain channel").0; | ||||
|                             State::Draining(sig.drain()) | ||||
|                         }, | ||||
|                         } | ||||
|                         Poll::Pending => { | ||||
|                             let watch = drain | ||||
|                                 .as_ref() | ||||
|                                 .expect("drain channel") | ||||
|                                 .1 | ||||
|                                 .clone(); | ||||
|                             let watch = drain.as_ref().expect("drain channel").1.clone(); | ||||
|                             return spawn_all.poll_watch(cx, &GracefulWatcher(watch)); | ||||
|                         }, | ||||
|                         } | ||||
|                     }, | ||||
|                     State::Draining(ref mut draining) => { | ||||
|                         return Pin::new(draining).poll(cx).map(Ok); | ||||
| @@ -109,13 +101,11 @@ where | ||||
|     <S::ResBody as Payload>::Data: Unpin, | ||||
|     E: H2Exec<S::Future, S::ResBody>, | ||||
| { | ||||
|     type Future = Watching<UpgradeableConnection<I, S, E>, fn(Pin<&mut UpgradeableConnection<I, S, E>>)>; | ||||
|     type Future = | ||||
|         Watching<UpgradeableConnection<I, S, E>, fn(Pin<&mut UpgradeableConnection<I, S, E>>)>; | ||||
|  | ||||
|     fn watch(&self, conn: UpgradeableConnection<I, S, E>) -> Self::Future { | ||||
|         self | ||||
|             .0 | ||||
|             .clone() | ||||
|             .watch(conn, on_drain) | ||||
|         self.0.clone().watch(conn, on_drain) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -130,4 +120,3 @@ where | ||||
| { | ||||
|     conn.graceful_shutdown() | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -7,10 +7,10 @@ use futures_util::FutureExt as _; | ||||
| use tokio::net::TcpListener; | ||||
| use tokio::time::Delay; | ||||
|  | ||||
| use crate::common::{Future, Pin, Poll, task}; | ||||
| use crate::common::{task, Future, Pin, Poll}; | ||||
|  | ||||
| use super::Accept; | ||||
| pub use self::addr_stream::AddrStream; | ||||
| use super::Accept; | ||||
|  | ||||
| /// A stream of connections from binding to an address. | ||||
| #[must_use = "streams do nothing unless polled"] | ||||
| @@ -25,15 +25,13 @@ pub struct AddrIncoming { | ||||
|  | ||||
| impl AddrIncoming { | ||||
|     pub(super) fn new(addr: &SocketAddr) -> crate::Result<Self> { | ||||
|         let std_listener = StdTcpListener::bind(addr) | ||||
|                 .map_err(crate::Error::new_listen)?; | ||||
|         let std_listener = StdTcpListener::bind(addr).map_err(crate::Error::new_listen)?; | ||||
|  | ||||
|         AddrIncoming::from_std(std_listener) | ||||
|     } | ||||
|  | ||||
|     pub(super) fn from_std(std_listener: StdTcpListener) -> crate::Result<Self> { | ||||
|         let listener = TcpListener::from_std(std_listener) | ||||
|             .map_err(crate::Error::new_listen)?; | ||||
|         let listener = TcpListener::from_std(std_listener).map_err(crate::Error::new_listen)?; | ||||
|         let addr = listener.local_addr().map_err(crate::Error::new_listen)?; | ||||
|         Ok(AddrIncoming { | ||||
|             listener, | ||||
| @@ -115,7 +113,7 @@ impl AddrIncoming { | ||||
|                         trace!("error trying to set TCP nodelay: {}", e); | ||||
|                     } | ||||
|                     return Poll::Ready(Ok(AddrStream::new(socket, addr))); | ||||
|                 }, | ||||
|                 } | ||||
|                 Poll::Pending => return Poll::Pending, | ||||
|                 Poll::Ready(Err(e)) => { | ||||
|                     // Connection errors can be ignored directly, continue by | ||||
| @@ -134,17 +132,17 @@ impl AddrIncoming { | ||||
|                         match Pin::new(&mut timeout).poll(cx) { | ||||
|                             Poll::Ready(()) => { | ||||
|                                 // Wow, it's been a second already? Ok then... | ||||
|                                 continue | ||||
|                             }, | ||||
|                                 continue; | ||||
|                             } | ||||
|                             Poll::Pending => { | ||||
|                                 self.timeout = Some(timeout); | ||||
|                                 return Poll::Pending; | ||||
|                             }, | ||||
|                             } | ||||
|                         } | ||||
|                     } else { | ||||
|                         return Poll::Ready(Err(e)); | ||||
|                     } | ||||
|                 }, | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -154,7 +152,10 @@ impl Accept for AddrIncoming { | ||||
|     type Conn = AddrStream; | ||||
|     type Error = io::Error; | ||||
|  | ||||
|     fn poll_accept(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Result<Self::Conn, Self::Error>>> { | ||||
|     fn poll_accept( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<Result<Self::Conn, Self::Error>>> { | ||||
|         let result = ready!(self.poll_next_(cx)); | ||||
|         Poll::Ready(Some(result)) | ||||
|     } | ||||
| @@ -169,9 +170,9 @@ impl Accept for AddrIncoming { | ||||
| /// and EMFILE. Otherwise, could enter into tight loop. | ||||
| fn is_connection_error(e: &io::Error) -> bool { | ||||
|     match e.kind() { | ||||
|         io::ErrorKind::ConnectionRefused | | ||||
|         io::ErrorKind::ConnectionAborted | | ||||
|         io::ErrorKind::ConnectionReset => true, | ||||
|         io::ErrorKind::ConnectionRefused | ||||
|         | io::ErrorKind::ConnectionAborted | ||||
|         | io::ErrorKind::ConnectionReset => true, | ||||
|         _ => false, | ||||
|     } | ||||
| } | ||||
| @@ -188,14 +189,13 @@ impl fmt::Debug for AddrIncoming { | ||||
| } | ||||
|  | ||||
| mod addr_stream { | ||||
|     use bytes::{Buf, BufMut}; | ||||
|     use std::io; | ||||
|     use std::net::SocketAddr; | ||||
|     use bytes::{Buf, BufMut}; | ||||
|     use tokio::net::TcpStream; | ||||
|     use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|     use tokio::net::TcpStream; | ||||
|  | ||||
|     use crate::common::{Pin, Poll, task}; | ||||
|  | ||||
|     use crate::common::{task, Pin, Poll}; | ||||
|  | ||||
|     /// A transport returned yieled by `AddrIncoming`. | ||||
|     #[derive(Debug)] | ||||
| @@ -226,29 +226,48 @@ mod addr_stream { | ||||
|     } | ||||
|  | ||||
|     impl AsyncRead for AddrStream { | ||||
|         unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [std::mem::MaybeUninit<u8>]) -> bool { | ||||
|         unsafe fn prepare_uninitialized_buffer( | ||||
|             &self, | ||||
|             buf: &mut [std::mem::MaybeUninit<u8>], | ||||
|         ) -> bool { | ||||
|             self.inner.prepare_uninitialized_buffer(buf) | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> { | ||||
|         fn poll_read( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|             buf: &mut [u8], | ||||
|         ) -> Poll<io::Result<usize>> { | ||||
|             Pin::new(&mut self.inner).poll_read(cx, buf) | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn poll_read_buf<B: BufMut>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> { | ||||
|         fn poll_read_buf<B: BufMut>( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|             buf: &mut B, | ||||
|         ) -> Poll<io::Result<usize>> { | ||||
|             Pin::new(&mut self.inner).poll_read_buf(cx, buf) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl AsyncWrite for AddrStream { | ||||
|         #[inline] | ||||
|         fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> { | ||||
|         fn poll_write( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|             buf: &[u8], | ||||
|         ) -> Poll<io::Result<usize>> { | ||||
|             Pin::new(&mut self.inner).poll_write(cx, buf) | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn poll_write_buf<B: Buf>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut B) -> Poll<io::Result<usize>> { | ||||
|         fn poll_write_buf<B: Buf>( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|             buf: &mut B, | ||||
|         ) -> Poll<io::Result<usize>> { | ||||
|             Pin::new(&mut self.inner).poll_write_buf(cx, buf) | ||||
|         } | ||||
|  | ||||
| @@ -259,7 +278,10 @@ mod addr_stream { | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { | ||||
|         fn poll_shutdown( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|         ) -> Poll<io::Result<()>> { | ||||
|             Pin::new(&mut self.inner).poll_shutdown(cx) | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use std::error::Error as StdError; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use crate::common::{task, Future, Poll}; | ||||
| use crate::{Request, Response}; | ||||
|  | ||||
| /// An asynchronous function from `Request` to `Response`. | ||||
| @@ -17,7 +17,7 @@ pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> { | ||||
|     type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|  | ||||
|     /// The `Future` returned by this `Service`. | ||||
|     type Future: Future<Output=Result<Response<Self::ResBody>, Self::Error>>; | ||||
|     type Future: Future<Output = Result<Response<Self::ResBody>, Self::Error>>; | ||||
|  | ||||
|     #[doc(hidden)] | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>; | ||||
| @@ -27,7 +27,7 @@ pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> { | ||||
| } | ||||
|  | ||||
| impl<T, B1, B2> HttpService<B1> for T | ||||
| where  | ||||
| where | ||||
|     T: tower_service::Service<Request<B1>, Response = Response<B2>>, | ||||
|     B2: Payload, | ||||
|     T::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
| @@ -46,13 +46,13 @@ where | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B1, B2> sealed::Sealed<B1> for T  | ||||
| where  | ||||
| impl<T, B1, B2> sealed::Sealed<B1> for T | ||||
| where | ||||
|     T: tower_service::Service<Request<B1>, Response = Response<B2>>, | ||||
|     B2: Payload, | ||||
| {} | ||||
| { | ||||
| } | ||||
|  | ||||
| mod sealed { | ||||
|     pub trait Sealed<T> {} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,9 +3,9 @@ use std::fmt; | ||||
|  | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use super::{HttpService, Service}; | ||||
| use crate::body::Payload; | ||||
| use crate::common::{task, Future, Poll}; | ||||
|  | ||||
| // The same "trait alias" as tower::MakeConnection, but inlined to reduce | ||||
| // dependencies. | ||||
| @@ -44,13 +44,9 @@ where | ||||
| pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<(Target, ReqBody)> { | ||||
|     type ResBody: Payload; | ||||
|     type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|     type Service: HttpService< | ||||
|         ReqBody, | ||||
|         ResBody=Self::ResBody, | ||||
|         Error=Self::Error, | ||||
|     >; | ||||
|     type Service: HttpService<ReqBody, ResBody = Self::ResBody, Error = Self::Error>; | ||||
|     type MakeError: Into<Box<dyn StdError + Send + Sync>>; | ||||
|     type Future: Future<Output=Result<Self::Service, Self::MakeError>>; | ||||
|     type Future: Future<Output = Result<Self::Service, Self::MakeError>>; | ||||
|  | ||||
|     // Acting like a #[non_exhaustive] for associated types of this trait. | ||||
|     // | ||||
| @@ -70,11 +66,11 @@ pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<(Target, ReqBody | ||||
|  | ||||
| impl<T, Target, E, ME, S, F, IB, OB> MakeServiceRef<Target, IB> for T | ||||
| where | ||||
|     T: for<'a> Service<&'a Target, Error=ME, Response=S, Future=F>, | ||||
|     T: for<'a> Service<&'a Target, Error = ME, Response = S, Future = F>, | ||||
|     E: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     ME: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     S: HttpService<IB, ResBody=OB, Error=E>, | ||||
|     F: Future<Output=Result<S, ME>>, | ||||
|     S: HttpService<IB, ResBody = OB, Error = E>, | ||||
|     F: Future<Output = Result<S, ME>>, | ||||
|     IB: Payload, | ||||
|     OB: Payload, | ||||
| { | ||||
| @@ -145,9 +141,7 @@ where | ||||
|     F: FnMut(&Target) -> Ret, | ||||
|     Ret: Future, | ||||
| { | ||||
|     MakeServiceFn { | ||||
|         f, | ||||
|     } | ||||
|     MakeServiceFn { f } | ||||
| } | ||||
|  | ||||
| // Not exported from crate as this will likely be replaced with `impl Service`. | ||||
| @@ -158,7 +152,7 @@ pub struct MakeServiceFn<F> { | ||||
| impl<'t, F, Ret, Target, Svc, MkErr> Service<&'t Target> for MakeServiceFn<F> | ||||
| where | ||||
|     F: FnMut(&Target) -> Ret, | ||||
|     Ret: Future<Output=Result<Svc, MkErr>>, | ||||
|     Ret: Future<Output = Result<Svc, MkErr>>, | ||||
|     MkErr: Into<Box<dyn StdError + Send + Sync>>, | ||||
| { | ||||
|     type Error = MkErr; | ||||
| @@ -176,8 +170,7 @@ where | ||||
|  | ||||
| impl<F> fmt::Debug for MakeServiceFn<F> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("MakeServiceFn") | ||||
|             .finish() | ||||
|         f.debug_struct("MakeServiceFn").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -41,10 +41,9 @@ mod make; | ||||
| mod oneshot; | ||||
| mod util; | ||||
|  | ||||
| pub(crate) use self::make::{MakeConnection, MakeServiceRef}; | ||||
| pub(crate) use self::http::HttpService; | ||||
| pub(crate) use self::make::{MakeConnection, MakeServiceRef}; | ||||
| pub(crate) use self::oneshot::{oneshot, Oneshot}; | ||||
|  | ||||
| pub use self::make::make_service_fn; | ||||
| pub use self::util::service_fn; | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // TODO: Eventually to be replaced with tower_util::Oneshot. | ||||
|  | ||||
| use std::mem; | ||||
| use std::marker::Unpin; | ||||
| use std::mem; | ||||
|  | ||||
| use tower_service::Service; | ||||
|  | ||||
| use crate::common::{Future, Pin, Poll, task}; | ||||
| use crate::common::{task, Future, Pin, Poll}; | ||||
|  | ||||
| pub(crate) fn oneshot<S, Req>(svc: S, req: Req) -> Oneshot<S, Req> | ||||
| where | ||||
| @@ -35,7 +35,8 @@ impl<S, Req> Unpin for Oneshot<S, Req> | ||||
| where | ||||
|     S: Service<Req>, | ||||
|     S::Future: Unpin, | ||||
| {} | ||||
| { | ||||
| } | ||||
|  | ||||
| impl<S, Req> Future for Oneshot<S, Req> | ||||
| where | ||||
| @@ -52,17 +53,17 @@ where | ||||
|                 State::NotReady(ref mut svc, _) => { | ||||
|                     ready!(svc.poll_ready(cx))?; | ||||
|                     // fallthrough out of the match's borrow | ||||
|                 }, | ||||
|                 } | ||||
|                 State::Called(ref mut fut) => { | ||||
|                     return unsafe { Pin::new_unchecked(fut) }.poll(cx); | ||||
|                 }, | ||||
|                 } | ||||
|                 State::Tmp => unreachable!(), | ||||
|             } | ||||
|  | ||||
|             match mem::replace(&mut me.state, State::Tmp) { | ||||
|                 State::NotReady(mut svc, req) => { | ||||
|                     me.state = State::Called(svc.call(req)); | ||||
|                 }, | ||||
|                 } | ||||
|                 _ => unreachable!(), | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use std::fmt; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use crate::common::{task, Future, Poll}; | ||||
| use crate::{Request, Response}; | ||||
|  | ||||
| /// Create a `Service` from a function. | ||||
| @@ -41,11 +41,12 @@ pub struct ServiceFn<F, R> { | ||||
|     _req: PhantomData<fn(R)>, | ||||
| } | ||||
|  | ||||
| impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>> for ServiceFn<F, ReqBody> | ||||
| impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>> | ||||
|     for ServiceFn<F, ReqBody> | ||||
| where | ||||
|     F: FnMut(Request<ReqBody>) -> Ret, | ||||
|     ReqBody: Payload, | ||||
|     Ret: Future<Output=Result<Response<ResBody>, E>>, | ||||
|     Ret: Future<Output = Result<Response<ResBody>, E>>, | ||||
|     E: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     ResBody: Payload, | ||||
| { | ||||
| @@ -64,7 +65,6 @@ where | ||||
|  | ||||
| impl<F, R> fmt::Debug for ServiceFn<F, R> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("impl Service") | ||||
|             .finish() | ||||
|         f.debug_struct("impl Service").finish() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,12 +11,12 @@ use std::fmt; | ||||
| use std::io; | ||||
| use std::marker::Unpin; | ||||
|  | ||||
| use bytes::{/*Buf, BufMut, */Bytes}; | ||||
| use bytes::Bytes; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
| use tokio::sync::oneshot; | ||||
|  | ||||
| use crate::common::io::Rewind; | ||||
| use crate::common::{Future, Pin, Poll, task}; | ||||
| use crate::common::{task, Future, Pin, Poll}; | ||||
|  | ||||
| /// An upgraded HTTP connection. | ||||
| /// | ||||
| @@ -58,7 +58,7 @@ pub struct Parts<T> { | ||||
| } | ||||
|  | ||||
| pub(crate) struct Pending { | ||||
|     tx: oneshot::Sender<crate::Result<Upgraded>> | ||||
|     tx: oneshot::Sender<crate::Result<Upgraded>>, | ||||
| } | ||||
|  | ||||
| /// Error cause returned when an upgrade was expected but canceled | ||||
| @@ -70,14 +70,7 @@ struct UpgradeExpected(()); | ||||
|  | ||||
| pub(crate) fn pending() -> (Pending, OnUpgrade) { | ||||
|     let (tx, rx) = oneshot::channel(); | ||||
|     ( | ||||
|         Pending { | ||||
|             tx, | ||||
|         }, | ||||
|         OnUpgrade { | ||||
|             rx: Some(rx), | ||||
|         }, | ||||
|     ) | ||||
|     (Pending { tx }, OnUpgrade { rx: Some(rx) }) | ||||
| } | ||||
|  | ||||
| pub(crate) trait Io: AsyncRead + AsyncWrite + Unpin + 'static { | ||||
| @@ -130,7 +123,7 @@ impl Upgraded { | ||||
|             }), | ||||
|             Err(io) => Err(Upgraded { | ||||
|                 io: Rewind::new_buffered(io, buf), | ||||
|             }) | ||||
|             }), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -140,13 +133,21 @@ impl AsyncRead for Upgraded { | ||||
|         self.io.prepare_uninitialized_buffer(buf) | ||||
|     } | ||||
|  | ||||
|     fn poll_read(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> { | ||||
|     fn poll_read( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|         buf: &mut [u8], | ||||
|     ) -> Poll<io::Result<usize>> { | ||||
|         Pin::new(&mut self.io).poll_read(cx, buf) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl AsyncWrite for Upgraded { | ||||
|     fn poll_write(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> { | ||||
|     fn poll_write( | ||||
|         mut self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|         buf: &[u8], | ||||
|     ) -> Poll<io::Result<usize>> { | ||||
|         Pin::new(&mut self.io).poll_write(cx, buf) | ||||
|     } | ||||
|  | ||||
| @@ -161,8 +162,7 @@ impl AsyncWrite for Upgraded { | ||||
|  | ||||
| impl fmt::Debug for Upgraded { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Upgraded") | ||||
|             .finish() | ||||
|         f.debug_struct("Upgraded").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -170,9 +170,7 @@ impl fmt::Debug for Upgraded { | ||||
|  | ||||
| impl OnUpgrade { | ||||
|     pub(crate) fn none() -> Self { | ||||
|         OnUpgrade { | ||||
|             rx: None, | ||||
|         } | ||||
|         OnUpgrade { rx: None } | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn is_none(&self) -> bool { | ||||
| @@ -188,9 +186,9 @@ impl Future for OnUpgrade { | ||||
|             Some(ref mut rx) => Pin::new(rx).poll(cx).map(|res| match res { | ||||
|                 Ok(Ok(upgraded)) => Ok(upgraded), | ||||
|                 Ok(Err(err)) => Err(err), | ||||
|                 Err(_oneshot_canceled) => Err( | ||||
|                     crate::Error::new_canceled().with(UpgradeExpected(())) | ||||
|                 ), | ||||
|                 Err(_oneshot_canceled) => { | ||||
|                     Err(crate::Error::new_canceled().with(UpgradeExpected(()))) | ||||
|                 } | ||||
|             }), | ||||
|             None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())), | ||||
|         } | ||||
| @@ -199,8 +197,7 @@ impl Future for OnUpgrade { | ||||
|  | ||||
| impl fmt::Debug for OnUpgrade { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("OnUpgrade") | ||||
|             .finish() | ||||
|         f.debug_struct("OnUpgrade").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -233,4 +230,3 @@ impl StdError for UpgradeExpected { | ||||
|         "upgrade expected but not completed" | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user