Skip to content

Commit

Permalink
feat(lib): missing Timer will warn or panic
Browse files Browse the repository at this point in the history
If a default timeout is set, and no Timer, a warning will be emitted.

If a timeout is configured by the user, and no Timer is set, it will
panic.

Closes #3393
  • Loading branch information
seanmonstar committed Nov 6, 2023
1 parent 5571711 commit 9bdf96d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 43 deletions.
1 change: 1 addition & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
79 changes: 44 additions & 35 deletions src/common/time.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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<Duration>),
Configured(Option<Duration>),
}

impl fmt::Debug for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Time").finish()
}
}

/*
pub(crate) fn timeout<F>(tim: Tim, future: F, duration: Duration) -> HyperTimeout<F> {
HyperTimeout { sleep: tim.sleep(duration), future: future }
}
pin_project_lite::pin_project! {
pub(crate) struct HyperTimeout<F> {
sleep: Box<dyn Sleep>,
#[pin]
future: F
}
}
pub(crate) struct Timeout;
impl<F> Future for HyperTimeout<F> where F: Future {
type Output = Result<F::Output, Timeout>;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>{
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<Box<dyn Sleep>> {
Expand Down Expand Up @@ -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
}
}
};
}
19 changes: 11 additions & 8 deletions src/server/conn/http1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, B, S> = proto::h1::Dispatcher<
proto::h1::dispatch::Server<S, IncomingBody>,
Expand Down Expand Up @@ -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<Duration>,
h1_header_read_timeout: Dur,
h1_writev: Option<bool>,
max_buf_size: Option<usize>,
pipeline_flush: bool,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<Option<Duration>>) -> &mut Self {
self.h1_header_read_timeout = Dur::Configured(read_timeout.into());
self
}

Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 9bdf96d

Please sign in to comment.