1use std::{
2 fmt,
3 future::Future,
4 net::SocketAddr,
5 pin::Pin,
6 rc::Rc,
7 time::{Duration, Instant},
8};
9
10use bytes::BytesMut;
11
12use crate::{
13 date::{DateService, DATE_VALUE_LENGTH},
14 KeepAlive,
15};
16
17pub(crate) type GracefulShutdownFuture = Pin<Box<dyn Future<Output = ()>>>;
18
19#[derive(Clone)]
20pub(crate) struct GracefulShutdownSignal(Rc<dyn Fn() -> GracefulShutdownFuture>);
21
22impl GracefulShutdownSignal {
23 pub(crate) fn new<F, Fut>(signal: F) -> Self
24 where
25 F: Fn() -> Fut + 'static,
26 Fut: Future<Output = ()> + 'static,
27 {
28 Self(Rc::new(move || Box::pin(signal())))
29 }
30
31 fn notified(&self) -> GracefulShutdownFuture {
32 (self.0)()
33 }
34}
35
36impl fmt::Debug for GracefulShutdownSignal {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.debug_struct("GracefulShutdownSignal")
39 .finish_non_exhaustive()
40 }
41}
42
43pub(crate) const DEFAULT_H2_CONN_WINDOW_SIZE: u32 = 1024 * 1024 * 2; pub(crate) const DEFAULT_H2_STREAM_WINDOW_SIZE: u32 = 1024 * 1024; pub(crate) const DEFAULT_H1_WRITE_BUFFER_SIZE: usize = 32_768;
55
56#[derive(Default, Debug)]
58pub struct ServiceConfigBuilder {
59 inner: Inner,
60}
61
62impl ServiceConfigBuilder {
63 pub fn new() -> Self {
74 Self::default()
75 }
76
77 pub fn secure(mut self, secure: bool) -> Self {
79 self.inner.secure = secure;
80 self
81 }
82
83 pub fn local_addr(mut self, local_addr: Option<SocketAddr>) -> Self {
85 self.inner.local_addr = local_addr;
86 self
87 }
88
89 pub fn keep_alive(mut self, keep_alive: KeepAlive) -> Self {
91 self.inner.keep_alive = keep_alive;
92 self
93 }
94
95 pub fn client_request_timeout(mut self, timeout: Duration) -> Self {
97 self.inner.client_request_timeout = timeout;
98 self
99 }
100
101 pub fn client_disconnect_timeout(mut self, timeout: Duration) -> Self {
104 self.inner.client_disconnect_timeout = timeout;
105 self
106 }
107
108 pub fn tcp_nodelay(mut self, nodelay: Option<bool>) -> Self {
112 self.inner.tcp_nodelay = nodelay;
113 self
114 }
115
116 pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
122 self.inner.h1_allow_half_closed = allow;
123 self
124 }
125
126 pub fn h1_write_buffer_size(mut self, size: usize) -> Self {
136 assert!(
137 size > 0,
138 "HTTP/1 write buffer size must be greater than zero"
139 );
140
141 self.inner.h1_write_buffer_size = size;
142 self
143 }
144
145 pub(crate) fn graceful_shutdown_signal(
146 mut self,
147 signal: Option<GracefulShutdownSignal>,
148 ) -> Self {
149 self.inner.graceful_shutdown_signal = signal;
150 self
151 }
152
153 pub fn h2_initial_window_size(mut self, size: u32) -> Self {
160 self.inner.h2_stream_window_size = size;
161 self
162 }
163
164 pub fn h2_initial_connection_window_size(mut self, size: u32) -> Self {
171 self.inner.h2_conn_window_size = size;
172 self
173 }
174
175 pub fn build(self) -> ServiceConfig {
177 ServiceConfig(Rc::new(self.inner))
178 }
179}
180
181#[derive(Debug, Clone, Default)]
183pub struct ServiceConfig(Rc<Inner>);
184
185#[derive(Debug)]
186struct Inner {
187 keep_alive: KeepAlive,
188 client_request_timeout: Duration,
189 client_disconnect_timeout: Duration,
190 secure: bool,
191 local_addr: Option<SocketAddr>,
192 tcp_nodelay: Option<bool>,
193 date_service: DateService,
194 h1_allow_half_closed: bool,
195 h1_write_buffer_size: usize,
196 h2_conn_window_size: u32,
197 h2_stream_window_size: u32,
198 graceful_shutdown_signal: Option<GracefulShutdownSignal>,
199}
200
201impl Default for Inner {
202 fn default() -> Self {
203 Self {
204 keep_alive: KeepAlive::default(),
205 client_request_timeout: Duration::from_secs(5),
206 client_disconnect_timeout: Duration::ZERO,
207 secure: false,
208 local_addr: None,
209 tcp_nodelay: Some(true),
210 date_service: DateService::new(),
211 h1_allow_half_closed: true,
212 h1_write_buffer_size: DEFAULT_H1_WRITE_BUFFER_SIZE,
213 h2_conn_window_size: DEFAULT_H2_CONN_WINDOW_SIZE,
214 h2_stream_window_size: DEFAULT_H2_STREAM_WINDOW_SIZE,
215 graceful_shutdown_signal: None,
216 }
217 }
218}
219
220impl ServiceConfig {
221 pub fn new(
223 keep_alive: KeepAlive,
224 client_request_timeout: Duration,
225 client_disconnect_timeout: Duration,
226 secure: bool,
227 local_addr: Option<SocketAddr>,
228 ) -> ServiceConfig {
229 ServiceConfig(Rc::new(Inner {
230 keep_alive: keep_alive.normalize(),
231 client_request_timeout,
232 client_disconnect_timeout,
233 secure,
234 local_addr,
235 tcp_nodelay: Some(true),
236 date_service: DateService::new(),
237 h1_allow_half_closed: true,
238 h1_write_buffer_size: DEFAULT_H1_WRITE_BUFFER_SIZE,
239 h2_conn_window_size: DEFAULT_H2_CONN_WINDOW_SIZE,
240 h2_stream_window_size: DEFAULT_H2_STREAM_WINDOW_SIZE,
241 graceful_shutdown_signal: None,
242 }))
243 }
244
245 #[inline]
247 pub fn secure(&self) -> bool {
248 self.0.secure
249 }
250
251 #[inline]
255 pub fn local_addr(&self) -> Option<SocketAddr> {
256 self.0.local_addr
257 }
258
259 #[inline]
261 pub fn keep_alive(&self) -> KeepAlive {
262 self.0.keep_alive
263 }
264
265 pub fn keep_alive_deadline(&self) -> Option<Instant> {
270 match self.keep_alive() {
271 KeepAlive::Timeout(dur) => Some(self.now() + dur),
272 KeepAlive::Os => None,
273 KeepAlive::Disabled => None,
274 }
275 }
276
277 pub fn client_request_deadline(&self) -> Option<Instant> {
282 let timeout = self.0.client_request_timeout;
283 (timeout != Duration::ZERO).then(|| self.now() + timeout)
284 }
285
286 pub fn client_disconnect_deadline(&self) -> Option<Instant> {
288 let timeout = self.0.client_disconnect_timeout;
289 (timeout != Duration::ZERO).then(|| self.now() + timeout)
290 }
291
292 pub fn h1_allow_half_closed(&self) -> bool {
298 self.0.h1_allow_half_closed
299 }
300
301 pub fn h1_write_buffer_size(&self) -> usize {
303 self.0.h1_write_buffer_size
304 }
305
306 pub(crate) fn graceful_shutdown(&self) -> Option<GracefulShutdownFuture> {
307 self.0
308 .graceful_shutdown_signal
309 .as_ref()
310 .map(GracefulShutdownSignal::notified)
311 }
312
313 pub fn tcp_nodelay(&self) -> Option<bool> {
315 self.0.tcp_nodelay
316 }
317
318 pub fn h2_initial_window_size(&self) -> u32 {
320 self.0.h2_stream_window_size
321 }
322
323 pub fn h2_initial_connection_window_size(&self) -> u32 {
325 self.0.h2_conn_window_size
326 }
327
328 pub(crate) fn now(&self) -> Instant {
329 self.0.date_service.now()
330 }
331
332 #[doc(hidden)]
337 pub fn write_date_header(&self, dst: &mut BytesMut, camel_case: bool) {
338 const PREFIX_LEN: usize = 6;
339 const CRLF_LEN: usize = 2;
340 const DATE_HEADER_LEN: usize = PREFIX_LEN + DATE_VALUE_LENGTH + CRLF_LEN;
341
342 let mut buf: [u8; DATE_HEADER_LEN] = [0; DATE_HEADER_LEN];
343
344 buf[..PREFIX_LEN].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
345
346 self.0.date_service.with_date(|date| {
347 buf[PREFIX_LEN..PREFIX_LEN + DATE_VALUE_LENGTH].copy_from_slice(&date.bytes)
348 });
349
350 buf[PREFIX_LEN + DATE_VALUE_LENGTH..].copy_from_slice(b"\r\n");
351 dst.extend_from_slice(&buf);
352 }
353
354 #[allow(unused)] pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
356 self.0
357 .date_service
358 .with_date(|date| dst.extend_from_slice(&date.bytes));
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use memchr::memmem;
365 use tokio::{
366 task::yield_now,
367 time::{sleep, sleep_until},
368 };
369
370 use super::*;
371 use crate::{date::DATE_VALUE_LENGTH, notify_on_drop};
372
373 #[actix_rt::test]
374 async fn test_date_service_update() {
375 let settings =
376 ServiceConfig::new(KeepAlive::Os, Duration::ZERO, Duration::ZERO, false, None);
377
378 yield_now().await;
379
380 let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
381 settings.write_date_header(&mut buf1, false);
382 let now1 = settings.now();
383
384 sleep_until((Instant::now() + Duration::from_secs(2)).into()).await;
385 yield_now().await;
386
387 let now2 = settings.now();
388 let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
389 settings.write_date_header(&mut buf2, false);
390
391 assert_ne!(now1, now2);
392
393 assert_ne!(buf1, buf2);
394
395 drop(settings);
396
397 let mut times = 0;
399 while !notify_on_drop::is_dropped() {
400 sleep(Duration::from_millis(100)).await;
401 times += 1;
402 assert!(times < 10, "Timeout waiting for task drop");
403 }
404 }
405
406 #[actix_rt::test]
407 async fn test_date_service_drop() {
408 let service = Rc::new(DateService::new());
409
410 yield_now().await;
412
413 let clone1 = service.clone();
414 let clone2 = service.clone();
415 let clone3 = service.clone();
416
417 drop(clone1);
418 assert!(!notify_on_drop::is_dropped());
419 drop(clone2);
420 assert!(!notify_on_drop::is_dropped());
421 drop(clone3);
422 assert!(!notify_on_drop::is_dropped());
423
424 drop(service);
425
426 let mut times = 0;
428 while !notify_on_drop::is_dropped() {
429 sleep(Duration::from_millis(100)).await;
430 times += 1;
431 assert!(times < 10, "Timeout waiting for task drop");
432 }
433 }
434
435 #[test]
436 fn test_date_len() {
437 assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
438 }
439
440 #[actix_rt::test]
441 async fn test_date() {
442 let settings = ServiceConfig::default();
443
444 let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
445 settings.write_date_header(&mut buf1, false);
446
447 let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
448 settings.write_date_header(&mut buf2, false);
449
450 assert_eq!(buf1, buf2);
451 }
452
453 #[actix_rt::test]
454 async fn test_date_camel_case() {
455 let settings = ServiceConfig::default();
456
457 let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
458 settings.write_date_header(&mut buf, false);
459 assert!(memmem::find(&buf, b"date:").is_some());
460
461 let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
462 settings.write_date_header(&mut buf, true);
463 assert!(memmem::find(&buf, b"Date:").is_some());
464 }
465}