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:
		| @@ -45,10 +45,12 @@ | ||||
|  | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| use std::marker::PhantomData; | ||||
| use std::mem; | ||||
| #[cfg(feature = "tcp")] | ||||
| use std::net::SocketAddr; | ||||
| #[cfg(feature = "runtime")] | ||||
| #[cfg(feature = "http2")] | ||||
| use std::time::Duration; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| @@ -57,9 +59,11 @@ use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use super::Accept; | ||||
| use crate::body::{Body, HttpBody}; | ||||
| use crate::common::exec::{Exec, H2Exec, NewSvcExec}; | ||||
| use crate::common::exec::{ConnStreamExec, Exec, NewSvcExec}; | ||||
| #[cfg(feature = "http2")] | ||||
| use crate::common::io::Rewind; | ||||
| use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
| #[cfg(feature = "http2")] | ||||
| use crate::error::{Kind, Parse}; | ||||
| use crate::proto; | ||||
| use crate::service::{HttpService, MakeServiceRef}; | ||||
| @@ -85,6 +89,7 @@ pub struct Http<E = Exec> { | ||||
|     h1_half_close: bool, | ||||
|     h1_keep_alive: bool, | ||||
|     h1_writev: Option<bool>, | ||||
|     #[cfg(feature = "http2")] | ||||
|     h2_builder: proto::h2::server::Config, | ||||
|     mode: ConnectionMode, | ||||
|     max_buf_size: Option<usize>, | ||||
| @@ -97,8 +102,10 @@ enum ConnectionMode { | ||||
|     /// Always use HTTP/1 and do not upgrade when a parse error occurs. | ||||
|     H1Only, | ||||
|     /// Always use HTTP/2. | ||||
|     #[cfg(feature = "http2")] | ||||
|     H2Only, | ||||
|     /// Use HTTP/1 and try to upgrade to h2 when a parse error occurs. | ||||
|     #[cfg(feature = "http2")] | ||||
|     Fallback, | ||||
| } | ||||
|  | ||||
| @@ -150,6 +157,7 @@ where | ||||
|     S: HttpService<Body>, | ||||
| { | ||||
|     pub(super) conn: Option<ProtoServer<T, S::ResBody, S, E>>, | ||||
|     #[cfg(feature = "http2")] | ||||
|     fallback: Fallback<E>, | ||||
| } | ||||
|  | ||||
| @@ -167,16 +175,20 @@ where | ||||
|             T, | ||||
|             proto::ServerTransaction, | ||||
|         >, | ||||
|         PhantomData<E>, | ||||
|     ), | ||||
|     #[cfg(feature = "http2")] | ||||
|     H2(#[pin] proto::h2::Server<Rewind<T>, S, B, E>), | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| #[derive(Clone, Debug)] | ||||
| enum Fallback<E> { | ||||
|     ToHttp2(proto::h2::server::Config, E), | ||||
|     Http1Only, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<E> Fallback<E> { | ||||
|     fn to_h2(&self) -> bool { | ||||
|         match *self { | ||||
| @@ -186,6 +198,7 @@ impl<E> Fallback<E> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| impl<E> Unpin for Fallback<E> {} | ||||
|  | ||||
| /// Deconstructed parts of a `Connection`. | ||||
| @@ -221,8 +234,9 @@ impl Http { | ||||
|             h1_half_close: false, | ||||
|             h1_keep_alive: true, | ||||
|             h1_writev: None, | ||||
|             #[cfg(feature = "http2")] | ||||
|             h2_builder: Default::default(), | ||||
|             mode: ConnectionMode::Fallback, | ||||
|             mode: ConnectionMode::default(), | ||||
|             max_buf_size: None, | ||||
|             pipeline_flush: false, | ||||
|         } | ||||
| @@ -237,7 +251,10 @@ impl<E> Http<E> { | ||||
|         if val { | ||||
|             self.mode = ConnectionMode::H1Only; | ||||
|         } else { | ||||
|             self.mode = ConnectionMode::Fallback; | ||||
|             #[cfg(feature = "http2")] | ||||
|             { | ||||
|                 self.mode = ConnectionMode::Fallback; | ||||
|             } | ||||
|         } | ||||
|         self | ||||
|     } | ||||
| @@ -291,6 +308,8 @@ impl<E> Http<E> { | ||||
|     /// Sets whether HTTP2 is required. | ||||
|     /// | ||||
|     /// Default is false | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_only(&mut self, val: bool) -> &mut Self { | ||||
|         if val { | ||||
|             self.mode = ConnectionMode::H2Only; | ||||
| @@ -308,6 +327,8 @@ impl<E> Http<E> { | ||||
|     /// 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; | ||||
| @@ -321,6 +342,8 @@ impl<E> Http<E> { | ||||
|     /// 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>>, | ||||
| @@ -337,6 +360,8 @@ impl<E> Http<E> { | ||||
|     /// 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; | ||||
|  | ||||
| @@ -353,6 +378,8 @@ impl<E> Http<E> { | ||||
|     /// 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; | ||||
| @@ -366,6 +393,8 @@ impl<E> Http<E> { | ||||
|     /// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self { | ||||
|         self.h2_builder.max_concurrent_streams = max.into(); | ||||
|         self | ||||
| @@ -382,6 +411,8 @@ impl<E> Http<E> { | ||||
|     /// | ||||
|     /// 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>>, | ||||
| @@ -401,6 +432,8 @@ impl<E> Http<E> { | ||||
|     /// | ||||
|     /// 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 | ||||
| @@ -441,6 +474,7 @@ impl<E> Http<E> { | ||||
|             h1_half_close: self.h1_half_close, | ||||
|             h1_keep_alive: self.h1_keep_alive, | ||||
|             h1_writev: self.h1_writev, | ||||
|             #[cfg(feature = "http2")] | ||||
|             h2_builder: self.h2_builder, | ||||
|             mode: self.mode, | ||||
|             max_buf_size: self.max_buf_size, | ||||
| @@ -483,10 +517,10 @@ impl<E> Http<E> { | ||||
|         Bd: HttpBody + 'static, | ||||
|         Bd::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         I: AsyncRead + AsyncWrite + Unpin, | ||||
|         E: H2Exec<S::Future, Bd>, | ||||
|         E: ConnStreamExec<S::Future, Bd>, | ||||
|     { | ||||
|         let proto = match self.mode { | ||||
|             ConnectionMode::H1Only | ConnectionMode::Fallback => { | ||||
|         macro_rules! h1 { | ||||
|             () => {{ | ||||
|                 let mut conn = proto::Conn::new(io); | ||||
|                 if !self.h1_keep_alive { | ||||
|                     conn.disable_keep_alive(); | ||||
| @@ -506,8 +540,16 @@ impl<E> Http<E> { | ||||
|                     conn.set_max_buf_size(max); | ||||
|                 } | ||||
|                 let sd = proto::h1::dispatch::Server::new(service); | ||||
|                 ProtoServer::H1(proto::h1::Dispatcher::new(sd, conn)) | ||||
|             } | ||||
|                 ProtoServer::H1(proto::h1::Dispatcher::new(sd, conn), PhantomData) | ||||
|             }}; | ||||
|         } | ||||
|  | ||||
|         let proto = match self.mode { | ||||
|             #[cfg(not(feature = "http2"))] | ||||
|             ConnectionMode::H1Only => h1!(), | ||||
|             #[cfg(feature = "http2")] | ||||
|             ConnectionMode::H1Only | ConnectionMode::Fallback => h1!(), | ||||
|             #[cfg(feature = "http2")] | ||||
|             ConnectionMode::H2Only => { | ||||
|                 let rewind_io = Rewind::new(io); | ||||
|                 let h2 = | ||||
| @@ -518,6 +560,7 @@ impl<E> Http<E> { | ||||
|  | ||||
|         Connection { | ||||
|             conn: Some(proto), | ||||
|             #[cfg(feature = "http2")] | ||||
|             fallback: if self.mode == ConnectionMode::Fallback { | ||||
|                 Fallback::ToHttp2(self.h2_builder.clone(), self.exec.clone()) | ||||
|             } else { | ||||
| @@ -534,7 +577,7 @@ impl<E> Http<E> { | ||||
|         S: MakeServiceRef<IO, Body, ResBody = Bd>, | ||||
|         S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         Bd: HttpBody, | ||||
|         E: H2Exec<<S::Service as HttpService<Body>>::Future, Bd>, | ||||
|         E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, Bd>, | ||||
|     { | ||||
|         Serve { | ||||
|             incoming, | ||||
| @@ -553,7 +596,7 @@ where | ||||
|     I: AsyncRead + AsyncWrite + Unpin, | ||||
|     B: HttpBody + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<S::Future, B>, | ||||
|     E: ConnStreamExec<S::Future, B>, | ||||
| { | ||||
|     /// Start a graceful shutdown process for this connection. | ||||
|     /// | ||||
| @@ -567,9 +610,10 @@ where | ||||
|     /// nothing. | ||||
|     pub fn graceful_shutdown(self: Pin<&mut Self>) { | ||||
|         match self.project().conn { | ||||
|             Some(ProtoServer::H1(ref mut h1)) => { | ||||
|             Some(ProtoServer::H1(ref mut h1, _)) => { | ||||
|                 h1.disable_keep_alive(); | ||||
|             } | ||||
|             #[cfg(feature = "http2")] | ||||
|             Some(ProtoServer::H2(ref mut h2)) => { | ||||
|                 h2.graceful_shutdown(); | ||||
|             } | ||||
| @@ -596,7 +640,7 @@ where | ||||
|     /// This method will return a `None` if this connection is using an h2 protocol. | ||||
|     pub fn try_into_parts(self) -> Option<Parts<I, S>> { | ||||
|         match self.conn.unwrap() { | ||||
|             ProtoServer::H1(h1) => { | ||||
|             ProtoServer::H1(h1, _) => { | ||||
|                 let (io, read_buf, dispatch) = h1.into_inner(); | ||||
|                 Some(Parts { | ||||
|                     io, | ||||
| @@ -605,6 +649,7 @@ where | ||||
|                     _inner: (), | ||||
|                 }) | ||||
|             } | ||||
|             #[cfg(feature = "http2")] | ||||
|             ProtoServer::H2(_h2) => None, | ||||
|         } | ||||
|     } | ||||
| @@ -628,18 +673,24 @@ where | ||||
|     { | ||||
|         loop { | ||||
|             let polled = match *self.conn.as_mut().unwrap() { | ||||
|                 ProtoServer::H1(ref mut h1) => h1.poll_without_shutdown(cx), | ||||
|                 ProtoServer::H1(ref mut h1, _) => h1.poll_without_shutdown(cx), | ||||
|                 #[cfg(feature = "http2")] | ||||
|                 ProtoServer::H2(ref mut h2) => return Pin::new(h2).poll(cx).map_ok(|_| ()), | ||||
|             }; | ||||
|             match ready!(polled) { | ||||
|                 Ok(()) => return Poll::Ready(Ok(())), | ||||
|                 Err(e) => match *e.kind() { | ||||
|                     Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                         self.upgrade_h2(); | ||||
|                         continue; | ||||
|                 Err(e) => { | ||||
|                     #[cfg(feature = "http2")] | ||||
|                     match *e.kind() { | ||||
|                         Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                             self.upgrade_h2(); | ||||
|                             continue; | ||||
|                         } | ||||
|                         _ => (), | ||||
|                     } | ||||
|                     _ => return Poll::Ready(Err(e)), | ||||
|                 }, | ||||
|  | ||||
|                     return Poll::Ready(Err(e)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -659,12 +710,13 @@ where | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "http2")] | ||||
|     fn upgrade_h2(&mut self) { | ||||
|         trace!("Trying to upgrade connection to h2"); | ||||
|         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"); | ||||
|             } | ||||
| @@ -699,7 +751,7 @@ where | ||||
|     I: AsyncRead + AsyncWrite + Unpin + 'static, | ||||
|     B: HttpBody + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<S::Future, B>, | ||||
|     E: ConnStreamExec<S::Future, B>, | ||||
| { | ||||
|     type Output = crate::Result<()>; | ||||
|  | ||||
| @@ -716,13 +768,18 @@ where | ||||
|                     } | ||||
|                     return Poll::Ready(Ok(())); | ||||
|                 } | ||||
|                 Err(e) => match *e.kind() { | ||||
|                     Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                         self.upgrade_h2(); | ||||
|                         continue; | ||||
|                 Err(e) => { | ||||
|                     #[cfg(feature = "http2")] | ||||
|                     match *e.kind() { | ||||
|                         Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { | ||||
|                             self.upgrade_h2(); | ||||
|                             continue; | ||||
|                         } | ||||
|                         _ => (), | ||||
|                     } | ||||
|                     _ => return Poll::Ready(Err(e)), | ||||
|                 }, | ||||
|  | ||||
|                     return Poll::Ready(Err(e)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -736,6 +793,23 @@ where | ||||
|         f.debug_struct("Connection").finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl ConnectionMode ===== | ||||
|  | ||||
| impl ConnectionMode {} | ||||
|  | ||||
| impl Default for ConnectionMode { | ||||
|     #[cfg(feature = "http2")] | ||||
|     fn default() -> ConnectionMode { | ||||
|         ConnectionMode::Fallback | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "http2"))] | ||||
|     fn default() -> ConnectionMode { | ||||
|         ConnectionMode::H1Only | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl Serve ===== | ||||
|  | ||||
| impl<I, S, E> Serve<I, S, E> { | ||||
| @@ -766,7 +840,7 @@ where | ||||
|     IE: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     B: HttpBody, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>, | ||||
| { | ||||
|     fn poll_next_( | ||||
|         self: Pin<&mut Self>, | ||||
| @@ -804,7 +878,7 @@ where | ||||
|     S: HttpService<Body, ResBody = B>, | ||||
|     B: HttpBody + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<S::Future, B>, | ||||
|     E: ConnStreamExec<S::Future, B>, | ||||
| { | ||||
|     type Output = Result<Connection<I, S, E>, FE>; | ||||
|  | ||||
| @@ -838,7 +912,7 @@ where | ||||
|     IO: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|     S: MakeServiceRef<IO, Body, ResBody = B>, | ||||
|     B: HttpBody, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>, | ||||
| { | ||||
|     pub(super) fn poll_watch<W>( | ||||
|         self: Pin<&mut Self>, | ||||
| @@ -875,13 +949,14 @@ where | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     B: HttpBody + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<S::Future, B>, | ||||
|     E: ConnStreamExec<S::Future, B>, | ||||
| { | ||||
|     type Output = crate::Result<proto::Dispatched>; | ||||
|  | ||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||
|         match self.project() { | ||||
|             ProtoServerProj::H1(s) => s.poll(cx), | ||||
|             ProtoServerProj::H1(s, _) => s.poll(cx), | ||||
|             #[cfg(feature = "http2")] | ||||
|             ProtoServerProj::H2(s) => s.poll(cx), | ||||
|         } | ||||
|     } | ||||
| @@ -893,7 +968,7 @@ pub(crate) mod spawn_all { | ||||
|  | ||||
|     use super::{Connecting, UpgradeableConnection}; | ||||
|     use crate::body::{Body, HttpBody}; | ||||
|     use crate::common::exec::H2Exec; | ||||
|     use crate::common::exec::ConnStreamExec; | ||||
|     use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
|     use crate::service::HttpService; | ||||
|     use pin_project::pin_project; | ||||
| @@ -920,7 +995,7 @@ pub(crate) mod spawn_all { | ||||
|     where | ||||
|         I: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|         S: HttpService<Body>, | ||||
|         E: H2Exec<S::Future, S::ResBody>, | ||||
|         E: ConnStreamExec<S::Future, S::ResBody>, | ||||
|         S::ResBody: 'static, | ||||
|         <S::ResBody as HttpBody>::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     { | ||||
| @@ -970,7 +1045,7 @@ pub(crate) mod spawn_all { | ||||
|         S: HttpService<Body, ResBody = B>, | ||||
|         B: HttpBody + 'static, | ||||
|         B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         E: H2Exec<S::Future, B>, | ||||
|         E: ConnStreamExec<S::Future, B>, | ||||
|         W: Watcher<I, S, E>, | ||||
|     { | ||||
|         type Output = (); | ||||
| @@ -1036,7 +1111,7 @@ mod upgrades { | ||||
|         I: AsyncRead + AsyncWrite + Unpin, | ||||
|         B: HttpBody + 'static, | ||||
|         B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         E: H2Exec<S::Future, B>, | ||||
|         E: ConnStreamExec<S::Future, B>, | ||||
|     { | ||||
|         /// Start a graceful shutdown process for this connection. | ||||
|         /// | ||||
| @@ -1054,7 +1129,7 @@ mod upgrades { | ||||
|         I: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|         B: HttpBody + 'static, | ||||
|         B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         E: super::H2Exec<S::Future, B>, | ||||
|         E: ConnStreamExec<S::Future, B>, | ||||
|     { | ||||
|         type Output = crate::Result<()>; | ||||
|  | ||||
| @@ -1064,7 +1139,7 @@ mod upgrades { | ||||
|                     Ok(proto::Dispatched::Shutdown) => return Poll::Ready(Ok(())), | ||||
|                     Ok(proto::Dispatched::Upgrade(pending)) => { | ||||
|                         let h1 = match mem::replace(&mut self.inner.conn, None) { | ||||
|                             Some(ProtoServer::H1(h1)) => h1, | ||||
|                             Some(ProtoServer::H1(h1, _)) => h1, | ||||
|                             _ => unreachable!("Upgrade expects h1"), | ||||
|                         }; | ||||
|  | ||||
| @@ -1072,13 +1147,18 @@ mod upgrades { | ||||
|                         pending.fulfill(Upgraded::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; | ||||
|                     Err(e) => { | ||||
|                         #[cfg(feature = "http2")] | ||||
|                         match *e.kind() { | ||||
|                             Kind::Parse(Parse::VersionH2) if self.inner.fallback.to_h2() => { | ||||
|                                 self.inner.upgrade_h2(); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             _ => (), | ||||
|                         } | ||||
|                         _ => return Poll::Ready(Err(e)), | ||||
|                     }, | ||||
|  | ||||
|                         return Poll::Ready(Err(e)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -70,7 +70,7 @@ use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use self::accept::Accept; | ||||
| use crate::body::{Body, HttpBody}; | ||||
| use crate::common::exec::{Exec, H2Exec, NewSvcExec}; | ||||
| use crate::common::exec::{ConnStreamExec, Exec, NewSvcExec}; | ||||
| 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 | ||||
| @@ -154,7 +154,7 @@ where | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     B: HttpBody + Send + Sync + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: NewSvcExec<IO, S::Future, S::Service, E, GracefulWatcher>, | ||||
| { | ||||
|     /// Prepares a server to handle graceful shutdown when the provided future | ||||
| @@ -210,7 +210,7 @@ where | ||||
|     S::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     B: HttpBody + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: NewSvcExec<IO, S::Future, S::Service, E, NoopWatcher>, | ||||
| { | ||||
|     type Output = crate::Result<()>; | ||||
| @@ -307,6 +307,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// Sets whether HTTP/2 is required. | ||||
|     /// | ||||
|     /// Default is `false`. | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_only(mut self, val: bool) -> Self { | ||||
|         self.protocol.http2_only(val); | ||||
|         self | ||||
| @@ -320,6 +322,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// 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>>) -> Self { | ||||
|         self.protocol.http2_initial_stream_window_size(sz.into()); | ||||
|         self | ||||
| @@ -330,6 +334,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// 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>>) -> Self { | ||||
|         self.protocol | ||||
|             .http2_initial_connection_window_size(sz.into()); | ||||
| @@ -341,6 +347,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// 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) -> Self { | ||||
|         self.protocol.http2_adaptive_window(enabled); | ||||
|         self | ||||
| @@ -351,6 +359,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// 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>>) -> Self { | ||||
|         self.protocol.http2_max_frame_size(sz); | ||||
|         self | ||||
| @@ -362,6 +372,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing. | ||||
|     /// | ||||
|     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS | ||||
|     #[cfg(feature = "http2")] | ||||
|     #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] | ||||
|     pub fn http2_max_concurrent_streams(mut self, max: impl Into<Option<u32>>) -> Self { | ||||
|         self.protocol.http2_max_concurrent_streams(max.into()); | ||||
|         self | ||||
| @@ -378,6 +390,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// | ||||
|     /// 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>>) -> Self { | ||||
|         self.protocol.http2_keep_alive_interval(interval); | ||||
|         self | ||||
| @@ -394,6 +408,8 @@ impl<I, E> Builder<I, E> { | ||||
|     /// | ||||
|     /// 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) -> Self { | ||||
|         self.protocol.http2_keep_alive_timeout(timeout); | ||||
|         self | ||||
| @@ -449,7 +465,7 @@ impl<I, E> Builder<I, E> { | ||||
|         B: HttpBody + 'static, | ||||
|         B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|         E: NewSvcExec<I::Conn, S::Future, S::Service, E, NoopWatcher>, | ||||
|         E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|         E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     { | ||||
|         let serve = self.protocol.serve(self.incoming, new_service); | ||||
|         let spawn_all = serve.spawn_all(); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; | ||||
| use super::Accept; | ||||
| use crate::body::{Body, HttpBody}; | ||||
| use crate::common::drain::{self, Draining, Signal, Watch, Watching}; | ||||
| use crate::common::exec::{H2Exec, NewSvcExec}; | ||||
| use crate::common::exec::{ConnStreamExec, NewSvcExec}; | ||||
| use crate::common::{task, Future, Pin, Poll, Unpin}; | ||||
| use crate::service::{HttpService, MakeServiceRef}; | ||||
|  | ||||
| @@ -53,7 +53,7 @@ where | ||||
|     B: HttpBody + Send + Sync + 'static, | ||||
|     B::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     F: Future<Output = ()>, | ||||
|     E: H2Exec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>, | ||||
|     E: NewSvcExec<IO, S::Future, S::Service, E, GracefulWatcher>, | ||||
| { | ||||
|     type Output = crate::Result<()>; | ||||
| @@ -96,7 +96,7 @@ impl<I, S, E> Watcher<I, S, E> for GracefulWatcher | ||||
| where | ||||
|     I: AsyncRead + AsyncWrite + Unpin + Send + 'static, | ||||
|     S: HttpService<Body>, | ||||
|     E: H2Exec<S::Future, S::ResBody>, | ||||
|     E: ConnStreamExec<S::Future, S::ResBody>, | ||||
|     S::ResBody: Send + Sync + 'static, | ||||
|     <S::ResBody as HttpBody>::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
| { | ||||
| @@ -115,7 +115,7 @@ where | ||||
|     I: AsyncRead + AsyncWrite + Unpin, | ||||
|     S::ResBody: HttpBody + Send + 'static, | ||||
|     <S::ResBody as HttpBody>::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     E: H2Exec<S::Future, S::ResBody>, | ||||
|     E: ConnStreamExec<S::Future, S::ResBody>, | ||||
| { | ||||
|     conn.graceful_shutdown() | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user