feat(client): Make client an optional feature
				
					
				
			cc #2223 BREAKING CHANGE: The HTTP client of hyper is now an optional feature. To enable the client, add `features = ["client"]` to the dependency in your `Cargo.toml`.
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| use std::fmt; | ||||
| use std::io::{self}; | ||||
| use std::io; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| use bytes::{Buf, Bytes}; | ||||
| @@ -65,6 +65,7 @@ where | ||||
|         self.io.set_max_buf_size(max); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "client")] | ||||
|     pub fn set_read_buf_exact_size(&mut self, sz: usize) { | ||||
|         self.io.set_read_buf_exact_size(sz); | ||||
|     } | ||||
| @@ -77,6 +78,7 @@ where | ||||
|         self.io.set_write_strategy_queue(); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "client")] | ||||
|     pub fn set_title_case_headers(&mut self) { | ||||
|         self.state.title_case_headers = true; | ||||
|     } | ||||
|   | ||||
| @@ -1,15 +1,14 @@ | ||||
| use std::error::Error as StdError; | ||||
|  | ||||
| use bytes::{Buf, Bytes}; | ||||
| use http::{Request, Response, StatusCode}; | ||||
| use http::{Request, StatusCode}; | ||||
| use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use super::{Http1Transaction, Wants}; | ||||
| use crate::body::{Body, DecodedLength, HttpBody}; | ||||
| use crate::common::{task, Future, Never, Pin, Poll, Unpin}; | ||||
| use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
| use crate::proto::{ | ||||
|     BodyLength, Conn, Dispatched, MessageHead, RequestHead, RequestLine, | ||||
|     ResponseHead, | ||||
|     BodyLength, Conn, Dispatched, MessageHead, RequestHead, | ||||
| }; | ||||
| use crate::service::HttpService; | ||||
|  | ||||
| @@ -40,15 +39,17 @@ pub struct Server<S: HttpService<B>, B> { | ||||
|     pub(crate) service: S, | ||||
| } | ||||
|  | ||||
| #[pin_project::pin_project] | ||||
| pub struct Client<B> { | ||||
|     callback: Option<crate::client::dispatch::Callback<Request<B>, Response<Body>>>, | ||||
|     #[pin] | ||||
|     rx: ClientRx<B>, | ||||
|     rx_closed: bool, | ||||
| } | ||||
| cfg_client! { | ||||
|     #[pin_project::pin_project] | ||||
|     pub struct Client<B> { | ||||
|         callback: Option<crate::client::dispatch::Callback<Request<B>, http::Response<Body>>>, | ||||
|         #[pin] | ||||
|         rx: ClientRx<B>, | ||||
|         rx_closed: bool, | ||||
|     } | ||||
|  | ||||
| type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<Body>>; | ||||
|     type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, http::Response<Body>>; | ||||
| } | ||||
|  | ||||
| impl<D, Bs, I, T> Dispatcher<D, Bs, I, T> | ||||
| where | ||||
| @@ -523,115 +524,117 @@ where | ||||
|  | ||||
| // ===== impl Client ===== | ||||
|  | ||||
| impl<B> Client<B> { | ||||
|     pub fn new(rx: ClientRx<B>) -> Client<B> { | ||||
|         Client { | ||||
|             callback: None, | ||||
|             rx, | ||||
|             rx_closed: false, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Dispatch for Client<B> | ||||
| where | ||||
|     B: HttpBody, | ||||
| { | ||||
|     type PollItem = RequestHead; | ||||
|     type PollBody = B; | ||||
|     type PollError = Never; | ||||
|     type RecvItem = ResponseHead; | ||||
|  | ||||
|     fn poll_msg( | ||||
|         self: Pin<&mut Self>, | ||||
|         cx: &mut task::Context<'_>, | ||||
|     ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Never>>> { | ||||
|         let this = self.project(); | ||||
|         debug_assert!(!*this.rx_closed); | ||||
|         match this.rx.poll_next(cx) { | ||||
|             Poll::Ready(Some((req, mut cb))) => { | ||||
|                 // check that future hasn't been canceled already | ||||
|                 match cb.poll_canceled(cx) { | ||||
|                     Poll::Ready(()) => { | ||||
|                         trace!("request canceled"); | ||||
|                         Poll::Ready(None) | ||||
|                     } | ||||
|                     Poll::Pending => { | ||||
|                         let (parts, body) = req.into_parts(); | ||||
|                         let head = RequestHead { | ||||
|                             version: parts.version, | ||||
|                             subject: RequestLine(parts.method, parts.uri), | ||||
|                             headers: parts.headers, | ||||
|                         }; | ||||
|                         *this.callback = Some(cb); | ||||
|                         Poll::Ready(Some(Ok((head, body)))) | ||||
|                     } | ||||
|                 } | ||||
| cfg_client! { | ||||
|     impl<B> Client<B> { | ||||
|         pub fn new(rx: ClientRx<B>) -> Client<B> { | ||||
|             Client { | ||||
|                 callback: None, | ||||
|                 rx, | ||||
|                 rx_closed: false, | ||||
|             } | ||||
|             Poll::Ready(None) => { | ||||
|                 // user has dropped sender handle | ||||
|                 trace!("client tx closed"); | ||||
|                 *this.rx_closed = true; | ||||
|                 Poll::Ready(None) | ||||
|             } | ||||
|             Poll::Pending => Poll::Pending, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()> { | ||||
|         match msg { | ||||
|             Ok((msg, body)) => { | ||||
|                 if let Some(cb) = self.callback.take() { | ||||
|                     let mut res = Response::new(body); | ||||
|                     *res.status_mut() = msg.subject; | ||||
|                     *res.headers_mut() = msg.headers; | ||||
|                     *res.version_mut() = msg.version; | ||||
|                     cb.send(Ok(res)); | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     // Getting here is likely a bug! An error should have happened | ||||
|                     // in Conn::require_empty_read() before ever parsing a | ||||
|                     // full message! | ||||
|                     Err(crate::Error::new_unexpected_message()) | ||||
|     impl<B> Dispatch for Client<B> | ||||
|     where | ||||
|         B: HttpBody, | ||||
|     { | ||||
|         type PollItem = RequestHead; | ||||
|         type PollBody = B; | ||||
|         type PollError = crate::common::Never; | ||||
|         type RecvItem = crate::proto::ResponseHead; | ||||
|  | ||||
|         fn poll_msg( | ||||
|             self: Pin<&mut Self>, | ||||
|             cx: &mut task::Context<'_>, | ||||
|         ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), crate::common::Never>>> { | ||||
|             let this = self.project(); | ||||
|             debug_assert!(!*this.rx_closed); | ||||
|             match this.rx.poll_next(cx) { | ||||
|                 Poll::Ready(Some((req, mut cb))) => { | ||||
|                     // check that future hasn't been canceled already | ||||
|                     match cb.poll_canceled(cx) { | ||||
|                         Poll::Ready(()) => { | ||||
|                             trace!("request canceled"); | ||||
|                             Poll::Ready(None) | ||||
|                         } | ||||
|                         Poll::Pending => { | ||||
|                             let (parts, body) = req.into_parts(); | ||||
|                             let head = RequestHead { | ||||
|                                 version: parts.version, | ||||
|                                 subject: crate::proto::RequestLine(parts.method, parts.uri), | ||||
|                                 headers: parts.headers, | ||||
|                             }; | ||||
|                             *this.callback = Some(cb); | ||||
|                             Poll::Ready(Some(Ok((head, body)))) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Poll::Ready(None) => { | ||||
|                     // user has dropped sender handle | ||||
|                     trace!("client tx closed"); | ||||
|                     *this.rx_closed = true; | ||||
|                     Poll::Ready(None) | ||||
|                 } | ||||
|                 Poll::Pending => Poll::Pending, | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 if let Some(cb) = self.callback.take() { | ||||
|                     cb.send(Err((err, None))); | ||||
|                     Ok(()) | ||||
|                 } else if !self.rx_closed { | ||||
|                     self.rx.close(); | ||||
|                     if let Some((req, cb)) = self.rx.try_recv() { | ||||
|                         trace!("canceling queued request with connection error: {}", err); | ||||
|                         // in this case, the message was never even started, so it's safe to tell | ||||
|                         // the user that the request was completely canceled | ||||
|                         cb.send(Err((crate::Error::new_canceled().with(err), Some(req)))); | ||||
|         } | ||||
|  | ||||
|         fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, Body)>) -> crate::Result<()> { | ||||
|             match msg { | ||||
|                 Ok((msg, body)) => { | ||||
|                     if let Some(cb) = self.callback.take() { | ||||
|                         let mut res = http::Response::new(body); | ||||
|                         *res.status_mut() = msg.subject; | ||||
|                         *res.headers_mut() = msg.headers; | ||||
|                         *res.version_mut() = msg.version; | ||||
|                         cb.send(Ok(res)); | ||||
|                         Ok(()) | ||||
|                     } else { | ||||
|                         // Getting here is likely a bug! An error should have happened | ||||
|                         // in Conn::require_empty_read() before ever parsing a | ||||
|                         // full message! | ||||
|                         Err(crate::Error::new_unexpected_message()) | ||||
|                     } | ||||
|                 } | ||||
|                 Err(err) => { | ||||
|                     if let Some(cb) = self.callback.take() { | ||||
|                         cb.send(Err((err, None))); | ||||
|                         Ok(()) | ||||
|                     } else if !self.rx_closed { | ||||
|                         self.rx.close(); | ||||
|                         if let Some((req, cb)) = self.rx.try_recv() { | ||||
|                             trace!("canceling queued request with connection error: {}", err); | ||||
|                             // in this case, the message was never even started, so it's safe to tell | ||||
|                             // the user that the request was completely canceled | ||||
|                             cb.send(Err((crate::Error::new_canceled().with(err), Some(req)))); | ||||
|                             Ok(()) | ||||
|                         } else { | ||||
|                             Err(err) | ||||
|                         } | ||||
|                     } else { | ||||
|                         Err(err) | ||||
|                     } | ||||
|                 } else { | ||||
|                     Err(err) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> { | ||||
|         match self.callback { | ||||
|             Some(ref mut cb) => match cb.poll_canceled(cx) { | ||||
|                 Poll::Ready(()) => { | ||||
|                     trace!("callback receiver has dropped"); | ||||
|                     Poll::Ready(Err(())) | ||||
|                 } | ||||
|                 Poll::Pending => Poll::Ready(Ok(())), | ||||
|             }, | ||||
|             None => Poll::Ready(Err(())), | ||||
|         fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> { | ||||
|             match self.callback { | ||||
|                 Some(ref mut cb) => match cb.poll_canceled(cx) { | ||||
|                     Poll::Ready(()) => { | ||||
|                         trace!("callback receiver has dropped"); | ||||
|                         Poll::Ready(Err(())) | ||||
|                     } | ||||
|                     Poll::Pending => Poll::Ready(Ok(())), | ||||
|                 }, | ||||
|                 None => Poll::Ready(Err(())), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn should_poll(&self) -> bool { | ||||
|         self.callback.is_none() | ||||
|         fn should_poll(&self) -> bool { | ||||
|             self.callback.is_none() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -84,6 +84,7 @@ where | ||||
|         self.write_buf.max_buf_size = max; | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "client")] | ||||
|     pub fn set_read_buf_exact_size(&mut self, sz: usize) { | ||||
|         self.read_buf_strategy = ReadStrategy::Exact(sz); | ||||
|     } | ||||
| @@ -317,6 +318,7 @@ enum ReadStrategy { | ||||
|         next: usize, | ||||
|         max: usize, | ||||
|     }, | ||||
|     #[cfg(feature = "client")] | ||||
|     Exact(usize), | ||||
| } | ||||
|  | ||||
| @@ -332,6 +334,7 @@ impl ReadStrategy { | ||||
|     fn next(&self) -> usize { | ||||
|         match *self { | ||||
|             ReadStrategy::Adaptive { next, .. } => next, | ||||
|             #[cfg(feature = "client")] | ||||
|             ReadStrategy::Exact(exact) => exact, | ||||
|         } | ||||
|     } | ||||
| @@ -339,38 +342,42 @@ impl ReadStrategy { | ||||
|     fn max(&self) -> usize { | ||||
|         match *self { | ||||
|             ReadStrategy::Adaptive { max, .. } => max, | ||||
|             #[cfg(feature = "client")] | ||||
|             ReadStrategy::Exact(exact) => exact, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn record(&mut self, bytes_read: usize) { | ||||
|         if let ReadStrategy::Adaptive { | ||||
|             ref mut decrease_now, | ||||
|             ref mut next, | ||||
|             max, | ||||
|             .. | ||||
|         } = *self | ||||
|         { | ||||
|             if bytes_read >= *next { | ||||
|                 *next = cmp::min(incr_power_of_two(*next), max); | ||||
|                 *decrease_now = false; | ||||
|             } else { | ||||
|                 let decr_to = prev_power_of_two(*next); | ||||
|                 if bytes_read < decr_to { | ||||
|                     if *decrease_now { | ||||
|                         *next = cmp::max(decr_to, INIT_BUFFER_SIZE); | ||||
|                         *decrease_now = false; | ||||
|                     } else { | ||||
|                         // Decreasing is a two "record" process. | ||||
|                         *decrease_now = true; | ||||
|                     } | ||||
|                 } else { | ||||
|                     // A read within the current range should cancel | ||||
|                     // a potential decrease, since we just saw proof | ||||
|                     // that we still need this size. | ||||
|         match *self { | ||||
|             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; | ||||
|                 } else { | ||||
|                     let decr_to = prev_power_of_two(*next); | ||||
|                     if bytes_read < decr_to { | ||||
|                         if *decrease_now { | ||||
|                             *next = cmp::max(decr_to, INIT_BUFFER_SIZE); | ||||
|                             *decrease_now = false; | ||||
|                         } else { | ||||
|                             // Decreasing is a two "record" process. | ||||
|                             *decrease_now = true; | ||||
|                         } | ||||
|                     } else { | ||||
|                         // A read within the current range should cancel | ||||
|                         // a potential decrease, since we just saw proof | ||||
|                         // that we still need this size. | ||||
|                         *decrease_now = false; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             }, | ||||
|             #[cfg(feature = "client")] | ||||
|             ReadStrategy::Exact(_) => (), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,10 @@ mod io; | ||||
| mod role; | ||||
|  | ||||
| pub(crate) type ServerTransaction = role::Server; | ||||
| pub(crate) type ClientTransaction = role::Client; | ||||
|  | ||||
| cfg_client! { | ||||
|     pub(crate) type ClientTransaction = role::Client; | ||||
| } | ||||
|  | ||||
| pub(crate) trait Http1Transaction { | ||||
|     type Incoming; | ||||
|   | ||||
| @@ -10,7 +10,7 @@ use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use super::{decode_content_length, ping, PipeToSendStream, SendBuf}; | ||||
| use crate::body::HttpBody; | ||||
| use crate::common::{task, Exec, Future, Never, Pin, Poll}; | ||||
| use crate::common::{task, exec::Exec, Future, Never, Pin, Poll}; | ||||
| use crate::headers; | ||||
| use crate::proto::Dispatched; | ||||
| use crate::{Body, Request, Response}; | ||||
|   | ||||
| @@ -13,11 +13,14 @@ use crate::body::{DecodedLength, HttpBody}; | ||||
| use crate::common::{task, Future, Pin, Poll}; | ||||
| use crate::headers::content_length_parse_all; | ||||
|  | ||||
| pub(crate) mod client; | ||||
| pub(crate) mod ping; | ||||
| pub(crate) mod server; | ||||
|  | ||||
| pub(crate) use self::client::ClientTask; | ||||
| cfg_client! { | ||||
|     pub(crate) mod client; | ||||
|     pub(crate) use self::client::ClientTask; | ||||
| } | ||||
|  | ||||
| pub(crate) use self::server::Server; | ||||
|  | ||||
| /// Default initial stream window size defined in HTTP2 spec. | ||||
|   | ||||
| @@ -236,6 +236,7 @@ impl Recorder { | ||||
|  | ||||
|     /// If the incoming stream is already closed, convert self into | ||||
|     /// a disabled reporter. | ||||
|     #[cfg(feature = "client")] | ||||
|     pub(super) fn for_stream(self, stream: &h2::RecvStream) -> Self { | ||||
|         if stream.is_end_stream() { | ||||
|             disabled() | ||||
|   | ||||
| @@ -3,7 +3,10 @@ | ||||
| cfg_http1! { | ||||
|     pub(crate) mod h1; | ||||
|  | ||||
|     pub(crate) use self::h1::{dispatch, Conn, ServerTransaction}; | ||||
|     pub(crate) use self::h1::{Conn, ServerTransaction}; | ||||
|  | ||||
|     #[cfg(feature = "client")] | ||||
|     pub(crate) use self::h1::dispatch; | ||||
| } | ||||
|  | ||||
| cfg_http2! { | ||||
| @@ -31,6 +34,7 @@ pub struct RequestLine(pub http::Method, pub http::Uri); | ||||
|  | ||||
| /// An incoming response message. | ||||
| #[cfg(feature = "http1")] | ||||
| #[cfg(feature = "client")] | ||||
| pub type ResponseHead = MessageHead<http::StatusCode>; | ||||
|  | ||||
| #[derive(Debug)] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user