1use std::{
2 net,
3 rc::Rc,
4 time::{Duration, Instant},
5};
6
7use bytes::BytesMut;
8
9use crate::{date::DateService, KeepAlive};
10
11#[derive(Debug, Clone)]
13pub struct ServiceConfig(Rc<Inner>);
14
15#[derive(Debug)]
16struct Inner {
17 keep_alive: KeepAlive,
18 client_request_timeout: Duration,
19 client_disconnect_timeout: Duration,
20 secure: bool,
21 local_addr: Option<std::net::SocketAddr>,
22 date_service: DateService,
23}
24
25impl Default for ServiceConfig {
26 fn default() -> Self {
27 Self::new(
28 KeepAlive::default(),
29 Duration::from_secs(5),
30 Duration::ZERO,
31 false,
32 None,
33 )
34 }
35}
36
37impl ServiceConfig {
38 pub fn new(
40 keep_alive: KeepAlive,
41 client_request_timeout: Duration,
42 client_disconnect_timeout: Duration,
43 secure: bool,
44 local_addr: Option<net::SocketAddr>,
45 ) -> ServiceConfig {
46 ServiceConfig(Rc::new(Inner {
47 keep_alive: keep_alive.normalize(),
48 client_request_timeout,
49 client_disconnect_timeout,
50 secure,
51 local_addr,
52 date_service: DateService::new(),
53 }))
54 }
55
56 #[inline]
58 pub fn secure(&self) -> bool {
59 self.0.secure
60 }
61
62 #[inline]
66 pub fn local_addr(&self) -> Option<net::SocketAddr> {
67 self.0.local_addr
68 }
69
70 #[inline]
72 pub fn keep_alive(&self) -> KeepAlive {
73 self.0.keep_alive
74 }
75
76 pub fn keep_alive_deadline(&self) -> Option<Instant> {
81 match self.keep_alive() {
82 KeepAlive::Timeout(dur) => Some(self.now() + dur),
83 KeepAlive::Os => None,
84 KeepAlive::Disabled => None,
85 }
86 }
87
88 pub fn client_request_deadline(&self) -> Option<Instant> {
93 let timeout = self.0.client_request_timeout;
94 (timeout != Duration::ZERO).then(|| self.now() + timeout)
95 }
96
97 pub fn client_disconnect_deadline(&self) -> Option<Instant> {
99 let timeout = self.0.client_disconnect_timeout;
100 (timeout != Duration::ZERO).then(|| self.now() + timeout)
101 }
102
103 pub(crate) fn now(&self) -> Instant {
104 self.0.date_service.now()
105 }
106
107 #[doc(hidden)]
112 pub fn write_date_header(&self, dst: &mut BytesMut, camel_case: bool) {
113 let mut buf: [u8; 37] = [0; 37];
114
115 buf[..6].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
116
117 self.0
118 .date_service
119 .with_date(|date| buf[6..35].copy_from_slice(&date.bytes));
120
121 buf[35..].copy_from_slice(b"\r\n");
122 dst.extend_from_slice(&buf);
123 }
124
125 #[allow(unused)] pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
127 self.0
128 .date_service
129 .with_date(|date| dst.extend_from_slice(&date.bytes));
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use actix_rt::{
136 task::yield_now,
137 time::{sleep, sleep_until},
138 };
139 use memchr::memmem;
140
141 use super::*;
142 use crate::{date::DATE_VALUE_LENGTH, notify_on_drop};
143
144 #[actix_rt::test]
145 async fn test_date_service_update() {
146 let settings =
147 ServiceConfig::new(KeepAlive::Os, Duration::ZERO, Duration::ZERO, false, None);
148
149 yield_now().await;
150
151 let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
152 settings.write_date_header(&mut buf1, false);
153 let now1 = settings.now();
154
155 sleep_until((Instant::now() + Duration::from_secs(2)).into()).await;
156 yield_now().await;
157
158 let now2 = settings.now();
159 let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
160 settings.write_date_header(&mut buf2, false);
161
162 assert_ne!(now1, now2);
163
164 assert_ne!(buf1, buf2);
165
166 drop(settings);
167
168 let mut times = 0;
170 while !notify_on_drop::is_dropped() {
171 sleep(Duration::from_millis(100)).await;
172 times += 1;
173 assert!(times < 10, "Timeout waiting for task drop");
174 }
175 }
176
177 #[actix_rt::test]
178 async fn test_date_service_drop() {
179 let service = Rc::new(DateService::new());
180
181 yield_now().await;
183
184 let clone1 = service.clone();
185 let clone2 = service.clone();
186 let clone3 = service.clone();
187
188 drop(clone1);
189 assert!(!notify_on_drop::is_dropped());
190 drop(clone2);
191 assert!(!notify_on_drop::is_dropped());
192 drop(clone3);
193 assert!(!notify_on_drop::is_dropped());
194
195 drop(service);
196
197 let mut times = 0;
199 while !notify_on_drop::is_dropped() {
200 sleep(Duration::from_millis(100)).await;
201 times += 1;
202 assert!(times < 10, "Timeout waiting for task drop");
203 }
204 }
205
206 #[test]
207 fn test_date_len() {
208 assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
209 }
210
211 #[actix_rt::test]
212 async fn test_date() {
213 let settings = ServiceConfig::default();
214
215 let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
216 settings.write_date_header(&mut buf1, false);
217
218 let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
219 settings.write_date_header(&mut buf2, false);
220
221 assert_eq!(buf1, buf2);
222 }
223
224 #[actix_rt::test]
225 async fn test_date_camel_case() {
226 let settings = ServiceConfig::default();
227
228 let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
229 settings.write_date_header(&mut buf, false);
230 assert!(memmem::find(&buf, b"date:").is_some());
231
232 let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
233 settings.write_date_header(&mut buf, true);
234 assert!(memmem::find(&buf, b"Date:").is_some());
235 }
236}