diff --git a/src/common/mod.rs b/src/common/mod.rs index 4129673cdc..3acf211dd2 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -17,5 +17,6 @@ pub(crate) mod task; all(feature = "server", feature = "http1"), all(any(feature = "client", feature = "server"), feature = "http2"), ))] +#[macro_use] pub(crate) mod time; pub(crate) mod watch; diff --git a/src/common/time.rs b/src/common/time.rs index 9dff12534d..725adf837a 100644 --- a/src/common/time.rs +++ b/src/common/time.rs @@ -1,4 +1,7 @@ -#[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))] +#[cfg(any( + all(any(feature = "client", feature = "server"), feature = "http2"), + all(feature = "server", feature = "http1"), +))] use std::time::Duration; use std::{fmt, sync::Arc}; use std::{pin::Pin, time::Instant}; @@ -13,46 +16,19 @@ pub(crate) enum Time { Empty, } +#[cfg(all(feature = "server", feature = "http1"))] +#[derive(Clone, Copy, Debug)] +pub(crate) enum Dur { + Default(Option), + Configured(Option), +} + impl fmt::Debug for Time { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Time").finish() } } -/* -pub(crate) fn timeout(tim: Tim, future: F, duration: Duration) -> HyperTimeout { - HyperTimeout { sleep: tim.sleep(duration), future: future } -} - -pin_project_lite::pin_project! { - pub(crate) struct HyperTimeout { - sleep: Box, - #[pin] - future: F - } -} - -pub(crate) struct Timeout; - -impl Future for HyperTimeout where F: Future { - - type Output = Result; - - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll{ - let mut this = self.project(); - if let Poll::Ready(v) = this.future.poll(ctx) { - return Poll::Ready(Ok(v)); - } - - if let Poll::Ready(_) = Pin::new(&mut this.sleep).poll(ctx) { - return Poll::Ready(Err(Timeout)); - } - - return Poll::Pending; - } -} -*/ - impl Time { #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))] pub(crate) fn sleep(&self, duration: Duration) -> Pin> { @@ -83,3 +59,36 @@ impl Time { } } } + +#[cfg(all(feature = "server", feature = "http1"))] +macro_rules! check_timer { + ($me:ident.$opt:ident, $timer:ident, $closure:expr) => { + match $me.$opt { + Dur::Default(Some(dur)) => match $me.$timer { + Time::Empty => { + warn!(concat!( + "timeout `", + stringify!($opt), + "` has default, but no timer set", + )); + } + Time::Timer(..) => { + $closure(dur); + } + }, + Dur::Configured(Some(dur)) => match $me.$timer { + Time::Empty => panic!(concat!( + "timeout `", + stringify!($opt), + "` set, but no timer set", + )), + Time::Timer(..) => { + $closure(dur); + } + }, + Dur::Default(None) | Dur::Configured(None) => { + // do nothing + } + } + }; +} diff --git a/src/server/conn/http1.rs b/src/server/conn/http1.rs index c3a4f724ff..f3cf00e2c9 100644 --- a/src/server/conn/http1.rs +++ b/src/server/conn/http1.rs @@ -15,7 +15,10 @@ use bytes::Bytes; use crate::body::{Body, Incoming as IncomingBody}; use crate::proto; use crate::service::HttpService; -use crate::{common::time::Time, rt::Timer}; +use crate::{ + common::time::{Dur, Time}, + rt::Timer, +}; type Http1Dispatcher = proto::h1::Dispatcher< proto::h1::dispatch::Server, @@ -70,7 +73,7 @@ pub struct Builder { h1_keep_alive: bool, h1_title_case_headers: bool, h1_preserve_header_case: bool, - h1_header_read_timeout: Option, + h1_header_read_timeout: Dur, h1_writev: Option, max_buf_size: Option, pipeline_flush: bool, @@ -237,7 +240,7 @@ impl Builder { h1_keep_alive: true, h1_title_case_headers: false, h1_preserve_header_case: false, - h1_header_read_timeout: None, + h1_header_read_timeout: Dur::Default(None), h1_writev: None, max_buf_size: None, pipeline_flush: false, @@ -293,8 +296,8 @@ impl Builder { /// transmit the entire header within this time, the connection is closed. /// /// Default is None. - pub fn header_read_timeout(&mut self, read_timeout: Duration) -> &mut Self { - self.h1_header_read_timeout = Some(read_timeout); + pub fn header_read_timeout(&mut self, read_timeout: impl Into>) -> &mut Self { + self.h1_header_read_timeout = Dur::Configured(read_timeout.into()); self } @@ -400,9 +403,9 @@ impl Builder { if self.h1_preserve_header_case { conn.set_preserve_header_case(); } - if let Some(header_read_timeout) = self.h1_header_read_timeout { - conn.set_http1_header_read_timeout(header_read_timeout); - } + check_timer!(self.h1_header_read_timeout, timer, |dur| { + conn.set_http1_header_read_timeout(dur); + }); if let Some(writev) = self.h1_writev { if writev { conn.set_write_strategy_queue();