1313HOST = test_support .HOST
1414
1515class FakeSocket :
16- def __init__ (self , text , fileclass = StringIO .StringIO ):
16+ def __init__ (self , text , fileclass = StringIO .StringIO , host = None , port = None ):
1717 self .text = text
1818 self .fileclass = fileclass
1919 self .data = ''
20+ self .host = host
21+ self .port = port
2022
2123 def sendall (self , data ):
2224 self .data += '' .join (data )
@@ -26,6 +28,9 @@ def makefile(self, mode, bufsize=None):
2628 raise httplib .UnimplementedFileMode ()
2729 return self .fileclass (self .text )
2830
31+ def close (self ):
32+ pass
33+
2934class EPipeSocket (FakeSocket ):
3035
3136 def __init__ (self , text , pipe_trigger ):
@@ -123,7 +128,7 @@ def test_putheader(self):
123128 conn .sock = FakeSocket (None )
124129 conn .putrequest ('GET' ,'/' )
125130 conn .putheader ('Content-length' ,42 )
126- self .assertTrue ('Content-length: 42' in conn ._buffer )
131+ self .assertIn ('Content-length: 42' , conn ._buffer )
127132
128133 def test_ipv6host_header (self ):
129134 # Default host header on IPv6 transaction should wrapped by [] if
@@ -153,6 +158,8 @@ def test_status_lines(self):
153158 sock = FakeSocket (body )
154159 resp = httplib .HTTPResponse (sock )
155160 resp .begin ()
161+ self .assertEqual (resp .read (0 ), '' ) # Issue #20007
162+ self .assertFalse (resp .isclosed ())
156163 self .assertEqual (resp .read (), 'Text' )
157164 self .assertTrue (resp .isclosed ())
158165
@@ -255,6 +262,13 @@ def test_read_head(self):
255262 if resp .read () != "" :
256263 self .fail ("Did not expect response from HEAD request" )
257264
265+ def test_too_many_headers (self ):
266+ headers = '\r \n ' .join ('Header%d: foo' % i for i in xrange (200 )) + '\r \n '
267+ text = ('HTTP/1.1 200 OK\r \n ' + headers )
268+ s = FakeSocket (text )
269+ r = httplib .HTTPResponse (s )
270+ self .assertRaises (httplib .HTTPException , r .begin )
271+
258272 def test_send_file (self ):
259273 expected = 'GET /foo HTTP/1.1\r \n Host: example.com\r \n ' \
260274 'Accept-Encoding: identity\r \n Content-Length:'
@@ -464,7 +478,7 @@ def testTimeoutAttribute(self):
464478 HTTPConnection and into the socket.
465479 '''
466480 # default -- use global socket timeout
467- self .assertTrue (socket .getdefaulttimeout () is None )
481+ self .assertIsNone (socket .getdefaulttimeout ())
468482 socket .setdefaulttimeout (30 )
469483 try :
470484 httpConn = httplib .HTTPConnection (HOST , TimeoutTest .PORT )
@@ -475,7 +489,7 @@ def testTimeoutAttribute(self):
475489 httpConn .close ()
476490
477491 # no timeout -- do not use global socket default
478- self .assertTrue (socket .getdefaulttimeout () is None )
492+ self .assertIsNone (socket .getdefaulttimeout ())
479493 socket .setdefaulttimeout (30 )
480494 try :
481495 httpConn = httplib .HTTPConnection (HOST , TimeoutTest .PORT ,
@@ -524,9 +538,48 @@ def test_host_port(self):
524538 self .fail ("Port incorrectly parsed: %s != %s" % (p , c .host ))
525539
526540
541+ class TunnelTests (TestCase ):
542+ def test_connect (self ):
543+ response_text = (
544+ 'HTTP/1.0 200 OK\r \n \r \n ' # Reply to CONNECT
545+ 'HTTP/1.1 200 OK\r \n ' # Reply to HEAD
546+ 'Content-Length: 42\r \n \r \n '
547+ )
548+
549+ def create_connection (address , timeout = None , source_address = None ):
550+ return FakeSocket (response_text , host = address [0 ], port = address [1 ])
551+
552+ conn = httplib .HTTPConnection ('proxy.com' )
553+ conn ._create_connection = create_connection
554+
555+ # Once connected, we should not be able to tunnel anymore
556+ conn .connect ()
557+ self .assertRaises (RuntimeError , conn .set_tunnel , 'destination.com' )
558+
559+ # But if close the connection, we are good.
560+ conn .close ()
561+ conn .set_tunnel ('destination.com' )
562+ conn .request ('HEAD' , '/' , '' )
563+
564+ self .assertEqual (conn .sock .host , 'proxy.com' )
565+ self .assertEqual (conn .sock .port , 80 )
566+ self .assertTrue ('CONNECT destination.com' in conn .sock .data )
567+ self .assertTrue ('Host: destination.com' in conn .sock .data )
568+
569+ self .assertTrue ('Host: proxy.com' not in conn .sock .data )
570+
571+ conn .close ()
572+
573+ conn .request ('PUT' , '/' , '' )
574+ self .assertEqual (conn .sock .host , 'proxy.com' )
575+ self .assertEqual (conn .sock .port , 80 )
576+ self .assertTrue ('CONNECT destination.com' in conn .sock .data )
577+ self .assertTrue ('Host: destination.com' in conn .sock .data )
578+
579+
527580def test_main (verbose = None ):
528581 test_support .run_unittest (HeaderTests , OfflineTest , BasicTest , TimeoutTest ,
529- HTTPSTimeoutTest , SourceAddressTest )
582+ HTTPSTimeoutTest , SourceAddressTest , TunnelTests )
530583
531584if __name__ == '__main__' :
532585 test_main ()
0 commit comments