Skip to content

Commit fb185f9

Browse files
feat(server): configurable timeout + drop max_reqs
`MAX_REQUESTS` is introducing errors when they are not actually needed in the current configuration. If a user needs to limit incoming connections, this should happen more intelligently at a higher level in the stack.
1 parent 5b9e6ca commit fb185f9

File tree

2 files changed

+46
-17
lines changed

2 files changed

+46
-17
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ mod server;
115115
pub mod client;
116116

117117
pub use client::connect;
118-
pub use server::accept;
118+
pub use server::{accept, accept_with_opts, ServerOptions};

src/server/mod.rs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,62 @@ mod encode;
1313
use decode::decode;
1414
use encode::Encoder;
1515

16+
/// Configure the server.
17+
#[derive(Debug, Clone)]
18+
pub struct ServerOptions {
19+
/// Timeout to handle headers. Defaults to 60s.
20+
headers_timeout: Option<Duration>,
21+
}
22+
23+
impl Default for ServerOptions {
24+
fn default() -> Self {
25+
Self {
26+
headers_timeout: Some(Duration::from_secs(60)),
27+
}
28+
}
29+
}
30+
1631
/// Accept a new incoming HTTP/1.1 connection.
1732
///
1833
/// Supports `KeepAlive` requests by default.
19-
pub async fn accept<RW, F, Fut>(addr: &str, mut io: RW, endpoint: F) -> http_types::Result<()>
34+
pub async fn accept<RW, F, Fut>(addr: &str, io: RW, endpoint: F) -> http_types::Result<()>
2035
where
2136
RW: Read + Write + Clone + Send + Sync + Unpin + 'static,
2237
F: Fn(Request) -> Fut,
2338
Fut: Future<Output = http_types::Result<Response>>,
2439
{
25-
// TODO: make these values configurable
26-
let timeout_duration = Duration::from_secs(10);
27-
const MAX_REQUESTS: usize = 200;
28-
let mut num_requests = 0;
40+
accept_with_opts(addr, io, endpoint, Default::default()).await
41+
}
2942

43+
/// Accept a new incoming HTTP/1.1 connection.
44+
///
45+
/// Supports `KeepAlive` requests by default.
46+
pub async fn accept_with_opts<RW, F, Fut>(
47+
addr: &str,
48+
mut io: RW,
49+
endpoint: F,
50+
opts: ServerOptions,
51+
) -> http_types::Result<()>
52+
where
53+
RW: Read + Write + Clone + Send + Sync + Unpin + 'static,
54+
F: Fn(Request) -> Fut,
55+
Fut: Future<Output = http_types::Result<Response>>,
56+
{
3057
loop {
31-
// Stop parsing requests if we exceed the threshold.
32-
match num_requests {
33-
MAX_REQUESTS => return Ok(()),
34-
_ => num_requests += 1,
35-
};
58+
// Decode a new request, timing out if this takes longer than the timeout duration.
59+
let fut = decode(addr, io.clone());
3660

37-
// Decode a new request, timing out if this takes longer than the
38-
// timeout duration.
39-
let req = match timeout(timeout_duration, decode(addr, io.clone())).await {
40-
Ok(Ok(Some(r))) => r,
41-
Ok(Ok(None)) | Err(TimeoutError { .. }) => break, /* EOF or timeout */
42-
Ok(Err(e)) => return Err(e),
61+
let req = if let Some(timeout_duration) = opts.headers_timeout {
62+
match timeout(timeout_duration, fut).await {
63+
Ok(Ok(Some(r))) => r,
64+
Ok(Ok(None)) | Err(TimeoutError { .. }) => break, /* EOF or timeout */
65+
Ok(Err(e)) => return Err(e),
66+
}
67+
} else {
68+
match fut.await? {
69+
Some(r) => r,
70+
None => break, /* EOF */
71+
}
4372
};
4473

4574
// Pass the request to the endpoint and encode the response.

0 commit comments

Comments
 (0)