blob: 74301ff39accb8330ab617104b0ed05237c2cff5 [file] [log] [blame]
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +00001import httplib
Antoine Pitrou72481782009-09-29 17:48:18 +00002import array
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00003import httplib
4import StringIO
Facundo Batista07c78be2007-03-23 18:54:07 +00005import socket
Victor Stinner2c6aee92010-07-24 02:46:16 +00006import errno
Jeremy Hylton121d34a2003-07-08 12:36:58 +00007
Gregory P. Smith9d325212010-01-03 02:06:07 +00008import unittest
9TestCase = unittest.TestCase
Jeremy Hylton2c178252004-08-07 16:28:14 +000010
11from test import test_support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000012
Trent Nelsone41b0062008-04-08 23:47:30 +000013HOST = test_support.HOST
14
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000015class FakeSocket:
Jeremy Hylton121d34a2003-07-08 12:36:58 +000016 def __init__(self, text, fileclass=StringIO.StringIO):
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000017 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000018 self.fileclass = fileclass
Martin v. Löwis040a9272006-11-12 10:32:47 +000019 self.data = ''
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000020
Jeremy Hylton2c178252004-08-07 16:28:14 +000021 def sendall(self, data):
Antoine Pitrou72481782009-09-29 17:48:18 +000022 self.data += ''.join(data)
Jeremy Hylton2c178252004-08-07 16:28:14 +000023
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000024 def makefile(self, mode, bufsize=None):
25 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000026 raise httplib.UnimplementedFileMode()
Jeremy Hylton121d34a2003-07-08 12:36:58 +000027 return self.fileclass(self.text)
28
Victor Stinner2c6aee92010-07-24 02:46:16 +000029class EPipeSocket(FakeSocket):
30
31 def __init__(self, text, pipe_trigger):
32 # When sendall() is called with pipe_trigger, raise EPIPE.
33 FakeSocket.__init__(self, text)
34 self.pipe_trigger = pipe_trigger
35
36 def sendall(self, data):
37 if self.pipe_trigger in data:
38 raise socket.error(errno.EPIPE, "gotcha")
39 self.data += data
40
41 def close(self):
42 pass
43
Jeremy Hylton121d34a2003-07-08 12:36:58 +000044class NoEOFStringIO(StringIO.StringIO):
45 """Like StringIO, but raises AssertionError on EOF.
46
47 This is used below to test that httplib doesn't try to read
48 more from the underlying file than it should.
49 """
50 def read(self, n=-1):
51 data = StringIO.StringIO.read(self, n)
52 if data == '':
53 raise AssertionError('caller tried to read past EOF')
54 return data
55
56 def readline(self, length=None):
57 data = StringIO.StringIO.readline(self, length)
58 if data == '':
59 raise AssertionError('caller tried to read past EOF')
60 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000061
Jeremy Hylton2c178252004-08-07 16:28:14 +000062
63class HeaderTests(TestCase):
64 def test_auto_headers(self):
65 # Some headers are added automatically, but should not be added by
66 # .request() if they are explicitly set.
67
Jeremy Hylton2c178252004-08-07 16:28:14 +000068 class HeaderCountingBuffer(list):
69 def __init__(self):
70 self.count = {}
71 def append(self, item):
72 kv = item.split(':')
73 if len(kv) > 1:
74 # item is a 'Key: Value' header string
75 lcKey = kv[0].lower()
76 self.count.setdefault(lcKey, 0)
77 self.count[lcKey] += 1
78 list.append(self, item)
79
80 for explicit_header in True, False:
81 for header in 'Content-length', 'Host', 'Accept-encoding':
82 conn = httplib.HTTPConnection('example.com')
83 conn.sock = FakeSocket('blahblahblah')
84 conn._buffer = HeaderCountingBuffer()
85
86 body = 'spamspamspam'
87 headers = {}
88 if explicit_header:
89 headers[header] = str(len(body))
90 conn.request('POST', '/', body, headers)
91 self.assertEqual(conn._buffer.count[header.lower()], 1)
92
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +000093 def test_putheader(self):
94 conn = httplib.HTTPConnection('example.com')
95 conn.sock = FakeSocket(None)
96 conn.putrequest('GET','/')
97 conn.putheader('Content-length',42)
98 self.assertTrue('Content-length: 42' in conn._buffer)
99
Georg Brandl71a20892006-10-29 20:24:01 +0000100class BasicTest(TestCase):
101 def test_status_lines(self):
102 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000103
Georg Brandl71a20892006-10-29 20:24:01 +0000104 body = "HTTP/1.1 200 Ok\r\n\r\nText"
105 sock = FakeSocket(body)
106 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000107 resp.begin()
Georg Brandl71a20892006-10-29 20:24:01 +0000108 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000109 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000110
Georg Brandl71a20892006-10-29 20:24:01 +0000111 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
112 sock = FakeSocket(body)
113 resp = httplib.HTTPResponse(sock)
114 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000115
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000116 def test_bad_status_repr(self):
117 exc = httplib.BadStatusLine('')
118 self.assertEquals(repr(exc), '''BadStatusLine("\'\'",)''')
119
Facundo Batista70665902007-10-18 03:16:03 +0000120 def test_partial_reads(self):
121 # if we have a lenght, the system knows when to close itself
122 # same behaviour than when we read the whole thing with read()
123 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
124 sock = FakeSocket(body)
125 resp = httplib.HTTPResponse(sock)
126 resp.begin()
127 self.assertEqual(resp.read(2), 'Te')
128 self.assertFalse(resp.isclosed())
129 self.assertEqual(resp.read(2), 'xt')
130 self.assertTrue(resp.isclosed())
131
Georg Brandl71a20892006-10-29 20:24:01 +0000132 def test_host_port(self):
133 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000134
Georg Brandl71a20892006-10-29 20:24:01 +0000135 for hp in ("www.python.org:abc", "www.python.org:"):
136 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
137
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000138 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
139 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000140 ("www.python.org:80", "www.python.org", 80),
141 ("www.python.org", "www.python.org", 80),
142 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000143 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000144 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000145 if h != c.host:
146 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
147 if p != c.port:
148 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000149
Georg Brandl71a20892006-10-29 20:24:01 +0000150 def test_response_headers(self):
151 # test response with multiple message headers with the same field name.
152 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000153 'Set-Cookie: Customer="WILE_E_COYOTE";'
154 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000155 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
156 ' Path="/acme"\r\n'
157 '\r\n'
158 'No body\r\n')
159 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
160 ', '
161 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
162 s = FakeSocket(text)
163 r = httplib.HTTPResponse(s)
164 r.begin()
165 cookies = r.getheader("Set-Cookie")
166 if cookies != hdr:
167 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000168
Georg Brandl71a20892006-10-29 20:24:01 +0000169 def test_read_head(self):
170 # Test that the library doesn't attempt to read any data
171 # from a HEAD request. (Tickles SF bug #622042.)
172 sock = FakeSocket(
173 'HTTP/1.1 200 OK\r\n'
174 'Content-Length: 14432\r\n'
175 '\r\n',
176 NoEOFStringIO)
177 resp = httplib.HTTPResponse(sock, method="HEAD")
178 resp.begin()
179 if resp.read() != "":
180 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000181
Martin v. Löwis040a9272006-11-12 10:32:47 +0000182 def test_send_file(self):
183 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
184 'Accept-Encoding: identity\r\nContent-Length:'
185
186 body = open(__file__, 'rb')
187 conn = httplib.HTTPConnection('example.com')
188 sock = FakeSocket(body)
189 conn.sock = sock
190 conn.request('GET', '/foo', body)
191 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000192
Antoine Pitrou72481782009-09-29 17:48:18 +0000193 def test_send(self):
194 expected = 'this is a test this is only a test'
195 conn = httplib.HTTPConnection('example.com')
196 sock = FakeSocket(None)
197 conn.sock = sock
198 conn.send(expected)
199 self.assertEquals(expected, sock.data)
200 sock.data = ''
201 conn.send(array.array('c', expected))
202 self.assertEquals(expected, sock.data)
203 sock.data = ''
204 conn.send(StringIO.StringIO(expected))
205 self.assertEquals(expected, sock.data)
206
Georg Brandl23635032008-02-24 00:03:22 +0000207 def test_chunked(self):
208 chunked_start = (
209 'HTTP/1.1 200 OK\r\n'
210 'Transfer-Encoding: chunked\r\n\r\n'
211 'a\r\n'
212 'hello worl\r\n'
213 '1\r\n'
214 'd\r\n'
215 )
216 sock = FakeSocket(chunked_start + '0\r\n')
217 resp = httplib.HTTPResponse(sock, method="GET")
218 resp.begin()
219 self.assertEquals(resp.read(), 'hello world')
220 resp.close()
221
222 for x in ('', 'foo\r\n'):
223 sock = FakeSocket(chunked_start + x)
224 resp = httplib.HTTPResponse(sock, method="GET")
225 resp.begin()
226 try:
227 resp.read()
228 except httplib.IncompleteRead, i:
229 self.assertEquals(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000230 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
231 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000232 else:
233 self.fail('IncompleteRead expected')
234 finally:
235 resp.close()
236
Senthil Kumaraned9204342010-04-28 17:20:43 +0000237 def test_chunked_head(self):
238 chunked_start = (
239 'HTTP/1.1 200 OK\r\n'
240 'Transfer-Encoding: chunked\r\n\r\n'
241 'a\r\n'
242 'hello world\r\n'
243 '1\r\n'
244 'd\r\n'
245 )
246 sock = FakeSocket(chunked_start + '0\r\n')
247 resp = httplib.HTTPResponse(sock, method="HEAD")
248 resp.begin()
249 self.assertEquals(resp.read(), '')
250 self.assertEquals(resp.status, 200)
251 self.assertEquals(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000252 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000253
Georg Brandl8c460d52008-02-24 00:14:24 +0000254 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000255 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
256 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000257 resp = httplib.HTTPResponse(sock, method="GET")
258 resp.begin()
259 self.assertEquals(resp.read(), 'Hello\r\n')
260 resp.close()
261
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000262 def test_incomplete_read(self):
263 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
264 resp = httplib.HTTPResponse(sock, method="GET")
265 resp.begin()
266 try:
267 resp.read()
268 except httplib.IncompleteRead as i:
269 self.assertEquals(i.partial, 'Hello\r\n')
270 self.assertEqual(repr(i),
271 "IncompleteRead(7 bytes read, 3 more expected)")
272 self.assertEqual(str(i),
273 "IncompleteRead(7 bytes read, 3 more expected)")
274 else:
275 self.fail('IncompleteRead expected')
276 finally:
277 resp.close()
278
Victor Stinner2c6aee92010-07-24 02:46:16 +0000279 def test_epipe(self):
280 sock = EPipeSocket(
281 "HTTP/1.0 401 Authorization Required\r\n"
282 "Content-type: text/html\r\n"
283 "WWW-Authenticate: Basic realm=\"example\"\r\n",
284 b"Content-Length")
285 conn = httplib.HTTPConnection("example.com")
286 conn.sock = sock
287 self.assertRaises(socket.error,
288 lambda: conn.request("PUT", "/url", "body"))
289 resp = conn.getresponse()
290 self.assertEqual(401, resp.status)
291 self.assertEqual("Basic realm=\"example\"",
292 resp.getheader("www-authenticate"))
293
Senthil Kumarand389cb52010-09-21 01:38:15 +0000294 def test_filenoattr(self):
295 # Just test the fileno attribute in the HTTPResponse Object.
296 body = "HTTP/1.1 200 Ok\r\n\r\nText"
297 sock = FakeSocket(body)
298 resp = httplib.HTTPResponse(sock)
299 self.assertTrue(hasattr(resp,'fileno'),
300 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000301
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000302class OfflineTest(TestCase):
303 def test_responses(self):
304 self.assertEquals(httplib.responses[httplib.NOT_FOUND], "Not Found")
305
Gregory P. Smith9d325212010-01-03 02:06:07 +0000306
307class SourceAddressTest(TestCase):
308 def setUp(self):
309 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
310 self.port = test_support.bind_port(self.serv)
311 self.source_port = test_support.find_unused_port()
312 self.serv.listen(5)
313 self.conn = None
314
315 def tearDown(self):
316 if self.conn:
317 self.conn.close()
318 self.conn = None
319 self.serv.close()
320 self.serv = None
321
322 def testHTTPConnectionSourceAddress(self):
323 self.conn = httplib.HTTPConnection(HOST, self.port,
324 source_address=('', self.source_port))
325 self.conn.connect()
326 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
327
328 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
329 'httplib.HTTPSConnection not defined')
330 def testHTTPSConnectionSourceAddress(self):
331 self.conn = httplib.HTTPSConnection(HOST, self.port,
332 source_address=('', self.source_port))
333 # We don't test anything here other the constructor not barfing as
334 # this code doesn't deal with setting up an active running SSL server
335 # for an ssl_wrapped connect() to actually return from.
336
337
Facundo Batista07c78be2007-03-23 18:54:07 +0000338class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000339 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000340
Facundo Batista07c78be2007-03-23 18:54:07 +0000341 def setUp(self):
342 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000343 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000344 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000345
346 def tearDown(self):
347 self.serv.close()
348 self.serv = None
349
350 def testTimeoutAttribute(self):
351 '''This will prove that the timeout gets through
352 HTTPConnection and into the socket.
353 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000354 # default -- use global socket timeout
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000355 self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000356 socket.setdefaulttimeout(30)
357 try:
358 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
359 httpConn.connect()
360 finally:
361 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000362 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000363 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000364
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000365 # no timeout -- do not use global socket default
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000366 self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batista14553b02007-03-23 20:23:08 +0000367 socket.setdefaulttimeout(30)
368 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000369 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
370 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000371 httpConn.connect()
372 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000373 socket.setdefaulttimeout(None)
374 self.assertEqual(httpConn.sock.gettimeout(), None)
375 httpConn.close()
376
377 # a value
378 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
379 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000380 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000381 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000382
383
Facundo Batista70f996b2007-05-21 17:32:32 +0000384class HTTPSTimeoutTest(TestCase):
385# XXX Here should be tests for HTTPS, there isn't any right now!
386
387 def test_attributes(self):
388 # simple test to check it's storing it
Thomas Wouters628e3bb2007-08-30 22:35:31 +0000389 if hasattr(httplib, 'HTTPSConnection'):
Trent Nelsone41b0062008-04-08 23:47:30 +0000390 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
Thomas Wouters628e3bb2007-08-30 22:35:31 +0000391 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000392
Jeremy Hylton2c178252004-08-07 16:28:14 +0000393def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000394 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Gregory P. Smith9d325212010-01-03 02:06:07 +0000395 HTTPSTimeoutTest, SourceAddressTest)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000396
Georg Brandl71a20892006-10-29 20:24:01 +0000397if __name__ == '__main__':
398 test_main()