Skip to content

Commit f3308c0

Browse files
committedNov 8, 2023
feat(lib): missing Timer will warn or panic
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
1 parent 837c277 commit f3308c0

File tree

2 files changed

+48
-43
lines changed

2 files changed

+48
-43
lines changed
 

‎src/common/time.rs

+29-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
#[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
1+
#[cfg(any(
2+
all(any(feature = "client", feature = "server"), feature = "http2"),
3+
all(feature = "server", feature = "http1"),
4+
))]
25
use std::time::Duration;
36
use std::{fmt, sync::Arc};
47
use std::{pin::Pin, time::Instant};
@@ -13,46 +16,19 @@ pub(crate) enum Time {
1316
Empty,
1417
}
1518

19+
#[cfg(all(feature = "server", feature = "http1"))]
20+
#[derive(Clone, Copy, Debug)]
21+
pub(crate) enum Dur {
22+
Default(Option<Duration>),
23+
Configured(Option<Duration>),
24+
}
25+
1626
impl fmt::Debug for Time {
1727
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1828
f.debug_struct("Time").finish()
1929
}
2030
}
2131

22-
/*
23-
pub(crate) fn timeout<F>(tim: Tim, future: F, duration: Duration) -> HyperTimeout<F> {
24-
HyperTimeout { sleep: tim.sleep(duration), future: future }
25-
}
26-
27-
pin_project_lite::pin_project! {
28-
pub(crate) struct HyperTimeout<F> {
29-
sleep: Box<dyn Sleep>,
30-
#[pin]
31-
future: F
32-
}
33-
}
34-
35-
pub(crate) struct Timeout;
36-
37-
impl<F> Future for HyperTimeout<F> where F: Future {
38-
39-
type Output = Result<F::Output, Timeout>;
40-
41-
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>{
42-
let mut this = self.project();
43-
if let Poll::Ready(v) = this.future.poll(ctx) {
44-
return Poll::Ready(Ok(v));
45-
}
46-
47-
if let Poll::Ready(_) = Pin::new(&mut this.sleep).poll(ctx) {
48-
return Poll::Ready(Err(Timeout));
49-
}
50-
51-
return Poll::Pending;
52-
}
53-
}
54-
*/
55-
5632
impl Time {
5733
#[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
5834
pub(crate) fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {
@@ -82,4 +58,22 @@ impl Time {
8258
Time::Timer(ref t) => t.reset(sleep, new_deadline),
8359
}
8460
}
61+
62+
#[cfg(all(feature = "server", feature = "http1"))]
63+
pub(crate) fn check(&self, dur: Dur, name: &'static str) -> Option<Duration> {
64+
match dur {
65+
Dur::Default(Some(dur)) => match self {
66+
Time::Empty => {
67+
warn!("timeout `{}` has default, but no timer set", name,);
68+
None
69+
}
70+
Time::Timer(..) => Some(dur),
71+
},
72+
Dur::Configured(Some(dur)) => match self {
73+
Time::Empty => panic!("timeout `{}` set, but no timer set", name,),
74+
Time::Timer(..) => Some(dur),
75+
},
76+
Dur::Default(None) | Dur::Configured(None) => None,
77+
}
78+
}
8579
}

‎src/server/conn/http1.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use bytes::Bytes;
1515
use crate::body::{Body, Incoming as IncomingBody};
1616
use crate::proto;
1717
use crate::service::HttpService;
18-
use crate::{common::time::Time, rt::Timer};
18+
use crate::{
19+
common::time::{Dur, Time},
20+
rt::Timer,
21+
};
1922

2023
type Http1Dispatcher<T, B, S> = proto::h1::Dispatcher<
2124
proto::h1::dispatch::Server<S, IncomingBody>,
@@ -70,7 +73,7 @@ pub struct Builder {
7073
h1_keep_alive: bool,
7174
h1_title_case_headers: bool,
7275
h1_preserve_header_case: bool,
73-
h1_header_read_timeout: Option<Duration>,
76+
h1_header_read_timeout: Dur,
7477
h1_writev: Option<bool>,
7578
max_buf_size: Option<usize>,
7679
pipeline_flush: bool,
@@ -237,7 +240,7 @@ impl Builder {
237240
h1_keep_alive: true,
238241
h1_title_case_headers: false,
239242
h1_preserve_header_case: false,
240-
h1_header_read_timeout: None,
243+
h1_header_read_timeout: Dur::Default(None),
241244
h1_writev: None,
242245
max_buf_size: None,
243246
pipeline_flush: false,
@@ -293,8 +296,8 @@ impl Builder {
293296
/// transmit the entire header within this time, the connection is closed.
294297
///
295298
/// Default is None.
296-
pub fn header_read_timeout(&mut self, read_timeout: Duration) -> &mut Self {
297-
self.h1_header_read_timeout = Some(read_timeout);
299+
pub fn header_read_timeout(&mut self, read_timeout: impl Into<Option<Duration>>) -> &mut Self {
300+
self.h1_header_read_timeout = Dur::Configured(read_timeout.into());
298301
self
299302
}
300303

@@ -355,6 +358,11 @@ impl Builder {
355358
/// This returns a Future that must be polled in order for HTTP to be
356359
/// driven on the connection.
357360
///
361+
/// # Panics
362+
///
363+
/// If a timeout option has been configured, but a `timer` has not been
364+
/// provided, calling `serve_connection` will panic.
365+
///
358366
/// # Example
359367
///
360368
/// ```
@@ -400,9 +408,12 @@ impl Builder {
400408
if self.h1_preserve_header_case {
401409
conn.set_preserve_header_case();
402410
}
403-
if let Some(header_read_timeout) = self.h1_header_read_timeout {
404-
conn.set_http1_header_read_timeout(header_read_timeout);
405-
}
411+
if let Some(dur) = self
412+
.timer
413+
.check(self.h1_header_read_timeout, "header_read_timeout")
414+
{
415+
conn.set_http1_header_read_timeout(dur);
416+
};
406417
if let Some(writev) = self.h1_writev {
407418
if writev {
408419
conn.set_write_strategy_queue();

0 commit comments

Comments
 (0)
Please sign in to comment.