Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(56)

Side by Side Diff: Lib/test/test_httplib.py

Issue 7776: http.client.HTTPConnection tunneling is broken
Patch Set: Created 6 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Lib/http/client.py ('k') | Misc/NEWS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 import errno 1 import errno
2 from http import client 2 from http import client
3 import io 3 import io
4 import os 4 import os
5 import array 5 import array
6 import socket 6 import socket
7 7
8 import unittest 8 import unittest
9 TestCase = unittest.TestCase 9 TestCase = unittest.TestCase
10 10
11 from test import support 11 from test import support
12 12
13 here = os.path.dirname(__file__) 13 here = os.path.dirname(__file__)
14 # Self-signed cert file for 'localhost' 14 # Self-signed cert file for 'localhost'
15 CERT_localhost = os.path.join(here, 'keycert.pem') 15 CERT_localhost = os.path.join(here, 'keycert.pem')
16 # Self-signed cert file for 'fakehostname' 16 # Self-signed cert file for 'fakehostname'
17 CERT_fakehostname = os.path.join(here, 'keycert2.pem') 17 CERT_fakehostname = os.path.join(here, 'keycert2.pem')
18 # Root cert file (CA) for svn.python.org's cert 18 # Root cert file (CA) for svn.python.org's cert
19 CACERT_svn_python_org = os.path.join(here, 'https_svn_python_org_root.pem') 19 CACERT_svn_python_org = os.path.join(here, 'https_svn_python_org_root.pem')
20 20
21 HOST = support.HOST 21 HOST = support.HOST
22 22
23 class FakeSocket: 23 class FakeSocket:
24 def __init__(self, text, fileclass=io.BytesIO): 24 def __init__(self, text, fileclass=io.BytesIO, host=None, port=None):
25 if isinstance(text, str): 25 if isinstance(text, str):
26 text = text.encode("ascii") 26 text = text.encode("ascii")
27 self.text = text 27 self.text = text
28 self.fileclass = fileclass 28 self.fileclass = fileclass
29 self.data = b'' 29 self.data = b''
30 self.sendall_calls = 0 30 self.sendall_calls = 0
31 self.host = host
32 self.port = port
31 33
32 def sendall(self, data): 34 def sendall(self, data):
33 self.sendall_calls += 1 35 self.sendall_calls += 1
34 self.data += data 36 self.data += data
35 37
36 def makefile(self, mode, bufsize=None): 38 def makefile(self, mode, bufsize=None):
37 if mode != 'r' and mode != 'rb': 39 if mode != 'r' and mode != 'rb':
38 raise client.UnimplementedFileMode() 40 raise client.UnimplementedFileMode()
39 return self.fileclass(self.text) 41 return self.fileclass(self.text)
42
43 def close(self):
44 pass
40 45
41 class EPipeSocket(FakeSocket): 46 class EPipeSocket(FakeSocket):
42 47
43 def __init__(self, text, pipe_trigger): 48 def __init__(self, text, pipe_trigger):
44 # When sendall() is called with pipe_trigger, raise EPIPE. 49 # When sendall() is called with pipe_trigger, raise EPIPE.
45 FakeSocket.__init__(self, text) 50 FakeSocket.__init__(self, text)
46 self.pipe_trigger = pipe_trigger 51 self.pipe_trigger = pipe_trigger
47 52
48 def sendall(self, data): 53 def sendall(self, data):
49 if self.pipe_trigger in data: 54 if self.pipe_trigger in data:
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 header = self.resp.getheader('No-Such-Header', ('default', 'values')) 967 header = self.resp.getheader('No-Such-Header', ('default', 'values'))
963 self.assertEqual(header, 'default, values') 968 self.assertEqual(header, 'default, values')
964 969
965 def test_getting_nonexistent_header_without_default(self): 970 def test_getting_nonexistent_header_without_default(self):
966 header = self.resp.getheader('No-Such-Header') 971 header = self.resp.getheader('No-Such-Header')
967 self.assertEqual(header, None) 972 self.assertEqual(header, None)
968 973
969 def test_getting_header_defaultint(self): 974 def test_getting_header_defaultint(self):
970 header = self.resp.getheader('No-Such-Header',default=42) 975 header = self.resp.getheader('No-Such-Header',default=42)
971 self.assertEqual(header, 42) 976 self.assertEqual(header, 42)
977
978 class TunnelTests(TestCase):
979
980 def test_connect(self):
981 response_text = (
982 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
983 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
984 'Content-Length: 42\r\n\r\n'
985 )
986
987 def create_connection(address, timeout=None, source_address=None):
988 return FakeSocket(response_text, host=address[0],
989 port=address[1])
990
991 conn = client.HTTPConnection('proxy.com')
992 conn._create_connection = create_connection
993
994 # Once connected, we shouldn't be able to tunnel anymore
995 conn.connect()
996 self.assertRaises(RuntimeError, conn.set_tunnel,
997 'destination.com')
998
999 # But if we close the connection, we're good
1000 conn.close()
1001 conn.set_tunnel('destination.com')
1002 conn.request('HEAD', '/', '')
1003
1004 self.assertEqual(conn.sock.host, 'proxy.com')
1005 self.assertEqual(conn.sock.port, 80)
1006 self.assertTrue(b'CONNECT destination.com' in conn.sock.data)
1007 self.assertTrue(b'Host: destination.com' in conn.sock.data)
1008
1009 # This test should be removed if CONNECT ever gets
1010 # HTTP/1.1 blessing
1011 self.assertTrue(b'Host: proxy.com' not in conn.sock.data)
1012
1013 conn.close()
1014 conn.request('PUT', '/', '')
1015 self.assertEqual(conn.sock.host, 'proxy.com')
1016 self.assertEqual(conn.sock.port, 80)
1017 self.assertTrue(b'CONNECT destination.com' in conn.sock.data)
1018 self.assertTrue(b'Host: destination.com' in conn.sock.data)
972 1019
973 def test_main(verbose=None): 1020 def test_main(verbose=None):
974 support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, 1021 support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
975 HTTPSTest, RequestBodyTest, SourceAddressTest, 1022 HTTPSTest, RequestBodyTest, SourceAddressTest,
976 HTTPResponseTest) 1023 HTTPResponseTest, TunnelTests)
977 1024
978 if __name__ == '__main__': 1025 if __name__ == '__main__':
979 test_main() 1026 test_main()
OLDNEW
« no previous file with comments | « Lib/http/client.py ('k') | Misc/NEWS » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+