mirror of https://github.com/fafhrd91/actix-web
split out config module
This commit is contained in:
parent
312e415cd4
commit
28b27552e9
|
@ -3,24 +3,26 @@
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
### Added
|
### Added
|
||||||
- Implement `Default` for `KeepAlive`. [#2611]
|
- Implement `Default` for `KeepAlive`. [#2611]
|
||||||
- Implement `From<Option<Duration>> for KeepAlive`. [#2611]
|
- Implement `From<Duration>` for `KeepAlive`. [#2611]
|
||||||
|
- Implement `From<Option<Duration>>` for `KeepAlive`. [#2611]
|
||||||
|
- Implement `Default` for `HttpServiceBuilder`. [#2611]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Rename `ServiceConfig::{client_timer_expire => client_request_deadline}`. [#2611]
|
- Rename `ServiceConfig::{client_timer_expire => client_request_deadline}`. [#2611]
|
||||||
- Rename `ServiceConfig::{client_timer => client_request_timer}`. [#2611]
|
|
||||||
- Rename `ServiceConfig::{client_disconnect_timer => client_disconnect_deadline}`. [#2611]
|
- Rename `ServiceConfig::{client_disconnect_timer => client_disconnect_deadline}`. [#2611]
|
||||||
- Rename `ServiceConfig::{keep_alive_timer => keep_alive_deadline}`. [#2611]
|
|
||||||
- Deadline methods in `ServiceConfig` now return `std::time::Instant`s instead of Tokio's wrapper type. [#2611]
|
- Deadline methods in `ServiceConfig` now return `std::time::Instant`s instead of Tokio's wrapper type. [#2611]
|
||||||
- Rename `h1::Codec::{keepalive => keep_alive}`. [#2611]
|
- Rename `h1::Codec::{keepalive => keep_alive}`. [#2611]
|
||||||
- Rename `h1::Codec::{keepalive_enabled => keep_alive_enabled}`. [#2611]
|
- Rename `h1::Codec::{keepalive_enabled => keep_alive_enabled}`. [#2611]
|
||||||
- `HttpServiceBuilder::keep_alive` now receives a `Duration` instead of an integer number of seconds. [#2611]
|
- `ServiceConfig::keep_alive` now returns a `KeepAlive`. [#2611]
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- HTTP/1.1 dispatcher correctly uses client request timeout. [#2611]
|
- HTTP/1.1 dispatcher correctly uses client request timeout. [#2611]
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
- `ServiceConfig::{client_timer, keep_alive_timer}`. [#2611]
|
||||||
- `impl From<usize> for KeepAlive`; use `Duration`s instead. [#2611]
|
- `impl From<usize> for KeepAlive`; use `Duration`s instead. [#2611]
|
||||||
- `impl From<Option<usize>> for KeepAlive`; use `Duration`s instead. [#2611]
|
- `impl From<Option<usize>> for KeepAlive`; use `Duration`s instead. [#2611]
|
||||||
|
- `HttpServiceBuilder::new`; use `default` instead. [#2611]
|
||||||
|
|
||||||
[#2611]: https://github.com/actix/actix-web/pull/2611
|
[#2611]: https://github.com/actix/actix-web/pull/2611
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
|
||||||
fmt::{self, Write},
|
|
||||||
net,
|
net,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
time::{Duration, Instant, SystemTime},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_rt::{task::JoinHandle, time::interval};
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
|
|
||||||
use crate::KeepAlive;
|
use crate::{date::DateService, KeepAlive};
|
||||||
|
|
||||||
/// "Thu, 01 Jan 1970 00:00:00 GMT".len()
|
|
||||||
pub(crate) const DATE_VALUE_LENGTH: usize = 29;
|
|
||||||
|
|
||||||
/// HTTP service configuration.
|
/// HTTP service configuration.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -49,14 +43,8 @@ impl ServiceConfig {
|
||||||
secure: bool,
|
secure: bool,
|
||||||
local_addr: Option<net::SocketAddr>,
|
local_addr: Option<net::SocketAddr>,
|
||||||
) -> ServiceConfig {
|
) -> ServiceConfig {
|
||||||
// zero timeout keep-alive maps to disabled
|
|
||||||
let keep_alive = match keep_alive {
|
|
||||||
KeepAlive::Timeout(Duration::ZERO) => KeepAlive::Disabled,
|
|
||||||
ka => ka,
|
|
||||||
};
|
|
||||||
|
|
||||||
ServiceConfig(Rc::new(Inner {
|
ServiceConfig(Rc::new(Inner {
|
||||||
keep_alive,
|
keep_alive: keep_alive.normalize(),
|
||||||
client_request_timeout,
|
client_request_timeout,
|
||||||
client_disconnect_timeout,
|
client_disconnect_timeout,
|
||||||
secure,
|
secure,
|
||||||
|
@ -126,164 +114,30 @@ impl ServiceConfig {
|
||||||
self.0.date_service.now()
|
self.0.date_service.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_date(&self, dst: &mut BytesMut, camel_case: bool) {
|
pub(crate) fn write_date_header(&self, dst: &mut BytesMut, camel_case: bool) {
|
||||||
let mut buf: [u8; 39] = [0; 39];
|
let mut buf: [u8; 39] = [0; 39];
|
||||||
|
|
||||||
buf[..6].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
|
buf[..6].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.date_service
|
.date_service
|
||||||
.set_date(|date| buf[6..35].copy_from_slice(&date.bytes));
|
.with_date(|date| buf[6..35].copy_from_slice(&date.bytes));
|
||||||
|
|
||||||
buf[35..].copy_from_slice(b"\r\n\r\n");
|
buf[35..].copy_from_slice(b"\r\n\r\n");
|
||||||
dst.extend_from_slice(&buf);
|
dst.extend_from_slice(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_date_header(&self, dst: &mut BytesMut) {
|
pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
|
||||||
self.0
|
self.0
|
||||||
.date_service
|
.date_service
|
||||||
.set_date(|date| dst.extend_from_slice(&date.bytes));
|
.with_date(|date| dst.extend_from_slice(&date.bytes));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
struct Date {
|
|
||||||
bytes: [u8; DATE_VALUE_LENGTH],
|
|
||||||
pos: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Date {
|
|
||||||
fn new() -> Date {
|
|
||||||
let mut date = Date {
|
|
||||||
bytes: [0; DATE_VALUE_LENGTH],
|
|
||||||
pos: 0,
|
|
||||||
};
|
|
||||||
date.update();
|
|
||||||
date
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.pos = 0;
|
|
||||||
write!(self, "{}", httpdate::fmt_http_date(SystemTime::now())).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Write for Date {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
let len = s.len();
|
|
||||||
self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
|
|
||||||
self.pos += len;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Service for update Date and Instant periodically at 500 millis interval.
|
|
||||||
struct DateService {
|
|
||||||
current: Rc<Cell<(Date, Instant)>>,
|
|
||||||
handle: JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DateService {
|
|
||||||
fn new() -> Self {
|
|
||||||
// shared date and timer for DateService and update async task.
|
|
||||||
let current = Rc::new(Cell::new((Date::new(), Instant::now())));
|
|
||||||
let current_clone = Rc::clone(¤t);
|
|
||||||
// spawn an async task sleep for 500 millis and update current date/timer in a loop.
|
|
||||||
// handle is used to stop the task on DateService drop.
|
|
||||||
let handle = actix_rt::spawn(async move {
|
|
||||||
#[cfg(test)]
|
|
||||||
let _notify = notify_on_drop::NotifyOnDrop::new();
|
|
||||||
|
|
||||||
let mut interval = interval(Duration::from_millis(500));
|
|
||||||
loop {
|
|
||||||
let now = interval.tick().await;
|
|
||||||
let date = Date::new();
|
|
||||||
current_clone.set((date, now.into_std()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DateService { current, handle }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn now(&self) -> Instant {
|
|
||||||
self.current.get().1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_date<F: FnMut(&Date)>(&self, mut f: F) {
|
|
||||||
f(&self.current.get().0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for DateService {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("DateService").finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for DateService {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// stop the timer update async task on drop.
|
|
||||||
self.handle.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: move to a util module for testing all spawn handle drop style tasks.
|
|
||||||
/// Test Module for checking the drop state of certain async tasks that are spawned
|
|
||||||
/// with `actix_rt::spawn`
|
|
||||||
///
|
|
||||||
/// The target task must explicitly generate `NotifyOnDrop` when spawn the task
|
|
||||||
#[cfg(test)]
|
|
||||||
mod notify_on_drop {
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
static NOTIFY_DROPPED: RefCell<Option<bool>> = RefCell::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the spawned task is dropped.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// Panics when there was no `NotifyOnDrop` instance on current thread.
|
|
||||||
pub(crate) fn is_dropped() -> bool {
|
|
||||||
NOTIFY_DROPPED.with(|bool| {
|
|
||||||
bool.borrow()
|
|
||||||
.expect("No NotifyOnDrop existed on current thread")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct NotifyOnDrop;
|
|
||||||
|
|
||||||
impl NotifyOnDrop {
|
|
||||||
/// # Panics
|
|
||||||
/// Panics hen construct multiple instances on any given thread.
|
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
NOTIFY_DROPPED.with(|bool| {
|
|
||||||
let mut bool = bool.borrow_mut();
|
|
||||||
if bool.is_some() {
|
|
||||||
panic!("NotifyOnDrop existed on current thread");
|
|
||||||
} else {
|
|
||||||
*bool = Some(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
NotifyOnDrop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for NotifyOnDrop {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
NOTIFY_DROPPED.with(|bool| {
|
|
||||||
if let Some(b) = bool.borrow_mut().as_mut() {
|
|
||||||
*b = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::{date::DATE_VALUE_LENGTH, notify_on_drop};
|
||||||
|
|
||||||
use actix_rt::{
|
use actix_rt::{
|
||||||
task::yield_now,
|
task::yield_now,
|
||||||
|
@ -299,7 +153,7 @@ mod tests {
|
||||||
yield_now().await;
|
yield_now().await;
|
||||||
|
|
||||||
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf1, false);
|
settings.write_date_header(&mut buf1, false);
|
||||||
let now1 = settings.now();
|
let now1 = settings.now();
|
||||||
|
|
||||||
sleep_until((Instant::now() + Duration::from_secs(2)).into()).await;
|
sleep_until((Instant::now() + Duration::from_secs(2)).into()).await;
|
||||||
|
@ -307,7 +161,7 @@ mod tests {
|
||||||
|
|
||||||
let now2 = settings.now();
|
let now2 = settings.now();
|
||||||
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf2, false);
|
settings.write_date_header(&mut buf2, false);
|
||||||
|
|
||||||
assert_ne!(now1, now2);
|
assert_ne!(now1, now2);
|
||||||
|
|
||||||
|
@ -363,10 +217,10 @@ mod tests {
|
||||||
let settings = ServiceConfig::default();
|
let settings = ServiceConfig::default();
|
||||||
|
|
||||||
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf1, false);
|
settings.write_date_header(&mut buf1, false);
|
||||||
|
|
||||||
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf2, false);
|
settings.write_date_header(&mut buf2, false);
|
||||||
|
|
||||||
assert_eq!(buf1, buf2);
|
assert_eq!(buf1, buf2);
|
||||||
}
|
}
|
||||||
|
@ -376,11 +230,11 @@ mod tests {
|
||||||
let settings = ServiceConfig::default();
|
let settings = ServiceConfig::default();
|
||||||
|
|
||||||
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf, false);
|
settings.write_date_header(&mut buf, false);
|
||||||
assert!(memmem::find(&buf, b"date:").is_some());
|
assert!(memmem::find(&buf, b"date:").is_some());
|
||||||
|
|
||||||
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf, true);
|
settings.write_date_header(&mut buf, true);
|
||||||
assert!(memmem::find(&buf, b"Date:").is_some());
|
assert!(memmem::find(&buf, b"Date:").is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
use std::{
|
||||||
|
cell::Cell,
|
||||||
|
fmt::{self, Write},
|
||||||
|
rc::Rc,
|
||||||
|
time::{Duration, Instant, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
|
use actix_rt::{task::JoinHandle, time::interval};
|
||||||
|
|
||||||
|
/// "Thu, 01 Jan 1970 00:00:00 GMT".len()
|
||||||
|
pub(crate) const DATE_VALUE_LENGTH: usize = 29;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) struct Date {
|
||||||
|
pub(crate) bytes: [u8; DATE_VALUE_LENGTH],
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Date {
|
||||||
|
fn new() -> Date {
|
||||||
|
let mut date = Date {
|
||||||
|
bytes: [0; DATE_VALUE_LENGTH],
|
||||||
|
pos: 0,
|
||||||
|
};
|
||||||
|
date.update();
|
||||||
|
date
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) {
|
||||||
|
self.pos = 0;
|
||||||
|
write!(self, "{}", httpdate::fmt_http_date(SystemTime::now())).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Write for Date {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
let len = s.len();
|
||||||
|
self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
|
||||||
|
self.pos += len;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Service for update Date and Instant periodically at 500 millis interval.
|
||||||
|
pub(crate) struct DateService {
|
||||||
|
current: Rc<Cell<(Date, Instant)>>,
|
||||||
|
handle: JoinHandle<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DateService {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
// shared date and timer for DateService and update async task.
|
||||||
|
let current = Rc::new(Cell::new((Date::new(), Instant::now())));
|
||||||
|
let current_clone = Rc::clone(¤t);
|
||||||
|
// spawn an async task sleep for 500 millis and update current date/timer in a loop.
|
||||||
|
// handle is used to stop the task on DateService drop.
|
||||||
|
let handle = actix_rt::spawn(async move {
|
||||||
|
#[cfg(test)]
|
||||||
|
let _notify = crate::notify_on_drop::NotifyOnDrop::new();
|
||||||
|
|
||||||
|
let mut interval = interval(Duration::from_millis(500));
|
||||||
|
loop {
|
||||||
|
let now = interval.tick().await;
|
||||||
|
let date = Date::new();
|
||||||
|
current_clone.set((date, now.into_std()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DateService { current, handle }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn now(&self) -> Instant {
|
||||||
|
self.current.get().1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn with_date<F: FnMut(&Date)>(&self, mut f: F) {
|
||||||
|
f(&self.current.get().0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for DateService {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("DateService").finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DateService {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// stop the timer update async task on drop.
|
||||||
|
self.handle.abort();
|
||||||
|
}
|
||||||
|
}
|
|
@ -212,7 +212,7 @@ pub(crate) trait MessageType: Sized {
|
||||||
|
|
||||||
// optimized date header, set_date writes \r\n
|
// optimized date header, set_date writes \r\n
|
||||||
if !has_date {
|
if !has_date {
|
||||||
config.set_date(dst, camel_case);
|
config.write_date_header(dst, camel_case);
|
||||||
} else {
|
} else {
|
||||||
// msg eof
|
// msg eof
|
||||||
dst.extend_from_slice(b"\r\n");
|
dst.extend_from_slice(b"\r\n");
|
||||||
|
|
|
@ -322,7 +322,7 @@ fn prepare_response(
|
||||||
// set date header
|
// set date header
|
||||||
if !has_date {
|
if !has_date {
|
||||||
let mut bytes = BytesMut::with_capacity(29);
|
let mut bytes = BytesMut::with_capacity(29);
|
||||||
config.write_date_header(&mut bytes);
|
config.write_date_header_value(&mut bytes);
|
||||||
res.headers_mut().insert(
|
res.headers_mut().insert(
|
||||||
DATE,
|
DATE,
|
||||||
// SAFETY: serialized date-times are known ASCII strings
|
// SAFETY: serialized date-times are known ASCII strings
|
||||||
|
|
|
@ -4,8 +4,7 @@ use bytes::BytesMut;
|
||||||
use http::header::{HeaderValue, InvalidHeaderValue};
|
use http::header::{HeaderValue, InvalidHeaderValue};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::DATE_VALUE_LENGTH, error::ParseError, header::TryIntoHeaderValue,
|
date::DATE_VALUE_LENGTH, error::ParseError, header::TryIntoHeaderValue, helpers::MutWriter,
|
||||||
helpers::MutWriter,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A timestamp with HTTP-style formatting and parsing.
|
/// A timestamp with HTTP-style formatting and parsing.
|
||||||
|
|
|
@ -30,6 +30,14 @@ impl KeepAlive {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map zero duration to disabled.
|
||||||
|
pub(crate) fn normalize(self) -> KeepAlive {
|
||||||
|
match self {
|
||||||
|
KeepAlive::Timeout(Duration::ZERO) => KeepAlive::Disabled,
|
||||||
|
ka => ka,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for KeepAlive {
|
impl Default for KeepAlive {
|
||||||
|
@ -40,17 +48,17 @@ impl Default for KeepAlive {
|
||||||
|
|
||||||
impl From<Duration> for KeepAlive {
|
impl From<Duration> for KeepAlive {
|
||||||
fn from(dur: Duration) -> Self {
|
fn from(dur: Duration) -> Self {
|
||||||
KeepAlive::Timeout(dur)
|
KeepAlive::Timeout(dur).normalize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Option<Duration>> for KeepAlive {
|
impl From<Option<Duration>> for KeepAlive {
|
||||||
fn from(ka_dur: Option<Duration>) -> Self {
|
fn from(ka_dur: Option<Duration>) -> Self {
|
||||||
match ka_dur {
|
match ka_dur {
|
||||||
Some(Duration::ZERO) => KeepAlive::Disabled,
|
Some(dur) => KeepAlive::from(dur),
|
||||||
Some(dur) => KeepAlive::Timeout(dur),
|
|
||||||
None => KeepAlive::Disabled,
|
None => KeepAlive::Disabled,
|
||||||
}
|
}
|
||||||
|
.normalize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +74,9 @@ mod tests {
|
||||||
let test: KeepAlive = Duration::from_secs(0).into();
|
let test: KeepAlive = Duration::from_secs(0).into();
|
||||||
assert_eq!(test, KeepAlive::Disabled);
|
assert_eq!(test, KeepAlive::Disabled);
|
||||||
|
|
||||||
|
let test: KeepAlive = Some(Duration::from_secs(0)).into();
|
||||||
|
assert_eq!(test, KeepAlive::Disabled);
|
||||||
|
|
||||||
let test: KeepAlive = None.into();
|
let test: KeepAlive = None.into();
|
||||||
assert_eq!(test, KeepAlive::Disabled);
|
assert_eq!(test, KeepAlive::Disabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ pub use ::http::{Method, StatusCode, Version};
|
||||||
pub mod body;
|
pub mod body;
|
||||||
mod builder;
|
mod builder;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod date;
|
||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
@ -44,6 +45,8 @@ mod helpers;
|
||||||
mod http_message;
|
mod http_message;
|
||||||
mod keep_alive;
|
mod keep_alive;
|
||||||
mod message;
|
mod message;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod notify_on_drop;
|
||||||
mod payload;
|
mod payload;
|
||||||
mod requests;
|
mod requests;
|
||||||
mod responses;
|
mod responses;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/// Test Module for checking the drop state of certain async tasks that are spawned
|
||||||
|
/// with `actix_rt::spawn`
|
||||||
|
///
|
||||||
|
/// The target task must explicitly generate `NotifyOnDrop` when spawn the task
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static NOTIFY_DROPPED: RefCell<Option<bool>> = RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the spawned task is dropped.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics when there was no `NotifyOnDrop` instance on current thread.
|
||||||
|
pub(crate) fn is_dropped() -> bool {
|
||||||
|
NOTIFY_DROPPED.with(|bool| {
|
||||||
|
bool.borrow()
|
||||||
|
.expect("No NotifyOnDrop existed on current thread")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct NotifyOnDrop;
|
||||||
|
|
||||||
|
impl NotifyOnDrop {
|
||||||
|
/// # Panics
|
||||||
|
/// Panics hen construct multiple instances on any given thread.
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
NOTIFY_DROPPED.with(|bool| {
|
||||||
|
let mut bool = bool.borrow_mut();
|
||||||
|
if bool.is_some() {
|
||||||
|
panic!("NotifyOnDrop existed on current thread");
|
||||||
|
} else {
|
||||||
|
*bool = Some(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
NotifyOnDrop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for NotifyOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
NOTIFY_DROPPED.with(|bool| {
|
||||||
|
if let Some(b) = bool.borrow_mut().as_mut() {
|
||||||
|
*b = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue