@@ -88,6 +88,9 @@ where I: AsyncRead + AsyncWrite,
88
88
trace ! ( "poll when on keep-alive" ) ;
89
89
if !T :: should_read_first ( ) {
90
90
self . try_empty_read ( ) ?;
91
+ if self . is_read_closed ( ) {
92
+ return Ok ( Async :: Ready ( None ) ) ;
93
+ }
91
94
}
92
95
self . maybe_park_read ( ) ;
93
96
return Ok ( Async :: NotReady ) ;
@@ -134,6 +137,11 @@ where I: AsyncRead + AsyncWrite,
134
137
}
135
138
}
136
139
140
+ fn should_error_on_eof ( & self ) -> bool {
141
+ // If we're idle, it's probably just the connection closing gracefully.
142
+ T :: should_error_on_parse_eof ( ) && !self . state . is_idle ( )
143
+ }
144
+
137
145
pub fn read_head ( & mut self ) -> Poll < Option < ( super :: MessageHead < T :: Incoming > , bool ) > , :: Error > {
138
146
debug_assert ! ( self . can_read_head( ) ) ;
139
147
trace ! ( "Conn::read_head" ) ;
@@ -145,7 +153,7 @@ where I: AsyncRead + AsyncWrite,
145
153
// If we are currently waiting on a message, then an empty
146
154
// message should be reported as an error. If not, it is just
147
155
// the connection closing gracefully.
148
- let must_error = ! self . state . is_idle ( ) && T :: should_error_on_parse_eof ( ) ;
156
+ let must_error = self . should_error_on_eof ( ) ;
149
157
self . state . close_read ( ) ;
150
158
self . io . consume_leading_lines ( ) ;
151
159
let was_mid_parse = !self . io . read_buf ( ) . is_empty ( ) ;
@@ -185,6 +193,9 @@ where I: AsyncRead + AsyncWrite,
185
193
( true , Reading :: Body ( decoder) )
186
194
} ;
187
195
self . state . reading = reading;
196
+ if !body {
197
+ self . try_keep_alive ( ) ;
198
+ }
188
199
Ok ( Async :: Ready ( Some ( ( head, body) ) ) )
189
200
} ,
190
201
_ => {
@@ -219,6 +230,7 @@ where I: AsyncRead + AsyncWrite,
219
230
} ;
220
231
221
232
self . state . reading = reading;
233
+ self . try_keep_alive ( ) ;
222
234
ret
223
235
}
224
236
@@ -251,11 +263,12 @@ where I: AsyncRead + AsyncWrite,
251
263
} else {
252
264
match self . io . read_from_io ( ) {
253
265
Ok ( Async :: Ready ( 0 ) ) => {
254
- trace ! ( "try_empty_read; found EOF on connection" ) ;
266
+ trace ! ( "try_empty_read; found EOF on connection: {:?}" , self . state) ;
267
+ let must_error = self . should_error_on_eof ( ) ;
268
+ // order is important: must_error needs state BEFORE close_read
255
269
self . state . close_read ( ) ;
256
- let must_error = !self . state . is_idle ( ) && T :: should_error_on_parse_eof ( ) ;
257
270
if must_error {
258
- Err ( io:: ErrorKind :: UnexpectedEof . into ( ) )
271
+ Err ( io:: Error :: new ( io :: ErrorKind :: UnexpectedEof , "unexpected EOF waiting for response" ) )
259
272
} else {
260
273
Ok ( ( ) )
261
274
}
@@ -860,7 +873,7 @@ mod tests {
860
873
use super :: super :: h1:: Encoder ;
861
874
use mock:: AsyncIo ;
862
875
863
- use super :: { Conn , Reading , Writing } ;
876
+ use super :: { Conn , Decoder , Reading , Writing } ;
864
877
use :: uri:: Uri ;
865
878
866
879
use std:: str:: FromStr ;
@@ -960,6 +973,55 @@ mod tests {
960
973
} ) . wait ( ) ;
961
974
}
962
975
976
+ #[ test]
977
+ fn test_conn_body_finish_read_eof ( ) {
978
+ let _: Result < ( ) , ( ) > = future:: lazy ( || {
979
+ let io = AsyncIo :: new_eof ( ) ;
980
+ let mut conn = Conn :: < _ , proto:: Chunk , ClientTransaction > :: new ( io, Default :: default ( ) ) ;
981
+ conn. state . busy ( ) ;
982
+ conn. state . writing = Writing :: KeepAlive ;
983
+ conn. state . reading = Reading :: Body ( Decoder :: length ( 0 ) ) ;
984
+
985
+ match conn. poll ( ) {
986
+ Ok ( Async :: Ready ( Some ( Frame :: Body { chunk : None } ) ) ) => ( ) ,
987
+ other => panic ! ( "unexpected frame: {:?}" , other)
988
+ }
989
+
990
+ // conn eofs, but tokio-proto will call poll() again, before calling flush()
991
+ // the conn eof in this case is perfectly fine
992
+
993
+ match conn. poll ( ) {
994
+ Ok ( Async :: Ready ( None ) ) => ( ) ,
995
+ other => panic ! ( "unexpected frame: {:?}" , other)
996
+ }
997
+ Ok ( ( ) )
998
+ } ) . wait ( ) ;
999
+ }
1000
+
1001
+ #[ test]
1002
+ fn test_conn_message_empty_body_read_eof ( ) {
1003
+ let _: Result < ( ) , ( ) > = future:: lazy ( || {
1004
+ let io = AsyncIo :: new_buf ( b"HTTP/1.1 200 OK\r \n Content-Length: 0\r \n \r \n " . to_vec ( ) , 1024 ) ;
1005
+ let mut conn = Conn :: < _ , proto:: Chunk , ClientTransaction > :: new ( io, Default :: default ( ) ) ;
1006
+ conn. state . busy ( ) ;
1007
+ conn. state . writing = Writing :: KeepAlive ;
1008
+
1009
+ match conn. poll ( ) {
1010
+ Ok ( Async :: Ready ( Some ( Frame :: Message { body : false , .. } ) ) ) => ( ) ,
1011
+ other => panic ! ( "unexpected frame: {:?}" , other)
1012
+ }
1013
+
1014
+ // conn eofs, but tokio-proto will call poll() again, before calling flush()
1015
+ // the conn eof in this case is perfectly fine
1016
+
1017
+ match conn. poll ( ) {
1018
+ Ok ( Async :: Ready ( None ) ) => ( ) ,
1019
+ other => panic ! ( "unexpected frame: {:?}" , other)
1020
+ }
1021
+ Ok ( ( ) )
1022
+ } ) . wait ( ) ;
1023
+ }
1024
+
963
1025
#[ test]
964
1026
fn test_conn_closed_read ( ) {
965
1027
let io = AsyncIo :: new_buf ( vec ! [ ] , 0 ) ;
0 commit comments