@@ -805,11 +805,12 @@ def app_check_disconnect(self, environ, start_response):
805
805
)
806
806
return [body ]
807
807
808
- def _make_app_with_lookahead (self ):
808
+ def _make_app_with_lookahead (self , recv_bytes = 8192 ):
809
809
"""
810
810
Setup a channel with lookahead and store it and the socket in self
811
811
"""
812
812
adj = DummyAdjustments ()
813
+ adj .recv_bytes = recv_bytes
813
814
adj .channel_request_lookahead = 5
814
815
channel , sock , map = self ._makeOneWithMap (adj = adj )
815
816
channel .server .application = self .app_check_disconnect
@@ -901,6 +902,58 @@ def test_lookahead_continue(self):
901
902
self .assertEqual (data .split ("\r \n " )[- 1 ], "finished" )
902
903
self .assertEqual (self .request_body , b"x" )
903
904
905
+ def test_lookahead_bad_request_drop_extra_data (self ):
906
+ """
907
+ Send two requests, the first one being bad, split on the recv_bytes
908
+ limit, then emulate a race that could happen whereby we read data from
909
+ the socket while the service thread is cleaning up due to an error
910
+ processing the request.
911
+ """
912
+
913
+ invalid_request = [
914
+ "GET / HTTP/1.1" ,
915
+ "Host: localhost:8080" ,
916
+ "Content-length: -1" ,
917
+ "" ,
918
+ ]
919
+
920
+ invalid_request_len = len ("" .join ([x + "\r \n " for x in invalid_request ]))
921
+
922
+ second_request = [
923
+ "POST / HTTP/1.1" ,
924
+ "Host: localhost:8080" ,
925
+ "Content-Length: 1" ,
926
+ "" ,
927
+ "x" ,
928
+ ]
929
+
930
+ full_request = invalid_request + second_request
931
+
932
+ self ._make_app_with_lookahead (recv_bytes = invalid_request_len )
933
+ self ._send (* full_request )
934
+ self .channel .handle_read ()
935
+ self .assertEqual (len (self .channel .requests ), 1 )
936
+ self .channel .server .tasks [0 ].service ()
937
+ self .assertTrue (self .channel .close_when_flushed )
938
+ # Read all of the next request
939
+ self .channel .handle_read ()
940
+ self .channel .handle_read ()
941
+ # Validate that there is no more data to be read
942
+ self .assertEqual (self .sock .remote .local_sent , b"" )
943
+ # Validate that we dropped the data from the second read, and did not
944
+ # create a new request
945
+ self .assertEqual (len (self .channel .requests ), 0 )
946
+ data = self .sock .recv (256 ).decode ("ascii" )
947
+ self .assertFalse (self .channel .readable ())
948
+ self .assertTrue (self .channel .writable ())
949
+
950
+ # Handle the write, which will close the socket
951
+ self .channel .handle_write ()
952
+ self .assertTrue (self .sock .closed )
953
+
954
+ data = self .sock .recv (256 )
955
+ self .assertEqual (len (data ), 0 )
956
+
904
957
905
958
class DummySock :
906
959
blocking = False
0 commit comments