feat(http2): add HTTP2 keep-alive support for client and server
This adds HTTP2 keep-alive support to client and server connections based losely on GRPC keep-alive. When enabled, after no data has been received for some configured interval, an HTTP2 PING frame is sent. If the PING is not acknowledged with a configured timeout, the connection is closed. Clients have an additional option to enable keep-alive while the connection is otherwise idle. When disabled, keep-alive PINGs are only used while there are open request/response streams. If enabled, PINGs are sent even when there are no active streams. For now, since these features use `tokio::time::Delay`, the `runtime` cargo feature is required to use them.
This commit is contained in:
		| @@ -12,7 +12,7 @@ use http::HeaderMap; | ||||
| use http_body::{Body as HttpBody, SizeHint}; | ||||
|  | ||||
| use crate::common::{task, watch, Future, Never, Pin, Poll}; | ||||
| use crate::proto::h2::bdp; | ||||
| use crate::proto::h2::ping; | ||||
| use crate::proto::DecodedLength; | ||||
| use crate::upgrade::OnUpgrade; | ||||
|  | ||||
| @@ -38,7 +38,7 @@ enum Kind { | ||||
|         rx: mpsc::Receiver<Result<Bytes, crate::Error>>, | ||||
|     }, | ||||
|     H2 { | ||||
|         bdp: bdp::Sampler, | ||||
|         ping: ping::Recorder, | ||||
|         content_length: DecodedLength, | ||||
|         recv: h2::RecvStream, | ||||
|     }, | ||||
| @@ -180,10 +180,10 @@ impl Body { | ||||
|     pub(crate) fn h2( | ||||
|         recv: h2::RecvStream, | ||||
|         content_length: DecodedLength, | ||||
|         bdp: bdp::Sampler, | ||||
|         ping: ping::Recorder, | ||||
|     ) -> Self { | ||||
|         let body = Body::new(Kind::H2 { | ||||
|             bdp, | ||||
|             ping, | ||||
|             content_length, | ||||
|             recv, | ||||
|         }); | ||||
| @@ -265,14 +265,14 @@ impl Body { | ||||
|                 } | ||||
|             } | ||||
|             Kind::H2 { | ||||
|                 ref bdp, | ||||
|                 ref ping, | ||||
|                 recv: ref mut h2, | ||||
|                 content_length: ref mut len, | ||||
|             } => match ready!(h2.poll_data(cx)) { | ||||
|                 Some(Ok(bytes)) => { | ||||
|                     let _ = h2.flow_control().release_capacity(bytes.len()); | ||||
|                     len.sub_if(bytes.len() as u64); | ||||
|                     bdp.sample(bytes.len()); | ||||
|                     ping.record_data(bytes.len()); | ||||
|                     Poll::Ready(Some(Ok(bytes))) | ||||
|                 } | ||||
|                 Some(Err(e)) => Poll::Ready(Some(Err(crate::Error::new_body(e)))), | ||||
| @@ -321,9 +321,14 @@ impl HttpBody for Body { | ||||
|     ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { | ||||
|         match self.kind { | ||||
|             Kind::H2 { | ||||
|                 recv: ref mut h2, .. | ||||
|                 recv: ref mut h2, | ||||
|                 ref ping, | ||||
|                 .. | ||||
|             } => match ready!(h2.poll_trailers(cx)) { | ||||
|                 Ok(t) => Poll::Ready(Ok(t)), | ||||
|                 Ok(t) => { | ||||
|                     ping.record_non_data(); | ||||
|                     Poll::Ready(Ok(t)) | ||||
|                 } | ||||
|                 Err(e) => Poll::Ready(Err(crate::Error::new_h2(e))), | ||||
|             }, | ||||
|             _ => Poll::Ready(Ok(None)), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user