@@ -61,10 +61,14 @@ where
6161 #[ cfg( feature = "server" ) ]
6262 h1_header_read_timeout : None ,
6363 #[ cfg( feature = "server" ) ]
64- h1_header_read_timeout_fut : None ,
65- #[ cfg( feature = "server" ) ]
6664 h1_header_read_timeout_running : false ,
6765 #[ cfg( feature = "server" ) ]
66+ h1_idle_timeout : None ,
67+ #[ cfg( feature = "server" ) ]
68+ h1_idle_timeout_running : false ,
69+ #[ cfg( feature = "server" ) ]
70+ h1_timeout_fut : None ,
71+ #[ cfg( feature = "server" ) ]
6872 date_header : true ,
6973 #[ cfg( feature = "server" ) ]
7074 timer : Time :: Empty ,
@@ -147,6 +151,11 @@ where
147151 self . state . h1_header_read_timeout = Some ( val) ;
148152 }
149153
154+ #[ cfg( feature = "server" ) ]
155+ pub ( crate ) fn set_http1_idle_timeout ( & mut self , val : Duration ) {
156+ self . state . h1_idle_timeout = Some ( val) ;
157+ }
158+
150159 #[ cfg( feature = "server" ) ]
151160 pub ( crate ) fn set_allow_half_close ( & mut self ) {
152161 self . state . allow_half_close = true ;
@@ -217,24 +226,10 @@ where
217226 trace ! ( "Conn::read_head" ) ;
218227
219228 #[ cfg( feature = "server" ) ]
220- if !self . state . h1_header_read_timeout_running {
221- if let Some ( h1_header_read_timeout) = self . state . h1_header_read_timeout {
222- let deadline = Instant :: now ( ) + h1_header_read_timeout;
223- self . state . h1_header_read_timeout_running = true ;
224- match self . state . h1_header_read_timeout_fut {
225- Some ( ref mut h1_header_read_timeout_fut) => {
226- trace ! ( "resetting h1 header read timeout timer" ) ;
227- self . state . timer . reset ( h1_header_read_timeout_fut, deadline) ;
228- }
229- None => {
230- trace ! ( "setting h1 header read timeout timer" ) ;
231- self . state . h1_header_read_timeout_fut =
232- Some ( self . state . timer . sleep_until ( deadline) ) ;
233- }
234- }
235- }
236- }
229+ let first_head = !self . io . is_read_blocked ( ) ;
237230
231+ #[ cfg_attr( not( feature = "server" ) , allow( unused) ) ]
232+ let mut progress = false ;
238233 let msg = match self . io . parse :: < T > (
239234 cx,
240235 ParseContext {
@@ -249,20 +244,69 @@ where
249244 #[ cfg( feature = "ffi" ) ]
250245 on_informational : & mut self . state . on_informational ,
251246 } ,
247+ & mut progress,
252248 ) {
253249 Poll :: Ready ( Ok ( msg) ) => msg,
254250 Poll :: Ready ( Err ( e) ) => return self . on_read_head_error ( e) ,
255251 Poll :: Pending => {
252+ // - Use the read timeout on the first head to avoid common DoS.
253+ // - If made progress in reading header, must no longer be idle.
256254 #[ cfg( feature = "server" ) ]
257- if self . state . h1_header_read_timeout_running {
258- if let Some ( ref mut h1_header_read_timeout_fut) =
259- self . state . h1_header_read_timeout_fut
260- {
261- if Pin :: new ( h1_header_read_timeout_fut) . poll ( cx) . is_ready ( ) {
262- self . state . h1_header_read_timeout_running = false ;
263-
264- warn ! ( "read header from client timeout" ) ;
265- return Poll :: Ready ( Some ( Err ( crate :: Error :: new_header_timeout ( ) ) ) ) ;
255+ if first_head || progress {
256+ if !self . state . h1_header_read_timeout_running {
257+ if let Some ( h1_header_read_timeout) = self . state . h1_header_read_timeout {
258+ let deadline = Instant :: now ( ) + h1_header_read_timeout;
259+ self . state . h1_idle_timeout_running = false ;
260+ self . state . h1_header_read_timeout_running = true ;
261+ match self . state . h1_timeout_fut {
262+ Some ( ref mut ht_timeout_fut) => {
263+ trace ! ( "resetting h1 timeout timer for header read" ) ;
264+ self . state . timer . reset ( ht_timeout_fut, deadline) ;
265+ }
266+ None => {
267+ trace ! ( "setting h1 timeout timer for header read" ) ;
268+ self . state . h1_timeout_fut =
269+ Some ( self . state . timer . sleep_until ( deadline) ) ;
270+ }
271+ }
272+ } else if std:: mem:: take ( & mut self . state . h1_idle_timeout_running ) {
273+ trace ! ( "unsetting h1 timeout timer for idle" ) ;
274+ self . state . h1_timeout_fut = None ;
275+ }
276+ }
277+ } else if !self . state . h1_header_read_timeout_running
278+ && !self . state . h1_idle_timeout_running
279+ {
280+ if let Some ( h1_idle_timeout) = self . state . h1_idle_timeout {
281+ let deadline = Instant :: now ( ) + h1_idle_timeout;
282+ self . state . h1_idle_timeout_running = true ;
283+ match self . state . h1_timeout_fut {
284+ Some ( ref mut h1_timeout_fut) => {
285+ trace ! ( "resetting h1 timeout timer for idle" ) ;
286+ self . state . timer . reset ( h1_timeout_fut, deadline) ;
287+ }
288+ None => {
289+ trace ! ( "setting h1 timeout timer for idle" ) ;
290+ self . state . h1_timeout_fut =
291+ Some ( self . state . timer . sleep_until ( deadline) ) ;
292+ }
293+ }
294+ }
295+ }
296+
297+ #[ cfg( feature = "server" ) ]
298+ if self . state . h1_header_read_timeout_running || self . state . h1_idle_timeout_running {
299+ if let Some ( ref mut h1_timeout_fut) = self . state . h1_timeout_fut {
300+ if Pin :: new ( h1_timeout_fut) . poll ( cx) . is_ready ( ) {
301+ return Poll :: Ready ( Some ( Err (
302+ if self . state . h1_header_read_timeout_running {
303+ warn ! ( "read header from client timeout" ) ;
304+ crate :: Error :: new_header_timeout ( )
305+ } else {
306+ warn ! ( "idle client timeout" ) ;
307+ crate :: Error :: new_idle_timeout ( )
308+ } ,
309+ ) ) ) ;
266310 }
267311 }
268312 }
@@ -274,7 +318,8 @@ where
274318 #[ cfg( feature = "server" ) ]
275319 {
276320 self . state . h1_header_read_timeout_running = false ;
277- self . state . h1_header_read_timeout_fut = None ;
321+ self . state . h1_idle_timeout_running = false ;
322+ self . state . h1_timeout_fut = None ;
278323 }
279324
280325 // Note: don't deconstruct `msg` into local variables, it appears
@@ -919,10 +964,14 @@ struct State {
919964 #[ cfg( feature = "server" ) ]
920965 h1_header_read_timeout : Option < Duration > ,
921966 #[ cfg( feature = "server" ) ]
922- h1_header_read_timeout_fut : Option < Pin < Box < dyn Sleep > > > ,
923- #[ cfg( feature = "server" ) ]
924967 h1_header_read_timeout_running : bool ,
925968 #[ cfg( feature = "server" ) ]
969+ h1_idle_timeout : Option < Duration > ,
970+ #[ cfg( feature = "server" ) ]
971+ h1_idle_timeout_running : bool ,
972+ #[ cfg( feature = "server" ) ]
973+ h1_timeout_fut : Option < Pin < Box < dyn Sleep > > > ,
974+ #[ cfg( feature = "server" ) ]
926975 date_header : bool ,
927976 #[ cfg( feature = "server" ) ]
928977 timer : Time ,
@@ -1106,6 +1155,12 @@ impl State {
11061155 self . reading = Reading :: Init ;
11071156 self . writing = Writing :: Init ;
11081157
1158+ #[ cfg( feature = "server" ) ]
1159+ if self . h1_idle_timeout . is_some ( ) {
1160+ // Next read will start and poll the idle timeout.
1161+ self . notify_read = true ;
1162+ }
1163+
11091164 // !T::should_read_first() means Client.
11101165 //
11111166 // If Client connection has just gone idle, the Dispatcher
0 commit comments