2021-09-10 23:01:01 +00:00
|
|
|
use std::{
|
|
|
|
net,
|
|
|
|
rc::Rc,
|
2022-01-31 17:30:34 +00:00
|
|
|
time::{Duration, Instant},
|
2021-09-10 23:01:01 +00:00
|
|
|
};
|
2019-03-26 18:54:35 +00:00
|
|
|
|
|
|
|
use bytes::BytesMut;
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
use crate::{date::DateService, KeepAlive};
|
2019-03-26 18:54:35 +00:00
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
/// HTTP service configuration.
|
|
|
|
#[derive(Debug, Clone)]
|
2019-03-26 18:54:35 +00:00
|
|
|
pub struct ServiceConfig(Rc<Inner>);
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
#[derive(Debug)]
|
2019-03-26 18:54:35 +00:00
|
|
|
struct Inner {
|
2022-01-31 17:30:34 +00:00
|
|
|
keep_alive: KeepAlive,
|
|
|
|
client_request_timeout: Duration,
|
|
|
|
client_disconnect_timeout: Duration,
|
2019-12-02 11:33:11 +00:00
|
|
|
secure: bool,
|
|
|
|
local_addr: Option<std::net::SocketAddr>,
|
2021-02-12 21:52:58 +00:00
|
|
|
date_service: DateService,
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ServiceConfig {
|
|
|
|
fn default() -> Self {
|
2022-01-31 17:30:34 +00:00
|
|
|
Self::new(
|
|
|
|
KeepAlive::default(),
|
|
|
|
Duration::from_secs(5),
|
|
|
|
Duration::ZERO,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
)
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ServiceConfig {
|
2022-07-24 15:42:35 +00:00
|
|
|
/// Create instance of `ServiceConfig`.
|
2019-03-26 18:54:35 +00:00
|
|
|
pub fn new(
|
|
|
|
keep_alive: KeepAlive,
|
2022-01-31 17:30:34 +00:00
|
|
|
client_request_timeout: Duration,
|
|
|
|
client_disconnect_timeout: Duration,
|
2019-12-02 11:33:11 +00:00
|
|
|
secure: bool,
|
|
|
|
local_addr: Option<net::SocketAddr>,
|
2019-03-26 18:54:35 +00:00
|
|
|
) -> ServiceConfig {
|
|
|
|
ServiceConfig(Rc::new(Inner {
|
2022-01-31 17:30:34 +00:00
|
|
|
keep_alive: keep_alive.normalize(),
|
|
|
|
client_request_timeout,
|
|
|
|
client_disconnect_timeout,
|
2019-12-02 11:33:11 +00:00
|
|
|
secure,
|
|
|
|
local_addr,
|
2021-02-12 21:52:58 +00:00
|
|
|
date_service: DateService::new(),
|
2019-03-26 18:54:35 +00:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
/// Returns `true` if connection is secure (i.e., using TLS / HTTPS).
|
2019-12-02 11:33:11 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn secure(&self) -> bool {
|
|
|
|
self.0.secure
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the local address that this server is bound to.
|
2021-07-12 15:55:24 +00:00
|
|
|
///
|
|
|
|
/// Returns `None` for connections via UDS (Unix Domain Socket).
|
2021-02-11 22:39:54 +00:00
|
|
|
#[inline]
|
2019-12-02 11:33:11 +00:00
|
|
|
pub fn local_addr(&self) -> Option<net::SocketAddr> {
|
|
|
|
self.0.local_addr
|
|
|
|
}
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
/// Connection keep-alive setting.
|
2021-02-11 22:39:54 +00:00
|
|
|
#[inline]
|
2022-01-31 17:30:34 +00:00
|
|
|
pub fn keep_alive(&self) -> KeepAlive {
|
2019-03-26 18:54:35 +00:00
|
|
|
self.0.keep_alive
|
|
|
|
}
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
/// Creates a time object representing the deadline for this connection's keep-alive period, if
|
|
|
|
/// enabled.
|
|
|
|
///
|
|
|
|
/// When [`KeepAlive::Os`] or [`KeepAlive::Disabled`] is set, this will return `None`.
|
|
|
|
pub fn keep_alive_deadline(&self) -> Option<Instant> {
|
|
|
|
match self.keep_alive() {
|
|
|
|
KeepAlive::Timeout(dur) => Some(self.now() + dur),
|
|
|
|
KeepAlive::Os => None,
|
|
|
|
KeepAlive::Disabled => None,
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
/// Creates a time object representing the deadline for the client to finish sending the head of
|
|
|
|
/// its first request.
|
|
|
|
///
|
|
|
|
/// Returns `None` if this `ServiceConfig was` constructed with `client_request_timeout: 0`.
|
|
|
|
pub fn client_request_deadline(&self) -> Option<Instant> {
|
|
|
|
let timeout = self.0.client_request_timeout;
|
|
|
|
(timeout != Duration::ZERO).then(|| self.now() + timeout)
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
/// Creates a time object representing the deadline for the client to disconnect.
|
|
|
|
pub fn client_disconnect_deadline(&self) -> Option<Instant> {
|
|
|
|
let timeout = self.0.client_disconnect_timeout;
|
|
|
|
(timeout != Duration::ZERO).then(|| self.now() + timeout)
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn now(&self) -> Instant {
|
2021-02-12 21:52:58 +00:00
|
|
|
self.0.date_service.now()
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 20:37:33 +00:00
|
|
|
/// Writes date header to `dst` buffer.
|
|
|
|
///
|
|
|
|
/// Low-level method that utilizes the built-in efficient date service, requiring fewer syscalls
|
|
|
|
/// than normal. Note that a CRLF (`\r\n`) is included in what is written.
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub fn write_date_header(&self, dst: &mut BytesMut, camel_case: bool) {
|
|
|
|
let mut buf: [u8; 37] = [0; 37];
|
2022-01-21 20:15:43 +00:00
|
|
|
|
|
|
|
buf[..6].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
|
|
|
|
|
2019-07-18 11:37:41 +00:00
|
|
|
self.0
|
2021-02-12 21:52:58 +00:00
|
|
|
.date_service
|
2022-01-31 17:30:34 +00:00
|
|
|
.with_date(|date| buf[6..35].copy_from_slice(&date.bytes));
|
2022-01-21 20:15:43 +00:00
|
|
|
|
2022-02-04 20:37:33 +00:00
|
|
|
buf[35..].copy_from_slice(b"\r\n");
|
2019-03-26 18:54:35 +00:00
|
|
|
dst.extend_from_slice(&buf);
|
|
|
|
}
|
|
|
|
|
2022-01-31 21:22:23 +00:00
|
|
|
#[allow(unused)] // used with `http2` feature flag
|
2022-01-31 17:30:34 +00:00
|
|
|
pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
|
2019-07-18 11:37:41 +00:00
|
|
|
self.0
|
2021-02-12 21:52:58 +00:00
|
|
|
.date_service
|
2022-01-31 17:30:34 +00:00
|
|
|
.with_date(|date| dst.extend_from_slice(&date.bytes));
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-01-31 17:30:34 +00:00
|
|
|
use actix_rt::{
|
|
|
|
task::yield_now,
|
|
|
|
time::{sleep, sleep_until},
|
|
|
|
};
|
2022-01-21 20:15:43 +00:00
|
|
|
use memchr::memmem;
|
2021-02-12 21:52:58 +00:00
|
|
|
|
2023-07-17 01:38:12 +00:00
|
|
|
use super::*;
|
|
|
|
use crate::{date::DATE_VALUE_LENGTH, notify_on_drop};
|
|
|
|
|
2021-02-12 21:52:58 +00:00
|
|
|
#[actix_rt::test]
|
|
|
|
async fn test_date_service_update() {
|
2022-01-31 17:30:34 +00:00
|
|
|
let settings =
|
|
|
|
ServiceConfig::new(KeepAlive::Os, Duration::ZERO, Duration::ZERO, false, None);
|
2021-02-12 21:52:58 +00:00
|
|
|
|
|
|
|
yield_now().await;
|
|
|
|
|
|
|
|
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
2022-01-31 17:30:34 +00:00
|
|
|
settings.write_date_header(&mut buf1, false);
|
2021-02-12 21:52:58 +00:00
|
|
|
let now1 = settings.now();
|
|
|
|
|
2022-01-31 17:30:34 +00:00
|
|
|
sleep_until((Instant::now() + Duration::from_secs(2)).into()).await;
|
2021-02-12 21:52:58 +00:00
|
|
|
yield_now().await;
|
|
|
|
|
|
|
|
let now2 = settings.now();
|
|
|
|
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
2022-01-31 17:30:34 +00:00
|
|
|
settings.write_date_header(&mut buf2, false);
|
2021-02-12 21:52:58 +00:00
|
|
|
|
|
|
|
assert_ne!(now1, now2);
|
|
|
|
|
|
|
|
assert_ne!(buf1, buf2);
|
|
|
|
|
|
|
|
drop(settings);
|
2021-07-09 22:57:21 +00:00
|
|
|
|
|
|
|
// Ensure the task will drop eventually
|
|
|
|
let mut times = 0;
|
|
|
|
while !notify_on_drop::is_dropped() {
|
|
|
|
sleep(Duration::from_millis(100)).await;
|
|
|
|
times += 1;
|
|
|
|
assert!(times < 10, "Timeout waiting for task drop");
|
|
|
|
}
|
2021-02-12 21:52:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn test_date_service_drop() {
|
|
|
|
let service = Rc::new(DateService::new());
|
|
|
|
|
|
|
|
// yield so date service have a chance to register the spawned timer update task.
|
|
|
|
yield_now().await;
|
|
|
|
|
|
|
|
let clone1 = service.clone();
|
|
|
|
let clone2 = service.clone();
|
|
|
|
let clone3 = service.clone();
|
|
|
|
|
|
|
|
drop(clone1);
|
2021-06-26 14:33:43 +00:00
|
|
|
assert!(!notify_on_drop::is_dropped());
|
2021-02-12 21:52:58 +00:00
|
|
|
drop(clone2);
|
2021-06-26 14:33:43 +00:00
|
|
|
assert!(!notify_on_drop::is_dropped());
|
2021-02-12 21:52:58 +00:00
|
|
|
drop(clone3);
|
2021-06-26 14:33:43 +00:00
|
|
|
assert!(!notify_on_drop::is_dropped());
|
2021-02-12 21:52:58 +00:00
|
|
|
|
|
|
|
drop(service);
|
2021-07-09 22:57:21 +00:00
|
|
|
|
|
|
|
// Ensure the task will drop eventually
|
|
|
|
let mut times = 0;
|
|
|
|
while !notify_on_drop::is_dropped() {
|
|
|
|
sleep(Duration::from_millis(100)).await;
|
|
|
|
times += 1;
|
|
|
|
assert!(times < 10, "Timeout waiting for task drop");
|
|
|
|
}
|
2020-01-29 12:05:08 +00:00
|
|
|
}
|
|
|
|
|
2019-03-26 18:54:35 +00:00
|
|
|
#[test]
|
|
|
|
fn test_date_len() {
|
|
|
|
assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
|
|
|
|
}
|
|
|
|
|
2019-11-26 05:25:50 +00:00
|
|
|
#[actix_rt::test]
|
|
|
|
async fn test_date() {
|
2022-01-21 20:15:43 +00:00
|
|
|
let settings = ServiceConfig::default();
|
|
|
|
|
2019-11-26 05:25:50 +00:00
|
|
|
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
2022-01-31 17:30:34 +00:00
|
|
|
settings.write_date_header(&mut buf1, false);
|
2022-01-21 20:15:43 +00:00
|
|
|
|
2019-11-26 05:25:50 +00:00
|
|
|
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
2022-01-31 17:30:34 +00:00
|
|
|
settings.write_date_header(&mut buf2, false);
|
2022-01-21 20:15:43 +00:00
|
|
|
|
2019-11-26 05:25:50 +00:00
|
|
|
assert_eq!(buf1, buf2);
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|
2022-01-21 20:15:43 +00:00
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn test_date_camel_case() {
|
|
|
|
let settings = ServiceConfig::default();
|
|
|
|
|
|
|
|
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
2022-01-31 17:30:34 +00:00
|
|
|
settings.write_date_header(&mut buf, false);
|
2022-01-21 20:15:43 +00:00
|
|
|
assert!(memmem::find(&buf, b"date:").is_some());
|
|
|
|
|
|
|
|
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
2022-01-31 17:30:34 +00:00
|
|
|
settings.write_date_header(&mut buf, true);
|
2022-01-21 20:15:43 +00:00
|
|
|
assert!(memmem::find(&buf, b"Date:").is_some());
|
|
|
|
}
|
2019-03-26 18:54:35 +00:00
|
|
|
}
|