1use std::{
2 net::SocketAddr,
3 rc::Rc,
4 time::{Duration, Instant},
5};
6
7use bytes::BytesMut;
8
9use crate::{date::DateService, KeepAlive};
10
11pub(crate) const DEFAULT_H2_CONN_WINDOW_SIZE: u32 = 1024 * 1024 * 2; pub(crate) const DEFAULT_H2_STREAM_WINDOW_SIZE: u32 = 1024 * 1024; #[derive(Default, Debug)]
23pub struct ServiceConfigBuilder {
24 inner: Inner,
25}
26
27impl ServiceConfigBuilder {
28 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn secure(mut self, secure: bool) -> Self {
44 self.inner.secure = secure;
45 self
46 }
47
48 pub fn local_addr(mut self, local_addr: Option<SocketAddr>) -> Self {
50 self.inner.local_addr = local_addr;
51 self
52 }
53
54 pub fn keep_alive(mut self, keep_alive: KeepAlive) -> Self {
56 self.inner.keep_alive = keep_alive;
57 self
58 }
59
60 pub fn client_request_timeout(mut self, timeout: Duration) -> Self {
62 self.inner.client_request_timeout = timeout;
63 self
64 }
65
66 pub fn client_disconnect_timeout(mut self, timeout: Duration) -> Self {
69 self.inner.client_disconnect_timeout = timeout;
70 self
71 }
72
73 pub fn tcp_nodelay(mut self, nodelay: Option<bool>) -> Self {
75 self.inner.tcp_nodelay = nodelay;
76 self
77 }
78
79 pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
85 self.inner.h1_allow_half_closed = allow;
86 self
87 }
88
89 pub fn h2_initial_window_size(mut self, size: u32) -> Self {
96 self.inner.h2_stream_window_size = size;
97 self
98 }
99
100 pub fn h2_initial_connection_window_size(mut self, size: u32) -> Self {
107 self.inner.h2_conn_window_size = size;
108 self
109 }
110
111 pub fn build(self) -> ServiceConfig {
113 ServiceConfig(Rc::new(self.inner))
114 }
115}
116
117#[derive(Debug, Clone, Default)]
119pub struct ServiceConfig(Rc<Inner>);
120
121#[derive(Debug)]
122struct Inner {
123 keep_alive: KeepAlive,
124 client_request_timeout: Duration,
125 client_disconnect_timeout: Duration,
126 secure: bool,
127 local_addr: Option<SocketAddr>,
128 tcp_nodelay: Option<bool>,
129 date_service: DateService,
130 h1_allow_half_closed: bool,
131 h2_conn_window_size: u32,
132 h2_stream_window_size: u32,
133}
134
135impl Default for Inner {
136 fn default() -> Self {
137 Self {
138 keep_alive: KeepAlive::default(),
139 client_request_timeout: Duration::from_secs(5),
140 client_disconnect_timeout: Duration::ZERO,
141 secure: false,
142 local_addr: None,
143 tcp_nodelay: None,
144 date_service: DateService::new(),
145 h1_allow_half_closed: true,
146 h2_conn_window_size: DEFAULT_H2_CONN_WINDOW_SIZE,
147 h2_stream_window_size: DEFAULT_H2_STREAM_WINDOW_SIZE,
148 }
149 }
150}
151
152impl ServiceConfig {
153 pub fn new(
155 keep_alive: KeepAlive,
156 client_request_timeout: Duration,
157 client_disconnect_timeout: Duration,
158 secure: bool,
159 local_addr: Option<SocketAddr>,
160 ) -> ServiceConfig {
161 ServiceConfig(Rc::new(Inner {
162 keep_alive: keep_alive.normalize(),
163 client_request_timeout,
164 client_disconnect_timeout,
165 secure,
166 local_addr,
167 tcp_nodelay: None,
168 date_service: DateService::new(),
169 h1_allow_half_closed: true,
170 h2_conn_window_size: DEFAULT_H2_CONN_WINDOW_SIZE,
171 h2_stream_window_size: DEFAULT_H2_STREAM_WINDOW_SIZE,
172 }))
173 }
174
175 #[inline]
177 pub fn secure(&self) -> bool {
178 self.0.secure
179 }
180
181 #[inline]
185 pub fn local_addr(&self) -> Option<SocketAddr> {
186 self.0.local_addr
187 }
188
189 #[inline]
191 pub fn keep_alive(&self) -> KeepAlive {
192 self.0.keep_alive
193 }
194
195 pub fn keep_alive_deadline(&self) -> Option<Instant> {
200 match self.keep_alive() {
201 KeepAlive::Timeout(dur) => Some(self.now() + dur),
202 KeepAlive::Os => None,
203 KeepAlive::Disabled => None,
204 }
205 }
206
207 pub fn client_request_deadline(&self) -> Option<Instant> {
212 let timeout = self.0.client_request_timeout;
213 (timeout != Duration::ZERO).then(|| self.now() + timeout)
214 }
215
216 pub fn client_disconnect_deadline(&self) -> Option<Instant> {
218 let timeout = self.0.client_disconnect_timeout;
219 (timeout != Duration::ZERO).then(|| self.now() + timeout)
220 }
221
222 pub fn h1_allow_half_closed(&self) -> bool {
228 self.0.h1_allow_half_closed
229 }
230
231 pub fn tcp_nodelay(&self) -> Option<bool> {
233 self.0.tcp_nodelay
234 }
235
236 pub fn h2_initial_window_size(&self) -> u32 {
238 self.0.h2_stream_window_size
239 }
240
241 pub fn h2_initial_connection_window_size(&self) -> u32 {
243 self.0.h2_conn_window_size
244 }
245
246 pub(crate) fn now(&self) -> Instant {
247 self.0.date_service.now()
248 }
249
250 #[doc(hidden)]
255 pub fn write_date_header(&self, dst: &mut BytesMut, camel_case: bool) {
256 let mut buf: [u8; 37] = [0; 37];
257
258 buf[..6].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
259
260 self.0
261 .date_service
262 .with_date(|date| buf[6..35].copy_from_slice(&date.bytes));
263
264 buf[35..].copy_from_slice(b"\r\n");
265 dst.extend_from_slice(&buf);
266 }
267
268 #[allow(unused)] pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
270 self.0
271 .date_service
272 .with_date(|date| dst.extend_from_slice(&date.bytes));
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use actix_rt::{
279 task::yield_now,
280 time::{sleep, sleep_until},
281 };
282 use memchr::memmem;
283
284 use super::*;
285 use crate::{date::DATE_VALUE_LENGTH, notify_on_drop};
286
287 #[actix_rt::test]
288 async fn test_date_service_update() {
289 let settings =
290 ServiceConfig::new(KeepAlive::Os, Duration::ZERO, Duration::ZERO, false, None);
291
292 yield_now().await;
293
294 let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
295 settings.write_date_header(&mut buf1, false);
296 let now1 = settings.now();
297
298 sleep_until((Instant::now() + Duration::from_secs(2)).into()).await;
299 yield_now().await;
300
301 let now2 = settings.now();
302 let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
303 settings.write_date_header(&mut buf2, false);
304
305 assert_ne!(now1, now2);
306
307 assert_ne!(buf1, buf2);
308
309 drop(settings);
310
311 let mut times = 0;
313 while !notify_on_drop::is_dropped() {
314 sleep(Duration::from_millis(100)).await;
315 times += 1;
316 assert!(times < 10, "Timeout waiting for task drop");
317 }
318 }
319
320 #[actix_rt::test]
321 async fn test_date_service_drop() {
322 let service = Rc::new(DateService::new());
323
324 yield_now().await;
326
327 let clone1 = service.clone();
328 let clone2 = service.clone();
329 let clone3 = service.clone();
330
331 drop(clone1);
332 assert!(!notify_on_drop::is_dropped());
333 drop(clone2);
334 assert!(!notify_on_drop::is_dropped());
335 drop(clone3);
336 assert!(!notify_on_drop::is_dropped());
337
338 drop(service);
339
340 let mut times = 0;
342 while !notify_on_drop::is_dropped() {
343 sleep(Duration::from_millis(100)).await;
344 times += 1;
345 assert!(times < 10, "Timeout waiting for task drop");
346 }
347 }
348
349 #[test]
350 fn test_date_len() {
351 assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
352 }
353
354 #[actix_rt::test]
355 async fn test_date() {
356 let settings = ServiceConfig::default();
357
358 let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
359 settings.write_date_header(&mut buf1, false);
360
361 let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
362 settings.write_date_header(&mut buf2, false);
363
364 assert_eq!(buf1, buf2);
365 }
366
367 #[actix_rt::test]
368 async fn test_date_camel_case() {
369 let settings = ServiceConfig::default();
370
371 let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
372 settings.write_date_header(&mut buf, false);
373 assert!(memmem::find(&buf, b"date:").is_some());
374
375 let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
376 settings.write_date_header(&mut buf, true);
377 assert!(memmem::find(&buf, b"Date:").is_some());
378 }
379}