sui_http/
connection_handler.rs1use std::future::Future;
5use std::pin::Pin;
6use std::pin::pin;
7use std::time::Duration;
8
9use http::Request;
10use http::Response;
11use hyper_util::rt::TokioExecutor;
12use hyper_util::server::conn::auto;
13use tracing::debug;
14use tracing::trace;
15
16use crate::ActiveConnections;
17use crate::BoxError;
18use crate::ConnectionId;
19use crate::fuse::Fuse;
20
21pub async fn serve_connection<IO, S, B, C>(
24 hyper_io: IO,
25 hyper_svc: S,
26 builder: auto::Builder<TokioExecutor>,
27 graceful_shutdown_token: tokio_util::sync::CancellationToken,
28 max_connection_age: Option<Duration>,
29 max_connection_age_grace: Option<Duration>,
30 on_connection_close: C,
31) where
32 B: http_body::Body + Send + 'static,
33 B::Data: Send,
34 B::Error: Into<BoxError>,
35 IO: hyper::rt::Read + hyper::rt::Write + Send + Unpin + 'static,
36 S: hyper::service::Service<Request<hyper::body::Incoming>, Response = Response<B>> + 'static,
37 S::Future: Send + 'static,
38 S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
39{
40 if builder.is_http1_available() {
48 let conn = pin!(builder.serve_connection_with_upgrades(hyper_io, hyper_svc));
49 drive_connection(
50 conn,
51 graceful_shutdown_token,
52 max_connection_age,
53 max_connection_age_grace,
54 )
55 .await;
56 } else {
57 let conn = pin!(builder.serve_connection(hyper_io, hyper_svc));
58 drive_connection(
59 conn,
60 graceful_shutdown_token,
61 max_connection_age,
62 max_connection_age_grace,
63 )
64 .await;
65 }
66
67 trace!("connection closed");
68 drop(on_connection_close);
69}
70
71trait GracefulConnection: Future<Output = Result<(), BoxError>> {
74 fn graceful_shutdown(self: Pin<&mut Self>);
75}
76
77impl<IO, S, B> GracefulConnection for auto::Connection<'_, IO, S, TokioExecutor>
78where
79 B: http_body::Body + Send + 'static,
80 B::Data: Send,
81 B::Error: Into<BoxError>,
82 IO: hyper::rt::Read + hyper::rt::Write + Unpin + 'static,
83 S: hyper::service::Service<Request<hyper::body::Incoming>, Response = Response<B>>,
84 S::Future: Send + 'static,
85 S::Error: Into<BoxError>,
86{
87 fn graceful_shutdown(self: Pin<&mut Self>) {
88 auto::Connection::graceful_shutdown(self)
89 }
90}
91
92impl<IO, S, B> GracefulConnection for auto::UpgradeableConnection<'_, IO, S, TokioExecutor>
93where
94 B: http_body::Body + Send + 'static,
95 B::Data: Send,
96 B::Error: Into<BoxError>,
97 IO: hyper::rt::Read + hyper::rt::Write + Send + Unpin + 'static,
98 S: hyper::service::Service<Request<hyper::body::Incoming>, Response = Response<B>>,
99 S::Future: Send + 'static,
100 S::Error: Into<BoxError>,
101{
102 fn graceful_shutdown(self: Pin<&mut Self>) {
103 auto::UpgradeableConnection::graceful_shutdown(self)
104 }
105}
106
107async fn drive_connection<C>(
108 mut conn: Pin<&mut C>,
109 graceful_shutdown_token: tokio_util::sync::CancellationToken,
110 max_connection_age: Option<Duration>,
111 max_connection_age_grace: Option<Duration>,
112) where
113 C: GracefulConnection,
114{
115 let mut sig = pin!(Fuse::new(graceful_shutdown_token.cancelled_owned()));
116
117 let sleep = sleep_or_pending(max_connection_age);
118 tokio::pin!(sleep);
119 let mut in_grace_period = false;
120
121 loop {
122 tokio::select! {
123 _ = &mut sig => {
124 conn.as_mut().graceful_shutdown();
125 if !in_grace_period {
131 in_grace_period = true;
132 sleep.set(sleep_or_pending(max_connection_age_grace));
133 }
134 }
135 rv = &mut conn => {
136 if let Err(err) = rv {
137 debug!("failed serving connection: {:#}", err);
138 }
139 break;
140 },
141 _ = &mut sleep => {
142 if in_grace_period {
143 debug!("max connection age grace period expired, closing connection");
149 break;
150 }
151 conn.as_mut().graceful_shutdown();
152 in_grace_period = true;
153 sleep.set(sleep_or_pending(max_connection_age_grace));
154 },
155 }
156 }
157}
158
159async fn sleep_or_pending(wait_for: Option<Duration>) {
160 match wait_for {
161 Some(wait) => tokio::time::sleep(wait).await,
162 None => std::future::pending().await,
163 };
164}
165
166pub(crate) struct OnConnectionClose<A> {
167 id: ConnectionId,
168 active_connections: ActiveConnections<A>,
169}
170
171impl<A> OnConnectionClose<A> {
172 pub(crate) fn new(id: ConnectionId, active_connections: ActiveConnections<A>) -> Self {
173 Self {
174 id,
175 active_connections,
176 }
177 }
178}
179
180impl<A> Drop for OnConnectionClose<A> {
181 fn drop(&mut self) {
182 self.active_connections.write().unwrap().remove(&self.id);
183 }
184}