@@ -1257,6 +1257,35 @@ def test_overflowing_header_limit_after_100(self):
12571257 self .assertIn ('got more than ' , str (cm .exception ))
12581258 self .assertIn ('headers' , str (cm .exception ))
12591259
1260+ def test_too_many_interim_responses (self ):
1261+ # A server streaming "100 Continue" responses forever must not
1262+ # hang getresponse().
1263+ body = (
1264+ 'HTTP/1.1 100 Continue\r \n \r \n '
1265+ * (client ._MAXINTERIMRESPONSES + 1 )
1266+ )
1267+ resp = client .HTTPResponse (FakeSocket (body ))
1268+ with self .assertRaises (client .HTTPException ) as cm :
1269+ resp .begin ()
1270+ self .assertIn ('got more than ' , str (cm .exception ))
1271+ self .assertIn ('interim responses' , str (cm .exception ))
1272+
1273+ def test_multiple_interim_responses (self ):
1274+ # A reasonable number of interim responses before the final
1275+ # response is skipped as before.
1276+ body = (
1277+ 'HTTP/1.1 100 Continue\r \n \r \n ' * 3 +
1278+ 'HTTP/1.1 200 OK\r \n '
1279+ 'Content-Length: 5\r \n '
1280+ '\r \n '
1281+ 'hello'
1282+ )
1283+ resp = client .HTTPResponse (FakeSocket (body ), method = "GET" )
1284+ resp .begin ()
1285+ self .assertEqual (resp .status , 200 )
1286+ self .assertEqual (resp .read (), b'hello' )
1287+ resp .close ()
1288+
12601289 def test_overflowing_chunked_line (self ):
12611290 body = (
12621291 'HTTP/1.1 200 OK\r \n '
@@ -1328,6 +1357,35 @@ def test_chunked_trailers(self):
13281357 self .assertEqual (sock .file .read (), b"" ) #we read to the end
13291358 resp .close ()
13301359
1360+ def test_chunked_too_many_trailers (self ):
1361+ """A response streaming endless trailer lines must raise, not hang"""
1362+ too_many_trailers = "" .join (
1363+ f"X-Trailer{ i } : { i } \r \n " for i in range (client ._MAXHEADERS + 1 )
1364+ )
1365+ # An unbounded read() reaches the trailers via the final 0 chunk.
1366+ sock = FakeSocket (
1367+ chunked_start + last_chunk + too_many_trailers + chunked_end )
1368+ resp = client .HTTPResponse (sock , method = "GET" )
1369+ resp .begin ()
1370+ with self .assertRaisesRegex (
1371+ client .HTTPException ,
1372+ f"got more than { client ._MAXHEADERS } trailers" ,
1373+ ):
1374+ resp .read ()
1375+ resp .close ()
1376+
1377+ # A bounded read(amt) larger than the body hits the same limit.
1378+ sock = FakeSocket (
1379+ chunked_start + last_chunk + too_many_trailers + chunked_end )
1380+ resp = client .HTTPResponse (sock , method = "GET" )
1381+ resp .begin ()
1382+ with self .assertRaisesRegex (
1383+ client .HTTPException ,
1384+ f"got more than { client ._MAXHEADERS } trailers" ,
1385+ ):
1386+ resp .read (len (chunked_expected ) + 1 )
1387+ resp .close ()
1388+
13311389 def test_chunked_sync (self ):
13321390 """Check that we don't read past the end of the chunked-encoding stream"""
13331391 expected = chunked_expected
0 commit comments