feat(serve): split request read budget into head_timeout + body_timeout
The single request_timeout covered head + body under one wall clock, so a slow-but-legit body upload (e.g. a trickling cellular IoT client) was judged by the short head deadline and killed mid-body. Split into: - head_timeout (default 30s): first byte -> full head parse; the classic slowloris surface, kept short. - body_timeout (default 300s): head parse -> full body; an absolute cap sized for slow links, anchored independently once the head has parsed. read_head no longer returns a shared deadline; run_connection anchors the body deadline itself. ReadHeadErr::RequestTimeout -> HeadTimeout. Config and ConnLimits gain body_timeout; request_timeout renamed to head_timeout (breaking, but this axis is unreleased). Tests: slow_body_outlives_head_timeout (positive: body survives past the head clock), fixed_/chunked_body_stall_killed_at_body_timeout (body cap still bites), slowloris_partial_head_killed_at_head_timeout (head clock unchanged). 79 lib + 43 integration green; clippy --lib clean.
This commit is contained in:
+12
-3
@@ -37,7 +37,14 @@ pub struct Config {
|
||||
pub keep_alive_timeout: Duration,
|
||||
pub max_header_count: usize,
|
||||
pub read_buf_size: usize,
|
||||
pub request_timeout: Duration,
|
||||
/// Wall-clock budget for reading the request HEAD (from first byte to
|
||||
/// full head parse). Kept short — an incomplete head is the classic
|
||||
/// slowloris. See `ConnLimits::head_timeout`.
|
||||
pub head_timeout: Duration,
|
||||
/// Absolute wall-clock cap on reading the request BODY (from head-parse
|
||||
/// to full body). Sized for slow links, so much larger than
|
||||
/// `head_timeout`. See `ConnLimits::body_timeout`.
|
||||
pub body_timeout: Duration,
|
||||
/// Per-write budget for response bytes (the fixed head+body write, and
|
||||
/// each streamed chunk). See `ConnLimits::write_timeout`.
|
||||
pub write_timeout: Duration,
|
||||
@@ -88,7 +95,8 @@ impl Config {
|
||||
keep_alive_timeout: Duration::from_secs(60),
|
||||
max_header_count: 64,
|
||||
read_buf_size: 8 * 1024,
|
||||
request_timeout: Duration::from_secs(30),
|
||||
head_timeout: Duration::from_secs(30),
|
||||
body_timeout: Duration::from_secs(300),
|
||||
write_timeout: Duration::from_secs(30),
|
||||
max_body_bytes: 16 * 1024 * 1024,
|
||||
drain_timeout: Duration::from_secs(30),
|
||||
@@ -107,7 +115,8 @@ impl Config {
|
||||
max_head_bytes: 64 * 1024,
|
||||
max_body_bytes: self.max_body_bytes,
|
||||
keep_alive_timeout: self.keep_alive_timeout,
|
||||
request_timeout: self.request_timeout,
|
||||
head_timeout: self.head_timeout,
|
||||
body_timeout: self.body_timeout,
|
||||
write_timeout: self.write_timeout,
|
||||
max_frame_payload: self.max_frame_payload,
|
||||
max_message_bytes: self.max_message_bytes,
|
||||
|
||||
Reference in New Issue
Block a user