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