feat(http2): Make HTTP/2 support an optional feature
cc #2251 BREAKING CHANGE: This puts all HTTP/2 methods and support behind an `http2` cargo feature, which will not be enabled by default. To use HTTP/2, add `features = ["http2"]` to the hyper dependency in your `Cargo.toml`.
This commit is contained in:
		| @@ -13,6 +13,7 @@ use std::fmt; | ||||
| use std::mem; | ||||
| use std::sync::Arc; | ||||
| #[cfg(feature = "runtime")] | ||||
| #[cfg(feature = "http2")] | ||||
| use std::time::Duration; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| @@ -36,6 +37,7 @@ where | ||||
|     B: HttpBody, | ||||
| { | ||||
|     H1(#[pin] Http1Dispatcher<T, B, proto::h1::ClientTransaction>), | ||||
|     #[cfg(feature = "http2")] | ||||
|     H2(#[pin] proto::h2::ClientTask<B>), | ||||
| } | ||||
|  | ||||
| @@ -79,8 +81,16 @@ pub struct Builder { | ||||
|     h1_title_case_headers: bool, | ||||
|     h1_read_buf_exact_size: Option<usize>, | ||||
|     h1_max_buf_size: Option<usize>, | ||||
|     http2: bool, | ||||
|     #[cfg(feature = "http2")] | ||||
|     h2_builder: proto::h2::client::Config, | ||||
|     version: Proto, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Debug)] | ||||
| enum Proto { | ||||
|     Http1, | ||||
|     #[cfg(feature = "http2")] | ||||
|     Http2, | ||||
| } | ||||
|  | ||||
| /// A future returned by `SendRequest::send_request`. | ||||
| @@ -122,6 +132,7 @@ pub struct Parts<T> { | ||||
| // A `SendRequest` that can be cloned to send HTTP2 requests. | ||||
| // private for now, probably not a great idea of a type... | ||||
| #[must_use = "futures do nothing unless polled"] | ||||
| #[cfg(feature = "http2")] | ||||
| pub(super) struct Http2SendRequest<B> { | ||||
|     dispatch: dispatch::UnboundedSender<Request<B>, Response<Body>>, | ||||
| } | ||||
| @@ -152,6 +163,7 @@ impl<B> SendRequest<B> { | ||||
|         self.dispatch.is_closed() | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "http2")] | ||||
|     pub(super) fn into_http2(self) -> Http2SendRequest<B> { | ||||
|         Http2SendRequest { | ||||
|             dispatch: self.dispatch.unbound(), | ||||
| @@ -269,6 +281,7 @@ impl<B> fmt::Debug for SendRequest<B> { | ||||
|  | ||||
| // ===== impl Http2SendRequest | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<B> Http2SendRequest<B> { | ||||
|     pub(super) fn is_ready(&self) -> bool { | ||||
|         self.dispatch.is_ready() | ||||
| @@ -279,6 +292,7 @@ impl<B> Http2SendRequest<B> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<B> Http2SendRequest<B> | ||||
| where | ||||
|     B: HttpBody + 'static, | ||||
| @@ -310,12 +324,14 @@ where | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<B> fmt::Debug for Http2SendRequest<B> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("Http2SendRequest").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<B> Clone for Http2SendRequest<B> { | ||||
|     fn clone(&self) -> Self { | ||||
|         Http2SendRequest { | ||||
| @@ -339,6 +355,7 @@ where | ||||
|     pub fn into_parts(self) -> Parts<T> { | ||||
|         let (io, read_buf, _) = match self.inner.expect("already upgraded") { | ||||
|             ProtoClient::H1(h1) => h1.into_inner(), | ||||
|             #[cfg(feature = "http2")] | ||||
|             ProtoClient::H2(_h2) => { | ||||
|                 panic!("http2 cannot into_inner"); | ||||
|             } | ||||
| @@ -365,6 +382,7 @@ where | ||||
|     pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||
|         match *self.inner.as_mut().expect("already upgraded") { | ||||
|             ProtoClient::H1(ref mut h1) => h1.poll_without_shutdown(cx), | ||||
|             #[cfg(feature = "http2")] | ||||
|             ProtoClient::H2(ref mut h2) => Pin::new(h2).poll(cx).map_ok(|_| ()), | ||||
|         } | ||||
|     } | ||||
| @@ -428,8 +446,9 @@ impl Builder { | ||||
|             h1_read_buf_exact_size: None, | ||||
|             h1_title_case_headers: false, | ||||
|             h1_max_buf_size: None, | ||||
|             http2: false, | ||||
|             #[cfg(feature = "http2")] | ||||
|             h2_builder: Default::default(), | ||||
|             version: Proto::Http1, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -472,8 +491,10 @@ impl Builder { | ||||
|     /// Sets whether HTTP2 is required. | ||||
|     /// | ||||
|     /// Default is false. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_only(&mut self, enabled: bool) -> &mut Builder { | ||||
|         self.http2 = enabled; | ||||
|         self.version = if enabled { Proto::Http2 } else { Proto::Http1 }; | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -485,6 +506,8 @@ impl Builder { | ||||
|     /// If not set, hyper will use a default. | ||||
|     /// | ||||
|     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|         if let Some(sz) = sz.into() { | ||||
|             self.h2_builder.adaptive_window = false; | ||||
| @@ -498,6 +521,8 @@ impl Builder { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_initial_connection_window_size( | ||||
|         &mut self, | ||||
|         sz: impl Into<Option<u32>>, | ||||
| @@ -514,6 +539,8 @@ impl Builder { | ||||
|     /// Enabling this will override the limits set in | ||||
|     /// `http2_initial_stream_window_size` and | ||||
|     /// `http2_initial_connection_window_size`. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self { | ||||
|         use proto::h2::SPEC_WINDOW_SIZE; | ||||
|  | ||||
| @@ -530,6 +557,8 @@ impl Builder { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_max_frame_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|         if let Some(sz) = sz.into() { | ||||
|             self.h2_builder.max_frame_size = sz; | ||||
| @@ -548,6 +577,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// Requires the `runtime` cargo feature to be enabled. | ||||
|     #[cfg(feature = "runtime")] | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_keep_alive_interval( | ||||
|         &mut self, | ||||
|         interval: impl Into<Option<Duration>>, | ||||
| @@ -567,6 +598,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// Requires the `runtime` cargo feature to be enabled. | ||||
|     #[cfg(feature = "runtime")] | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self { | ||||
|         self.h2_builder.keep_alive_timeout = timeout; | ||||
|         self | ||||
| @@ -585,6 +618,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// Requires the `runtime` cargo feature to be enabled. | ||||
|     #[cfg(feature = "runtime")] | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self { | ||||
|         self.h2_builder.keep_alive_while_idle = enabled; | ||||
|         self | ||||
| @@ -604,34 +639,39 @@ impl Builder { | ||||
|         let opts = self.clone(); | ||||
|  | ||||
|         async move { | ||||
|             trace!("client handshake HTTP/{}", if opts.http2 { 2 } else { 1 }); | ||||
|             trace!("client handshake {:?}", opts.version); | ||||
|  | ||||
|             let (tx, rx) = dispatch::channel(); | ||||
|             let proto = if !opts.http2 { | ||||
|                 let mut conn = proto::Conn::new(io); | ||||
|                 if let Some(writev) = opts.h1_writev { | ||||
|                     if writev { | ||||
|                         conn.set_write_strategy_queue(); | ||||
|                     } else { | ||||
|                         conn.set_write_strategy_flatten(); | ||||
|             let proto = match opts.version { | ||||
|                 Proto::Http1 => { | ||||
|                     let mut conn = proto::Conn::new(io); | ||||
|                     if let Some(writev) = opts.h1_writev { | ||||
|                         if writev { | ||||
|                             conn.set_write_strategy_queue(); | ||||
|                         } else { | ||||
|                             conn.set_write_strategy_flatten(); | ||||
|                         } | ||||
|                     } | ||||
|                     if opts.h1_title_case_headers { | ||||
|                         conn.set_title_case_headers(); | ||||
|                     } | ||||
|                     if let Some(sz) = opts.h1_read_buf_exact_size { | ||||
|                         conn.set_read_buf_exact_size(sz); | ||||
|                     } | ||||
|                     if let Some(max) = opts.h1_max_buf_size { | ||||
|                         conn.set_max_buf_size(max); | ||||
|                     } | ||||
|                     let cd = proto::h1::dispatch::Client::new(rx); | ||||
|                     let dispatch = proto::h1::Dispatcher::new(cd, conn); | ||||
|                     ProtoClient::H1(dispatch) | ||||
|                 } | ||||
|                 if opts.h1_title_case_headers { | ||||
|                     conn.set_title_case_headers(); | ||||
|                 #[cfg(feature = "http2")] | ||||
|                 Proto::Http2 => { | ||||
|                     let h2 = | ||||
|                         proto::h2::client::handshake(io, rx, &opts.h2_builder, opts.exec.clone()) | ||||
|                             .await?; | ||||
|                     ProtoClient::H2(h2) | ||||
|                 } | ||||
|                 if let Some(sz) = opts.h1_read_buf_exact_size { | ||||
|                     conn.set_read_buf_exact_size(sz); | ||||
|                 } | ||||
|                 if let Some(max) = opts.h1_max_buf_size { | ||||
|                     conn.set_max_buf_size(max); | ||||
|                 } | ||||
|                 let cd = proto::h1::dispatch::Client::new(rx); | ||||
|                 let dispatch = proto::h1::Dispatcher::new(cd, conn); | ||||
|                 ProtoClient::H1(dispatch) | ||||
|             } else { | ||||
|                 let h2 = proto::h2::client::handshake(io, rx, &opts.h2_builder, opts.exec.clone()) | ||||
|                     .await?; | ||||
|                 ProtoClient::H2(h2) | ||||
|             }; | ||||
|  | ||||
|             Ok(( | ||||
| @@ -684,6 +724,7 @@ where | ||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||
|         match self.project() { | ||||
|             ProtoClientProj::H1(c) => c.poll(cx), | ||||
|             #[cfg(feature = "http2")] | ||||
|             ProtoClientProj::H2(c) => c.poll(cx), | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -184,6 +184,7 @@ impl Connected { | ||||
|  | ||||
|     // Don't public expose that `Connected` is `Clone`, unsure if we want to | ||||
|     // keep that contract... | ||||
|     #[cfg(feature = "http2")] | ||||
|     pub(super) fn clone(&self) -> Connected { | ||||
|         Connected { | ||||
|             alpn: self.alpn.clone(), | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| use futures_util::future; | ||||
| #[cfg(feature = "http2")] | ||||
| use std::future::Future; | ||||
|  | ||||
| use tokio::stream::Stream; | ||||
| use tokio::sync::{mpsc, oneshot}; | ||||
|  | ||||
| use crate::common::{task, Future, Pin, Poll}; | ||||
| use crate::common::{task, 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>>; | ||||
| @@ -41,6 +43,7 @@ pub struct Sender<T, U> { | ||||
| /// | ||||
| /// Cannot poll the Giver, but can still use it to determine if the Receiver | ||||
| /// has been dropped. However, this version can be cloned. | ||||
| #[cfg(feature = "http2")] | ||||
| pub struct UnboundedSender<T, U> { | ||||
|     /// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked. | ||||
|     giver: want::SharedGiver, | ||||
| @@ -97,6 +100,7 @@ impl<T, U> Sender<T, U> { | ||||
|             .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "http2")] | ||||
|     pub fn unbound(self) -> UnboundedSender<T, U> { | ||||
|         UnboundedSender { | ||||
|             giver: self.giver.shared(), | ||||
| @@ -105,6 +109,7 @@ impl<T, U> Sender<T, U> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<T, U> UnboundedSender<T, U> { | ||||
|     pub fn is_ready(&self) -> bool { | ||||
|         !self.giver.is_canceled() | ||||
| @@ -123,6 +128,7 @@ impl<T, U> UnboundedSender<T, U> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<T, U> Clone for UnboundedSender<T, U> { | ||||
|     fn clone(&self) -> Self { | ||||
|         UnboundedSender { | ||||
| @@ -197,6 +203,7 @@ pub enum Callback<T, U> { | ||||
| } | ||||
|  | ||||
| impl<T, U> Callback<T, U> { | ||||
|     #[cfg(feature = "http2")] | ||||
|     pub(crate) fn is_canceled(&self) -> bool { | ||||
|         match *self { | ||||
|             Callback::Retry(ref tx) => tx.is_closed(), | ||||
| @@ -222,10 +229,13 @@ impl<T, U> Callback<T, U> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "http2")] | ||||
|     pub(crate) fn send_when( | ||||
|         self, | ||||
|         mut when: impl Future<Output = Result<U, (crate::Error, Option<T>)>> + Unpin, | ||||
|     ) -> impl Future<Output = ()> { | ||||
|         use futures_util::future; | ||||
|  | ||||
|         let mut cb = Some(self); | ||||
|  | ||||
|         // "select" on this callback being canceled, and the future completing | ||||
| @@ -330,6 +340,7 @@ mod tests { | ||||
|         let _ = tx.try_send(Custom(2)).expect("2 ready"); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[test] | ||||
|     fn unbounded_sender_doesnt_bound_on_want() { | ||||
|         let (tx, rx) = channel::<Custom, ()>(); | ||||
|   | ||||
| @@ -460,6 +460,9 @@ where | ||||
|     ) -> impl Lazy<Output = crate::Result<Pooled<PoolClient<B>>>> + Unpin { | ||||
|         let executor = self.conn_builder.exec.clone(); | ||||
|         let pool = self.pool.clone(); | ||||
|         #[cfg(not(feature = "http2"))] | ||||
|         let conn_builder = self.conn_builder.clone(); | ||||
|         #[cfg(feature = "http2")] | ||||
|         let mut conn_builder = self.conn_builder.clone(); | ||||
|         let ver = self.config.ver; | ||||
|         let is_ver_h2 = ver == Ver::Http2; | ||||
| @@ -505,10 +508,16 @@ where | ||||
|                         } else { | ||||
|                             connecting | ||||
|                         }; | ||||
|  | ||||
|                         #[cfg_attr(not(feature = "http2"), allow(unused))] | ||||
|                         let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2; | ||||
|                         #[cfg(feature = "http2")] | ||||
|                         { | ||||
|                             conn_builder.http2_only(is_h2); | ||||
|                         } | ||||
|  | ||||
|                         Either::Left(Box::pin( | ||||
|                             conn_builder | ||||
|                                 .http2_only(is_h2) | ||||
|                                 .handshake(io) | ||||
|                                 .and_then(move |(tx, conn)| { | ||||
|                                     trace!( | ||||
| @@ -524,15 +533,23 @@ where | ||||
|                                     tx.when_ready() | ||||
|                                 }) | ||||
|                                 .map_ok(move |tx| { | ||||
|                                     let tx = { | ||||
|                                         #[cfg(feature = "http2")] | ||||
|                                         { | ||||
|                                             if is_h2 { | ||||
|                                                 PoolTx::Http2(tx.into_http2()) | ||||
|                                             } else { | ||||
|                                                 PoolTx::Http1(tx) | ||||
|                                             } | ||||
|                                         } | ||||
|                                         #[cfg(not(feature = "http2"))] | ||||
|                                         PoolTx::Http1(tx) | ||||
|                                     }; | ||||
|                                     pool.pooled( | ||||
|                                         connecting, | ||||
|                                         PoolClient { | ||||
|                                             conn_info: connected, | ||||
|                                             tx: if is_h2 { | ||||
|                                                 PoolTx::Http2(tx.into_http2()) | ||||
|                                             } else { | ||||
|                                                 PoolTx::Http1(tx) | ||||
|                                             }, | ||||
|                                             tx, | ||||
|                                         }, | ||||
|                                     ) | ||||
|                                 }), | ||||
| @@ -640,6 +657,7 @@ struct PoolClient<B> { | ||||
|  | ||||
| enum PoolTx<B> { | ||||
|     Http1(conn::SendRequest<B>), | ||||
|     #[cfg(feature = "http2")] | ||||
|     Http2(conn::Http2SendRequest<B>), | ||||
| } | ||||
|  | ||||
| @@ -647,6 +665,7 @@ impl<B> PoolClient<B> { | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||
|         match self.tx { | ||||
|             PoolTx::Http1(ref mut tx) => tx.poll_ready(cx), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(_) => Poll::Ready(Ok(())), | ||||
|         } | ||||
|     } | ||||
| @@ -658,6 +677,7 @@ impl<B> PoolClient<B> { | ||||
|     fn is_http2(&self) -> bool { | ||||
|         match self.tx { | ||||
|             PoolTx::Http1(_) => false, | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(_) => true, | ||||
|         } | ||||
|     } | ||||
| @@ -665,6 +685,7 @@ impl<B> PoolClient<B> { | ||||
|     fn is_ready(&self) -> bool { | ||||
|         match self.tx { | ||||
|             PoolTx::Http1(ref tx) => tx.is_ready(), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(ref tx) => tx.is_ready(), | ||||
|         } | ||||
|     } | ||||
| @@ -672,6 +693,7 @@ impl<B> PoolClient<B> { | ||||
|     fn is_closed(&self) -> bool { | ||||
|         match self.tx { | ||||
|             PoolTx::Http1(ref tx) => tx.is_closed(), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(ref tx) => tx.is_closed(), | ||||
|         } | ||||
|     } | ||||
| @@ -686,7 +708,11 @@ impl<B: HttpBody + 'static> PoolClient<B> { | ||||
|         B: Send, | ||||
|     { | ||||
|         match self.tx { | ||||
|             #[cfg(not(feature = "http2"))] | ||||
|             PoolTx::Http1(ref mut tx) => tx.send_request_retryable(req), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http1(ref mut tx) => Either::Left(tx.send_request_retryable(req)), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(ref mut tx) => Either::Right(tx.send_request_retryable(req)), | ||||
|         } | ||||
|     } | ||||
| @@ -699,6 +725,7 @@ where | ||||
|     fn is_open(&self) -> bool { | ||||
|         match self.tx { | ||||
|             PoolTx::Http1(ref tx) => tx.is_ready(), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(ref tx) => tx.is_ready(), | ||||
|         } | ||||
|     } | ||||
| @@ -709,6 +736,7 @@ where | ||||
|                 conn_info: self.conn_info, | ||||
|                 tx: PoolTx::Http1(tx), | ||||
|             }), | ||||
|             #[cfg(feature = "http2")] | ||||
|             PoolTx::Http2(tx) => { | ||||
|                 let b = PoolClient { | ||||
|                     conn_info: self.conn_info.clone(), | ||||
| @@ -1020,6 +1048,8 @@ impl Builder { | ||||
|     /// Note that setting this to true prevents HTTP/1 from being allowed. | ||||
|     /// | ||||
|     /// Default is false. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_only(&mut self, val: bool) -> &mut Self { | ||||
|         self.client_config.ver = if val { Ver::Http2 } else { Ver::Auto }; | ||||
|         self | ||||
| @@ -1033,6 +1063,8 @@ impl Builder { | ||||
|     /// If not set, hyper will use a default. | ||||
|     /// | ||||
|     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     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()); | ||||
| @@ -1044,6 +1076,8 @@ impl Builder { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_initial_connection_window_size( | ||||
|         &mut self, | ||||
|         sz: impl Into<Option<u32>>, | ||||
| @@ -1058,6 +1092,8 @@ impl Builder { | ||||
|     /// Enabling this will override the limits set in | ||||
|     /// `http2_initial_stream_window_size` and | ||||
|     /// `http2_initial_connection_window_size`. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self { | ||||
|         self.conn_builder.http2_adaptive_window(enabled); | ||||
|         self | ||||
| @@ -1068,6 +1104,8 @@ impl Builder { | ||||
|     /// Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// If not set, hyper will use a default. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_max_frame_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self { | ||||
|         self.conn_builder.http2_max_frame_size(sz); | ||||
|         self | ||||
| @@ -1084,6 +1122,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// Requires the `runtime` cargo feature to be enabled. | ||||
|     #[cfg(feature = "runtime")] | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_keep_alive_interval( | ||||
|         &mut self, | ||||
|         interval: impl Into<Option<Duration>>, | ||||
| @@ -1103,6 +1143,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// Requires the `runtime` cargo feature to be enabled. | ||||
|     #[cfg(feature = "runtime")] | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self { | ||||
|         self.conn_builder.http2_keep_alive_timeout(timeout); | ||||
|         self | ||||
| @@ -1121,6 +1163,8 @@ impl Builder { | ||||
|     /// | ||||
|     /// Requires the `runtime` cargo feature to be enabled. | ||||
|     #[cfg(feature = "runtime")] | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self { | ||||
|         self.conn_builder.http2_keep_alive_while_idle(enabled); | ||||
|         self | ||||
|   | ||||
| @@ -45,6 +45,7 @@ pub(super) enum Reservation<T> { | ||||
|     /// This connection could be used multiple times, the first one will be | ||||
|     /// reinserted into the `idle` pool, and the second will be given to | ||||
|     /// the `Checkout`. | ||||
|     #[cfg(feature = "http2")] | ||||
|     Shared(T, T), | ||||
|     /// This connection requires unique access. It will be returned after | ||||
|     /// use is complete. | ||||
| @@ -199,9 +200,14 @@ impl<T: Poolable> Pool<T> { | ||||
|     } | ||||
|     */ | ||||
|  | ||||
|     pub(super) fn pooled(&self, mut connecting: Connecting<T>, value: T) -> Pooled<T> { | ||||
|     pub(super) fn pooled( | ||||
|         &self, | ||||
|         #[cfg_attr(not(feature = "http2"), allow(unused_mut))] mut connecting: Connecting<T>, | ||||
|         value: T, | ||||
|     ) -> Pooled<T> { | ||||
|         let (value, pool_ref) = if let Some(ref enabled) = self.inner { | ||||
|             match value.reserve() { | ||||
|                 #[cfg(feature = "http2")] | ||||
|                 Reservation::Shared(to_insert, to_return) => { | ||||
|                     let mut inner = enabled.lock().unwrap(); | ||||
|                     inner.put(connecting.key.clone(), to_insert, enabled); | ||||
| @@ -291,6 +297,7 @@ impl<'a, T: Poolable + 'a> IdlePopper<'a, T> { | ||||
|             } | ||||
|  | ||||
|             let value = match entry.value.reserve() { | ||||
|                 #[cfg(feature = "http2")] | ||||
|                 Reservation::Shared(to_reinsert, to_checkout) => { | ||||
|                     self.list.push(Idle { | ||||
|                         idle_at: Instant::now(), | ||||
| @@ -325,6 +332,7 @@ impl<T: Poolable> PoolInner<T> { | ||||
|                 if !tx.is_canceled() { | ||||
|                     let reserved = value.take().expect("value already sent"); | ||||
|                     let reserved = match reserved.reserve() { | ||||
|                         #[cfg(feature = "http2")] | ||||
|                         Reservation::Shared(to_keep, to_send) => { | ||||
|                             value = Some(to_keep); | ||||
|                             to_send | ||||
|   | ||||
		Reference in New Issue
	
	Block a user