blob: fcbddd0f327eaf55533de7c01479cc8506a4e250 [file] [log] [blame]
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00001import httplib
2import StringIO
Facundo Batista07c78be2007-03-23 18:54:07 +00003import socket
Jeremy Hylton121d34a2003-07-08 12:36:58 +00004
Jeremy Hylton2c178252004-08-07 16:28:14 +00005from unittest import TestCase
6
7from test import test_support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00008
Trent Nelsone41b0062008-04-08 23:47:30 +00009HOST = test_support.HOST
10
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000011class FakeSocket:
Jeremy Hylton121d34a2003-07-08 12:36:58 +000012 def __init__(self, text, fileclass=StringIO.StringIO):
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000013 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000014 self.fileclass = fileclass
Martin v. Löwis040a9272006-11-12 10:32:47 +000015 self.data = ''
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000016
Jeremy Hylton2c178252004-08-07 16:28:14 +000017 def sendall(self, data):
Martin v. Löwis040a9272006-11-12 10:32:47 +000018 self.data += data
Jeremy Hylton2c178252004-08-07 16:28:14 +000019
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000020 def makefile(self, mode, bufsize=None):
21 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000022 raise httplib.UnimplementedFileMode()
Jeremy Hylton121d34a2003-07-08 12:36:58 +000023 return self.fileclass(self.text)
24
25class NoEOFStringIO(StringIO.StringIO):
26 """Like StringIO, but raises AssertionError on EOF.
27
28 This is used below to test that httplib doesn't try to read
29 more from the underlying file than it should.
30 """
31 def read(self, n=-1):
32 data = StringIO.StringIO.read(self, n)
33 if data == '':
34 raise AssertionError('caller tried to read past EOF')
35 return data
36
37 def readline(self, length=None):
38 data = StringIO.StringIO.readline(self, length)
39 if data == '':
40 raise AssertionError('caller tried to read past EOF')
41 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000042
Jeremy Hylton2c178252004-08-07 16:28:14 +000043
44class HeaderTests(TestCase):
45 def test_auto_headers(self):
46 # Some headers are added automatically, but should not be added by
47 # .request() if they are explicitly set.
48
49 import httplib
50
51 class HeaderCountingBuffer(list):
52 def __init__(self):
53 self.count = {}
54 def append(self, item):
55 kv = item.split(':')
56 if len(kv) > 1:
57 # item is a 'Key: Value' header string
58 lcKey = kv[0].lower()
59 self.count.setdefault(lcKey, 0)
60 self.count[lcKey] += 1
61 list.append(self, item)
62
63 for explicit_header in True, False:
64 for header in 'Content-length', 'Host', 'Accept-encoding':
65 conn = httplib.HTTPConnection('example.com')
66 conn.sock = FakeSocket('blahblahblah')
67 conn._buffer = HeaderCountingBuffer()
68
69 body = 'spamspamspam'
70 headers = {}
71 if explicit_header:
72 headers[header] = str(len(body))
73 conn.request('POST', '/', body, headers)
74 self.assertEqual(conn._buffer.count[header.lower()], 1)
75
Georg Brandl71a20892006-10-29 20:24:01 +000076class BasicTest(TestCase):
77 def test_status_lines(self):
78 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000079
Georg Brandl71a20892006-10-29 20:24:01 +000080 body = "HTTP/1.1 200 Ok\r\n\r\nText"
81 sock = FakeSocket(body)
82 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +000083 resp.begin()
Georg Brandl71a20892006-10-29 20:24:01 +000084 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +000085 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +000086
Georg Brandl71a20892006-10-29 20:24:01 +000087 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
88 sock = FakeSocket(body)
89 resp = httplib.HTTPResponse(sock)
90 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +000091
Facundo Batista70665902007-10-18 03:16:03 +000092 def test_partial_reads(self):
93 # if we have a lenght, the system knows when to close itself
94 # same behaviour than when we read the whole thing with read()
95 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
96 sock = FakeSocket(body)
97 resp = httplib.HTTPResponse(sock)
98 resp.begin()
99 self.assertEqual(resp.read(2), 'Te')
100 self.assertFalse(resp.isclosed())
101 self.assertEqual(resp.read(2), 'xt')
102 self.assertTrue(resp.isclosed())
103
Georg Brandl71a20892006-10-29 20:24:01 +0000104 def test_host_port(self):
105 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000106
Georg Brandl71a20892006-10-29 20:24:01 +0000107 for hp in ("www.python.org:abc", "www.python.org:"):
108 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
109
110 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", 8000),
111 ("www.python.org:80", "www.python.org", 80),
112 ("www.python.org", "www.python.org", 80),
113 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000114 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000115 c = http._conn
116 if h != c.host: self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
117 if p != c.port: self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000118
Georg Brandl71a20892006-10-29 20:24:01 +0000119 def test_response_headers(self):
120 # test response with multiple message headers with the same field name.
121 text = ('HTTP/1.1 200 OK\r\n'
122 'Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"\r\n'
123 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
124 ' Path="/acme"\r\n'
125 '\r\n'
126 'No body\r\n')
127 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
128 ', '
129 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
130 s = FakeSocket(text)
131 r = httplib.HTTPResponse(s)
132 r.begin()
133 cookies = r.getheader("Set-Cookie")
134 if cookies != hdr:
135 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000136
Georg Brandl71a20892006-10-29 20:24:01 +0000137 def test_read_head(self):
138 # Test that the library doesn't attempt to read any data
139 # from a HEAD request. (Tickles SF bug #622042.)
140 sock = FakeSocket(
141 'HTTP/1.1 200 OK\r\n'
142 'Content-Length: 14432\r\n'
143 '\r\n',
144 NoEOFStringIO)
145 resp = httplib.HTTPResponse(sock, method="HEAD")
146 resp.begin()
147 if resp.read() != "":
148 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000149
Martin v. Löwis040a9272006-11-12 10:32:47 +0000150 def test_send_file(self):
151 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
152 'Accept-Encoding: identity\r\nContent-Length:'
153
154 body = open(__file__, 'rb')
155 conn = httplib.HTTPConnection('example.com')
156 sock = FakeSocket(body)
157 conn.sock = sock
158 conn.request('GET', '/foo', body)
159 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000160
Georg Brandl23635032008-02-24 00:03:22 +0000161 def test_chunked(self):
162 chunked_start = (
163 'HTTP/1.1 200 OK\r\n'
164 'Transfer-Encoding: chunked\r\n\r\n'
165 'a\r\n'
166 'hello worl\r\n'
167 '1\r\n'
168 'd\r\n'
169 )
170 sock = FakeSocket(chunked_start + '0\r\n')
171 resp = httplib.HTTPResponse(sock, method="GET")
172 resp.begin()
173 self.assertEquals(resp.read(), 'hello world')
174 resp.close()
175
176 for x in ('', 'foo\r\n'):
177 sock = FakeSocket(chunked_start + x)
178 resp = httplib.HTTPResponse(sock, method="GET")
179 resp.begin()
180 try:
181 resp.read()
182 except httplib.IncompleteRead, i:
183 self.assertEquals(i.partial, 'hello world')
184 else:
185 self.fail('IncompleteRead expected')
186 finally:
187 resp.close()
188
Georg Brandl8c460d52008-02-24 00:14:24 +0000189 def test_negative_content_length(self):
190 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\nHello\r\n')
191 resp = httplib.HTTPResponse(sock, method="GET")
192 resp.begin()
193 self.assertEquals(resp.read(), 'Hello\r\n')
194 resp.close()
195
Georg Brandl23635032008-02-24 00:03:22 +0000196
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000197class OfflineTest(TestCase):
198 def test_responses(self):
199 self.assertEquals(httplib.responses[httplib.NOT_FOUND], "Not Found")
200
Facundo Batista07c78be2007-03-23 18:54:07 +0000201class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000202 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000203
Facundo Batista07c78be2007-03-23 18:54:07 +0000204 def setUp(self):
205 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000206 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000207 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000208
209 def tearDown(self):
210 self.serv.close()
211 self.serv = None
212
213 def testTimeoutAttribute(self):
214 '''This will prove that the timeout gets through
215 HTTPConnection and into the socket.
216 '''
217 # default
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000218 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
Facundo Batista07c78be2007-03-23 18:54:07 +0000219 httpConn.connect()
220 self.assertTrue(httpConn.sock.gettimeout() is None)
Facundo Batistaf1966292007-03-25 03:20:05 +0000221 httpConn.close()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000222
Facundo Batista07c78be2007-03-23 18:54:07 +0000223 # a value
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000224 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
Facundo Batista07c78be2007-03-23 18:54:07 +0000225 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000226 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000227 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000228
229 # None, having other default
230 previous = socket.getdefaulttimeout()
Facundo Batista14553b02007-03-23 20:23:08 +0000231 socket.setdefaulttimeout(30)
232 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000233 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
234 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000235 httpConn.connect()
236 finally:
237 socket.setdefaulttimeout(previous)
238 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000239 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000240
241
Facundo Batista70f996b2007-05-21 17:32:32 +0000242class HTTPSTimeoutTest(TestCase):
243# XXX Here should be tests for HTTPS, there isn't any right now!
244
245 def test_attributes(self):
246 # simple test to check it's storing it
Thomas Wouters628e3bb2007-08-30 22:35:31 +0000247 if hasattr(httplib, 'HTTPSConnection'):
Trent Nelsone41b0062008-04-08 23:47:30 +0000248 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
Thomas Wouters628e3bb2007-08-30 22:35:31 +0000249 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000250
Jeremy Hylton2c178252004-08-07 16:28:14 +0000251def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000252 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
253 HTTPSTimeoutTest)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000254
Georg Brandl71a20892006-10-29 20:24:01 +0000255if __name__ == '__main__':
256 test_main()