Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lib): missing Timer will warn or panic #3394

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 29 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 @@ -82,4 +58,22 @@ impl Time {
Time::Timer(ref t) => t.reset(sleep, new_deadline),
}
}

#[cfg(all(feature = "server", feature = "http1"))]
pub(crate) fn check(&self, dur: Dur, name: &'static str) -> Option<Duration> {
match dur {
Dur::Default(Some(dur)) => match self {
Time::Empty => {
warn!("timeout `{}` has default, but no timer set", name,);
None
}
Time::Timer(..) => Some(dur),
},
Dur::Configured(Some(dur)) => match self {
Time::Empty => panic!("timeout `{}` set, but no timer set", name,),
Time::Timer(..) => Some(dur),
},
Dur::Default(None) | Dur::Configured(None) => None,
}
}
}
27 changes: 19 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 @@ -355,6 +358,11 @@ impl Builder {
/// This returns a Future that must be polled in order for HTTP to be
/// driven on the connection.
///
/// # Panics
///
/// If a timeout option has been configured, but a `timer` has not been
/// provided, calling `serve_connection` will panic.
///
/// # Example
///
/// ```
Expand Down Expand Up @@ -400,9 +408,12 @@ 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);
}
if let Some(dur) = self
.timer
.check(self.h1_header_read_timeout, "header_read_timeout")
{
conn.set_http1_header_read_timeout(dur);
};
if let Some(writev) = self.h1_writev {
if writev {
conn.set_write_strategy_queue();
Expand Down