@@ -419,6 +419,110 @@ def test_parser_request_4(self):
419419 with self .assertRaisesRegex (TypeError , 'a bytes-like object' ):
420420 p .feed_data ('POST HTTP/1.2' )
421421
422+ def test_parser_request_fragmented (self ):
423+ m = mock .Mock ()
424+ headers = {}
425+ m .on_header .side_effect = headers .__setitem__
426+ p = httptools .HttpRequestParser (m )
427+
428+ REQUEST = (
429+ b'PUT / HTTP/1.1\r \n Host: localhost:1234\r \n Content-Type: text/pl' ,
430+ b'ain; charset=utf-8\r \n X-Empty-Header: \r \n Connection: close\r \n ' ,
431+ b'Content-Length: 10\r \n \r \n 1234567890' ,
432+ )
433+
434+ p .feed_data (REQUEST [0 ])
435+
436+ m .on_message_begin .assert_called_once_with ()
437+ m .on_url .assert_called_once_with (b'/' )
438+ self .assertEqual (headers , {b'Host' : b'localhost:1234' })
439+
440+ p .feed_data (REQUEST [1 ])
441+ self .assertEqual (
442+ headers ,
443+ {b'Host' : b'localhost:1234' ,
444+ b'Content-Type' : b'text/plain; charset=utf-8' ,
445+ b'X-Empty-Header' : b'' })
446+
447+ p .feed_data (REQUEST [2 ])
448+ self .assertEqual (
449+ headers ,
450+ {b'Host' : b'localhost:1234' ,
451+ b'Content-Type' : b'text/plain; charset=utf-8' ,
452+ b'X-Empty-Header' : b'' ,
453+ b'Connection' : b'close' ,
454+ b'Content-Length' : b'10' })
455+ m .on_message_complete .assert_called_once_with ()
456+
457+ def test_parser_request_fragmented_header (self ):
458+ m = mock .Mock ()
459+ headers = {}
460+ m .on_header .side_effect = headers .__setitem__
461+ p = httptools .HttpRequestParser (m )
462+
463+ REQUEST = (
464+ b'PUT / HTTP/1.1\r \n Host: localhost:1234\r \n Content-' ,
465+ b'Type: text/plain; charset=utf-8\r \n \r \n ' ,
466+ )
467+
468+ p .feed_data (REQUEST [0 ])
469+
470+ m .on_message_begin .assert_called_once_with ()
471+ m .on_url .assert_called_once_with (b'/' )
472+ self .assertEqual (headers , {b'Host' : b'localhost:1234' })
473+
474+ p .feed_data (REQUEST [1 ])
475+ self .assertEqual (
476+ headers ,
477+ {b'Host' : b'localhost:1234' ,
478+ b'Content-Type' : b'text/plain; charset=utf-8' })
479+
480+ def test_parser_request_fragmented_value (self ):
481+ m = mock .Mock ()
482+ headers = {}
483+ m .on_header .side_effect = headers .__setitem__
484+ p = httptools .HttpRequestParser (m )
485+
486+ REQUEST = (
487+ b'PUT / HTTP/1.1\r \n Host: localhost:1234\r \n Content-Type:' ,
488+ b' text/pla' ,
489+ b'in; chars' ,
490+ b'et=utf-8\r \n \r \n ' ,
491+ )
492+
493+ p .feed_data (REQUEST [0 ])
494+
495+ m .on_message_begin .assert_called_once_with ()
496+ m .on_url .assert_called_once_with (b'/' )
497+ self .assertEqual (headers , {b'Host' : b'localhost:1234' })
498+
499+ p .feed_data (REQUEST [1 ])
500+ p .feed_data (REQUEST [2 ])
501+ p .feed_data (REQUEST [3 ])
502+ self .assertEqual (
503+ headers ,
504+ {b'Host' : b'localhost:1234' ,
505+ b'Content-Type' : b'text/plain; charset=utf-8' })
506+
507+ def test_parser_request_fragmented_bytes (self ):
508+ m = mock .Mock ()
509+ headers = {}
510+ m .on_header .side_effect = headers .__setitem__
511+ p = httptools .HttpRequestParser (m )
512+
513+ REQUEST = \
514+ b'PUT / HTTP/1.1\r \n Host: localhost:1234\r \n Content-' \
515+ b'Type: text/plain; charset=utf-8\r \n \r \n '
516+
517+ step = 1
518+ for i in range (0 , len (REQUEST ), step ):
519+ p .feed_data (REQUEST [i :i + step ])
520+
521+ self .assertEqual (
522+ headers ,
523+ {b'Host' : b'localhost:1234' ,
524+ b'Content-Type' : b'text/plain; charset=utf-8' })
525+
422526
423527class TestUrlParser (unittest .TestCase ):
424528
0 commit comments