blob: 6a20c6b81d2284e681b49c50a4074263c08368bc [file] [log] [blame]
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00001import httplib
2import StringIO
Jeremy Hylton121d34a2003-07-08 12:36:58 +00003import sys
Facundo Batista07c78be2007-03-23 18:54:07 +00004import socket
Jeremy Hylton121d34a2003-07-08 12:36:58 +00005
Jeremy Hylton2c178252004-08-07 16:28:14 +00006from unittest import TestCase
7
8from test import test_support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00009
10class FakeSocket:
Jeremy Hylton121d34a2003-07-08 12:36:58 +000011 def __init__(self, text, fileclass=StringIO.StringIO):
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000012 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000013 self.fileclass = fileclass
Martin v. Löwis040a9272006-11-12 10:32:47 +000014 self.data = ''
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000015
Jeremy Hylton2c178252004-08-07 16:28:14 +000016 def sendall(self, data):
Martin v. Löwis040a9272006-11-12 10:32:47 +000017 self.data += data
Jeremy Hylton2c178252004-08-07 16:28:14 +000018
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000019 def makefile(self, mode, bufsize=None):
20 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000021 raise httplib.UnimplementedFileMode()
Jeremy Hylton121d34a2003-07-08 12:36:58 +000022 return self.fileclass(self.text)
23
24class NoEOFStringIO(StringIO.StringIO):
25 """Like StringIO, but raises AssertionError on EOF.
26
27 This is used below to test that httplib doesn't try to read
28 more from the underlying file than it should.
29 """
30 def read(self, n=-1):
31 data = StringIO.StringIO.read(self, n)
32 if data == '':
33 raise AssertionError('caller tried to read past EOF')
34 return data
35
36 def readline(self, length=None):
37 data = StringIO.StringIO.readline(self, length)
38 if data == '':
39 raise AssertionError('caller tried to read past EOF')
40 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000041
Jeremy Hylton2c178252004-08-07 16:28:14 +000042
43class HeaderTests(TestCase):
44 def test_auto_headers(self):
45 # Some headers are added automatically, but should not be added by
46 # .request() if they are explicitly set.
47
48 import httplib
49
50 class HeaderCountingBuffer(list):
51 def __init__(self):
52 self.count = {}
53 def append(self, item):
54 kv = item.split(':')
55 if len(kv) > 1:
56 # item is a 'Key: Value' header string
57 lcKey = kv[0].lower()
58 self.count.setdefault(lcKey, 0)
59 self.count[lcKey] += 1
60 list.append(self, item)
61
62 for explicit_header in True, False:
63 for header in 'Content-length', 'Host', 'Accept-encoding':
64 conn = httplib.HTTPConnection('example.com')
65 conn.sock = FakeSocket('blahblahblah')
66 conn._buffer = HeaderCountingBuffer()
67
68 body = 'spamspamspam'
69 headers = {}
70 if explicit_header:
71 headers[header] = str(len(body))
72 conn.request('POST', '/', body, headers)
73 self.assertEqual(conn._buffer.count[header.lower()], 1)
74
Georg Brandl71a20892006-10-29 20:24:01 +000075class BasicTest(TestCase):
76 def test_status_lines(self):
77 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000078
Georg Brandl71a20892006-10-29 20:24:01 +000079 body = "HTTP/1.1 200 Ok\r\n\r\nText"
80 sock = FakeSocket(body)
81 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +000082 resp.begin()
Georg Brandl71a20892006-10-29 20:24:01 +000083 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +000084 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +000085
Georg Brandl71a20892006-10-29 20:24:01 +000086 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
87 sock = FakeSocket(body)
88 resp = httplib.HTTPResponse(sock)
89 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +000090
Facundo Batista70665902007-10-18 03:16:03 +000091 def test_partial_reads(self):
92 # if we have a lenght, the system knows when to close itself
93 # same behaviour than when we read the whole thing with read()
94 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
95 sock = FakeSocket(body)
96 resp = httplib.HTTPResponse(sock)
97 resp.begin()
98 self.assertEqual(resp.read(2), 'Te')
99 self.assertFalse(resp.isclosed())
100 self.assertEqual(resp.read(2), 'xt')
101 self.assertTrue(resp.isclosed())
102
Georg Brandl71a20892006-10-29 20:24:01 +0000103 def test_host_port(self):
104 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000105
Georg Brandl71a20892006-10-29 20:24:01 +0000106 for hp in ("www.python.org:abc", "www.python.org:"):
107 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
108
109 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", 8000),
110 ("www.python.org:80", "www.python.org", 80),
111 ("www.python.org", "www.python.org", 80),
112 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000113 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000114 c = http._conn
115 if h != c.host: self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
116 if p != c.port: self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000117
Georg Brandl71a20892006-10-29 20:24:01 +0000118 def test_response_headers(self):
119 # test response with multiple message headers with the same field name.
120 text = ('HTTP/1.1 200 OK\r\n'
121 'Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"\r\n'
122 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
123 ' Path="/acme"\r\n'
124 '\r\n'
125 'No body\r\n')
126 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
127 ', '
128 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
129 s = FakeSocket(text)
130 r = httplib.HTTPResponse(s)
131 r.begin()
132 cookies = r.getheader("Set-Cookie")
133 if cookies != hdr:
134 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000135
Georg Brandl71a20892006-10-29 20:24:01 +0000136 def test_read_head(self):
137 # Test that the library doesn't attempt to read any data
138 # from a HEAD request. (Tickles SF bug #622042.)
139 sock = FakeSocket(
140 'HTTP/1.1 200 OK\r\n'
141 'Content-Length: 14432\r\n'
142 '\r\n',
143 NoEOFStringIO)
144 resp = httplib.HTTPResponse(sock, method="HEAD")
145 resp.begin()
146 if resp.read() != "":
147 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000148
Martin v. Löwis040a9272006-11-12 10:32:47 +0000149 def test_send_file(self):
150 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
151 'Accept-Encoding: identity\r\nContent-Length:'
152
153 body = open(__file__, 'rb')
154 conn = httplib.HTTPConnection('example.com')
155 sock = FakeSocket(body)
156 conn.sock = sock
157 conn.request('GET', '/foo', body)
158 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000159
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000160class OfflineTest(TestCase):
161 def test_responses(self):
162 self.assertEquals(httplib.responses[httplib.NOT_FOUND], "Not Found")
163
Facundo Batista07c78be2007-03-23 18:54:07 +0000164PORT = 50003
165HOST = "localhost"
166
167class TimeoutTest(TestCase):
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000168
Facundo Batista07c78be2007-03-23 18:54:07 +0000169 def setUp(self):
170 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
171 self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
172 global PORT
173 PORT = test_support.bind_port(self.serv, HOST, PORT)
Facundo Batistaf1966292007-03-25 03:20:05 +0000174 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000175
176 def tearDown(self):
177 self.serv.close()
178 self.serv = None
179
180 def testTimeoutAttribute(self):
181 '''This will prove that the timeout gets through
182 HTTPConnection and into the socket.
183 '''
184 # default
185 httpConn = httplib.HTTPConnection(HOST, PORT)
186 httpConn.connect()
187 self.assertTrue(httpConn.sock.gettimeout() is None)
Facundo Batistaf1966292007-03-25 03:20:05 +0000188 httpConn.close()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000189
Facundo Batista07c78be2007-03-23 18:54:07 +0000190 # a value
Facundo Batista14553b02007-03-23 20:23:08 +0000191 httpConn = httplib.HTTPConnection(HOST, PORT, timeout=30)
Facundo Batista07c78be2007-03-23 18:54:07 +0000192 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000193 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000194 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000195
196 # None, having other default
197 previous = socket.getdefaulttimeout()
Facundo Batista14553b02007-03-23 20:23:08 +0000198 socket.setdefaulttimeout(30)
199 try:
200 httpConn = httplib.HTTPConnection(HOST, PORT, timeout=None)
201 httpConn.connect()
202 finally:
203 socket.setdefaulttimeout(previous)
204 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000205 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000206
207
Facundo Batista70f996b2007-05-21 17:32:32 +0000208class HTTPSTimeoutTest(TestCase):
209# XXX Here should be tests for HTTPS, there isn't any right now!
210
211 def test_attributes(self):
212 # simple test to check it's storing it
Thomas Wouters628e3bb2007-08-30 22:35:31 +0000213 if hasattr(httplib, 'HTTPSConnection'):
214 h = httplib.HTTPSConnection(HOST, PORT, timeout=30)
215 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000216
Jeremy Hylton2c178252004-08-07 16:28:14 +0000217def test_main(verbose=None):
Facundo Batista70f996b2007-05-21 17:32:32 +0000218 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, HTTPSTimeoutTest)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000219
Georg Brandl71a20892006-10-29 20:24:01 +0000220if __name__ == '__main__':
221 test_main()