@@ -1093,6 +1093,35 @@ def test_overflowing_header_limit_after_100(self):
10931093 self .assertIn ('got more than ' , str (cm .exception ))
10941094 self .assertIn ('headers' , str (cm .exception ))
10951095
1096+ def test_too_many_interim_responses (self ):
1097+ # A server streaming "100 Continue" responses forever must not
1098+ # hang getresponse().
1099+ body = (
1100+ 'HTTP/1.1 100 Continue\r \n \r \n '
1101+ * (client ._MAXINTERIMRESPONSES + 1 )
1102+ )
1103+ resp = client .HTTPResponse (FakeSocket (body ))
1104+ with self .assertRaises (client .HTTPException ) as cm :
1105+ resp .begin ()
1106+ self .assertIn ('got more than ' , str (cm .exception ))
1107+ self .assertIn ('interim responses' , str (cm .exception ))
1108+
1109+ def test_multiple_interim_responses (self ):
1110+ # A reasonable number of interim responses before the final
1111+ # response is skipped as before.
1112+ body = (
1113+ 'HTTP/1.1 100 Continue\r \n \r \n ' * 3 +
1114+ 'HTTP/1.1 200 OK\r \n '
1115+ 'Content-Length: 5\r \n '
1116+ '\r \n '
1117+ 'hello'
1118+ )
1119+ resp = client .HTTPResponse (FakeSocket (body ), method = "GET" )
1120+ resp .begin ()
1121+ self .assertEqual (resp .status , 200 )
1122+ self .assertEqual (resp .read (), b'hello' )
1123+ resp .close ()
1124+
10961125 def test_overflowing_chunked_line (self ):
10971126 body = (
10981127 'HTTP/1.1 200 OK\r \n '
@@ -1164,6 +1193,35 @@ def test_chunked_trailers(self):
11641193 self .assertEqual (sock .file .read (), b"" ) #we read to the end
11651194 resp .close ()
11661195
1196+ def test_chunked_too_many_trailers (self ):
1197+ """A response streaming endless trailer lines must raise, not hang"""
1198+ too_many_trailers = "" .join (
1199+ f"X-Trailer{ i } : { i } \r \n " for i in range (client ._MAXHEADERS + 1 )
1200+ )
1201+ # An unbounded read() reaches the trailers via the final 0 chunk.
1202+ sock = FakeSocket (
1203+ chunked_start + last_chunk + too_many_trailers + chunked_end )
1204+ resp = client .HTTPResponse (sock , method = "GET" )
1205+ resp .begin ()
1206+ with self .assertRaisesRegex (
1207+ client .HTTPException ,
1208+ f"got more than { client ._MAXHEADERS } trailers" ,
1209+ ):
1210+ resp .read ()
1211+ resp .close ()
1212+
1213+ # A bounded read(amt) larger than the body hits the same limit.
1214+ sock = FakeSocket (
1215+ chunked_start + last_chunk + too_many_trailers + chunked_end )
1216+ resp = client .HTTPResponse (sock , method = "GET" )
1217+ resp .begin ()
1218+ with self .assertRaisesRegex (
1219+ client .HTTPException ,
1220+ f"got more than { client ._MAXHEADERS } trailers" ,
1221+ ):
1222+ resp .read (len (chunked_expected ) + 1 )
1223+ resp .close ()
1224+
11671225 def test_chunked_sync (self ):
11681226 """Check that we don't read past the end of the chunked-encoding stream"""
11691227 expected = chunked_expected
0 commit comments