blob: a72f6f7ff1c27ce6395a76ae71ba92ce1924fbac [file] [log] [blame]
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +00001import httplib
R David Murrayb4b000f2015-03-22 15:15:44 -04002import itertools
Antoine Pitrou72481782009-09-29 17:48:18 +00003import array
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00004import StringIO
Facundo Batista07c78be2007-03-23 18:54:07 +00005import socket
Victor Stinner2c6aee92010-07-24 02:46:16 +00006import errno
Benjamin Petersone3e7d402014-11-23 21:02:02 -06007import os
Serhiy Storchaka80573bb2015-05-16 18:58:41 +03008import tempfile
Jeremy Hylton121d34a2003-07-08 12:36:58 +00009
Gregory P. Smith9d325212010-01-03 02:06:07 +000010import unittest
11TestCase = unittest.TestCase
Jeremy Hylton2c178252004-08-07 16:28:14 +000012
13from test import test_support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000014
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -060015here = os.path.dirname(__file__)
16# Self-signed cert file for 'localhost'
17CERT_localhost = os.path.join(here, 'keycert.pem')
18# Self-signed cert file for 'fakehostname'
19CERT_fakehostname = os.path.join(here, 'keycert2.pem')
20# Self-signed cert file for self-signed.pythontest.net
21CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
22
Trent Nelsone41b0062008-04-08 23:47:30 +000023HOST = test_support.HOST
24
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000025class FakeSocket:
Senthil Kumaran36f28f72014-05-16 18:51:46 -070026 def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000027 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000028 self.fileclass = fileclass
Martin v. Löwis040a9272006-11-12 10:32:47 +000029 self.data = ''
Serhiy Storchakad862db02014-12-01 13:07:28 +020030 self.file_closed = False
Senthil Kumaran36f28f72014-05-16 18:51:46 -070031 self.host = host
32 self.port = port
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000033
Jeremy Hylton2c178252004-08-07 16:28:14 +000034 def sendall(self, data):
Antoine Pitrou72481782009-09-29 17:48:18 +000035 self.data += ''.join(data)
Jeremy Hylton2c178252004-08-07 16:28:14 +000036
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000037 def makefile(self, mode, bufsize=None):
38 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000039 raise httplib.UnimplementedFileMode()
Serhiy Storchakad862db02014-12-01 13:07:28 +020040 # keep the file around so we can check how much was read from it
41 self.file = self.fileclass(self.text)
42 self.file.close = self.file_close #nerf close ()
43 return self.file
44
45 def file_close(self):
46 self.file_closed = True
Jeremy Hylton121d34a2003-07-08 12:36:58 +000047
Senthil Kumaran36f28f72014-05-16 18:51:46 -070048 def close(self):
49 pass
50
Victor Stinner2c6aee92010-07-24 02:46:16 +000051class EPipeSocket(FakeSocket):
52
53 def __init__(self, text, pipe_trigger):
54 # When sendall() is called with pipe_trigger, raise EPIPE.
55 FakeSocket.__init__(self, text)
56 self.pipe_trigger = pipe_trigger
57
58 def sendall(self, data):
59 if self.pipe_trigger in data:
60 raise socket.error(errno.EPIPE, "gotcha")
61 self.data += data
62
63 def close(self):
64 pass
65
Jeremy Hylton121d34a2003-07-08 12:36:58 +000066class NoEOFStringIO(StringIO.StringIO):
67 """Like StringIO, but raises AssertionError on EOF.
68
69 This is used below to test that httplib doesn't try to read
70 more from the underlying file than it should.
71 """
72 def read(self, n=-1):
73 data = StringIO.StringIO.read(self, n)
74 if data == '':
75 raise AssertionError('caller tried to read past EOF')
76 return data
77
78 def readline(self, length=None):
79 data = StringIO.StringIO.readline(self, length)
80 if data == '':
81 raise AssertionError('caller tried to read past EOF')
82 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000083
Jeremy Hylton2c178252004-08-07 16:28:14 +000084
85class HeaderTests(TestCase):
86 def test_auto_headers(self):
87 # Some headers are added automatically, but should not be added by
88 # .request() if they are explicitly set.
89
Jeremy Hylton2c178252004-08-07 16:28:14 +000090 class HeaderCountingBuffer(list):
91 def __init__(self):
92 self.count = {}
93 def append(self, item):
94 kv = item.split(':')
95 if len(kv) > 1:
96 # item is a 'Key: Value' header string
97 lcKey = kv[0].lower()
98 self.count.setdefault(lcKey, 0)
99 self.count[lcKey] += 1
100 list.append(self, item)
101
102 for explicit_header in True, False:
103 for header in 'Content-length', 'Host', 'Accept-encoding':
104 conn = httplib.HTTPConnection('example.com')
105 conn.sock = FakeSocket('blahblahblah')
106 conn._buffer = HeaderCountingBuffer()
107
108 body = 'spamspamspam'
109 headers = {}
110 if explicit_header:
111 headers[header] = str(len(body))
112 conn.request('POST', '/', body, headers)
113 self.assertEqual(conn._buffer.count[header.lower()], 1)
114
Senthil Kumaran618802d2012-05-19 16:52:21 +0800115 def test_content_length_0(self):
116
117 class ContentLengthChecker(list):
118 def __init__(self):
119 list.__init__(self)
120 self.content_length = None
121 def append(self, item):
122 kv = item.split(':', 1)
123 if len(kv) > 1 and kv[0].lower() == 'content-length':
124 self.content_length = kv[1].strip()
125 list.append(self, item)
126
R David Murrayb4b000f2015-03-22 15:15:44 -0400127 # Here, we're testing that methods expecting a body get a
128 # content-length set to zero if the body is empty (either None or '')
129 bodies = (None, '')
130 methods_with_body = ('PUT', 'POST', 'PATCH')
131 for method, body in itertools.product(methods_with_body, bodies):
132 conn = httplib.HTTPConnection('example.com')
133 conn.sock = FakeSocket(None)
134 conn._buffer = ContentLengthChecker()
135 conn.request(method, '/', body)
136 self.assertEqual(
137 conn._buffer.content_length, '0',
138 'Header Content-Length incorrect on {}'.format(method)
139 )
Senthil Kumaran618802d2012-05-19 16:52:21 +0800140
R David Murrayb4b000f2015-03-22 15:15:44 -0400141 # For these methods, we make sure that content-length is not set when
142 # the body is None because it might cause unexpected behaviour on the
143 # server.
144 methods_without_body = (
145 'GET', 'CONNECT', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE',
146 )
147 for method in methods_without_body:
148 conn = httplib.HTTPConnection('example.com')
149 conn.sock = FakeSocket(None)
150 conn._buffer = ContentLengthChecker()
151 conn.request(method, '/', None)
152 self.assertEqual(
153 conn._buffer.content_length, None,
154 'Header Content-Length set for empty body on {}'.format(method)
155 )
156
157 # If the body is set to '', that's considered to be "present but
158 # empty" rather than "missing", so content length would be set, even
159 # for methods that don't expect a body.
160 for method in methods_without_body:
161 conn = httplib.HTTPConnection('example.com')
162 conn.sock = FakeSocket(None)
163 conn._buffer = ContentLengthChecker()
164 conn.request(method, '/', '')
165 self.assertEqual(
166 conn._buffer.content_length, '0',
167 'Header Content-Length incorrect on {}'.format(method)
168 )
169
170 # If the body is set, make sure Content-Length is set.
171 for method in itertools.chain(methods_without_body, methods_with_body):
172 conn = httplib.HTTPConnection('example.com')
173 conn.sock = FakeSocket(None)
174 conn._buffer = ContentLengthChecker()
175 conn.request(method, '/', ' ')
176 self.assertEqual(
177 conn._buffer.content_length, '1',
178 'Header Content-Length incorrect on {}'.format(method)
179 )
Senthil Kumaran618802d2012-05-19 16:52:21 +0800180
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000181 def test_putheader(self):
182 conn = httplib.HTTPConnection('example.com')
183 conn.sock = FakeSocket(None)
184 conn.putrequest('GET','/')
185 conn.putheader('Content-length',42)
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200186 self.assertIn('Content-length: 42', conn._buffer)
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000187
Serhiy Storchaka59bdf632015-03-12 11:12:51 +0200188 conn.putheader('Foo', ' bar ')
189 self.assertIn(b'Foo: bar ', conn._buffer)
190 conn.putheader('Bar', '\tbaz\t')
191 self.assertIn(b'Bar: \tbaz\t', conn._buffer)
192 conn.putheader('Authorization', 'Bearer mytoken')
193 self.assertIn(b'Authorization: Bearer mytoken', conn._buffer)
194 conn.putheader('IterHeader', 'IterA', 'IterB')
195 self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer)
196 conn.putheader('LatinHeader', b'\xFF')
197 self.assertIn(b'LatinHeader: \xFF', conn._buffer)
198 conn.putheader('Utf8Header', b'\xc3\x80')
199 self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer)
200 conn.putheader('C1-Control', b'next\x85line')
201 self.assertIn(b'C1-Control: next\x85line', conn._buffer)
202 conn.putheader('Embedded-Fold-Space', 'is\r\n allowed')
203 self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer)
204 conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed')
205 self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer)
206 conn.putheader('Key Space', 'value')
207 self.assertIn(b'Key Space: value', conn._buffer)
208 conn.putheader('KeySpace ', 'value')
209 self.assertIn(b'KeySpace : value', conn._buffer)
210 conn.putheader(b'Nonbreak\xa0Space', 'value')
211 self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer)
212 conn.putheader(b'\xa0NonbreakSpace', 'value')
213 self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer)
214
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000215 def test_ipv6host_header(self):
216 # Default host header on IPv6 transaction should wrapped by [] if
217 # its actual IPv6 address
218 expected = 'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
219 'Accept-Encoding: identity\r\n\r\n'
220 conn = httplib.HTTPConnection('[2001::]:81')
221 sock = FakeSocket('')
222 conn.sock = sock
223 conn.request('GET', '/foo')
224 self.assertTrue(sock.data.startswith(expected))
225
226 expected = 'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
227 'Accept-Encoding: identity\r\n\r\n'
228 conn = httplib.HTTPConnection('[2001:102A::]')
229 sock = FakeSocket('')
230 conn.sock = sock
231 conn.request('GET', '/foo')
232 self.assertTrue(sock.data.startswith(expected))
233
Benjamin Petersonbfd976f2015-01-25 23:34:42 -0500234 def test_malformed_headers_coped_with(self):
235 # Issue 19996
236 body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n"
237 sock = FakeSocket(body)
238 resp = httplib.HTTPResponse(sock)
239 resp.begin()
240
241 self.assertEqual(resp.getheader('First'), 'val')
242 self.assertEqual(resp.getheader('Second'), 'val')
243
Serhiy Storchaka59bdf632015-03-12 11:12:51 +0200244 def test_invalid_headers(self):
245 conn = httplib.HTTPConnection('example.com')
246 conn.sock = FakeSocket('')
247 conn.putrequest('GET', '/')
248
249 # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no
250 # longer allowed in header names
251 cases = (
252 (b'Invalid\r\nName', b'ValidValue'),
253 (b'Invalid\rName', b'ValidValue'),
254 (b'Invalid\nName', b'ValidValue'),
255 (b'\r\nInvalidName', b'ValidValue'),
256 (b'\rInvalidName', b'ValidValue'),
257 (b'\nInvalidName', b'ValidValue'),
258 (b' InvalidName', b'ValidValue'),
259 (b'\tInvalidName', b'ValidValue'),
260 (b'Invalid:Name', b'ValidValue'),
261 (b':InvalidName', b'ValidValue'),
262 (b'ValidName', b'Invalid\r\nValue'),
263 (b'ValidName', b'Invalid\rValue'),
264 (b'ValidName', b'Invalid\nValue'),
265 (b'ValidName', b'InvalidValue\r\n'),
266 (b'ValidName', b'InvalidValue\r'),
267 (b'ValidName', b'InvalidValue\n'),
268 )
269 for name, value in cases:
270 with self.assertRaisesRegexp(ValueError, 'Invalid header'):
271 conn.putheader(name, value)
272
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000273
Georg Brandl71a20892006-10-29 20:24:01 +0000274class BasicTest(TestCase):
275 def test_status_lines(self):
276 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000277
Georg Brandl71a20892006-10-29 20:24:01 +0000278 body = "HTTP/1.1 200 Ok\r\n\r\nText"
279 sock = FakeSocket(body)
280 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000281 resp.begin()
Serhiy Storchakac97f5ed2013-12-17 21:49:48 +0200282 self.assertEqual(resp.read(0), '') # Issue #20007
283 self.assertFalse(resp.isclosed())
Georg Brandl71a20892006-10-29 20:24:01 +0000284 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000285 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000286
Georg Brandl71a20892006-10-29 20:24:01 +0000287 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
288 sock = FakeSocket(body)
289 resp = httplib.HTTPResponse(sock)
290 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000291
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000292 def test_bad_status_repr(self):
293 exc = httplib.BadStatusLine('')
Ezio Melotti2623a372010-11-21 13:34:58 +0000294 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000295
Facundo Batista70665902007-10-18 03:16:03 +0000296 def test_partial_reads(self):
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100297 # if we have a length, the system knows when to close itself
Facundo Batista70665902007-10-18 03:16:03 +0000298 # same behaviour than when we read the whole thing with read()
299 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
300 sock = FakeSocket(body)
301 resp = httplib.HTTPResponse(sock)
302 resp.begin()
303 self.assertEqual(resp.read(2), 'Te')
304 self.assertFalse(resp.isclosed())
305 self.assertEqual(resp.read(2), 'xt')
306 self.assertTrue(resp.isclosed())
307
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100308 def test_partial_reads_no_content_length(self):
309 # when no length is present, the socket should be gracefully closed when
310 # all data was read
311 body = "HTTP/1.1 200 Ok\r\n\r\nText"
312 sock = FakeSocket(body)
313 resp = httplib.HTTPResponse(sock)
314 resp.begin()
315 self.assertEqual(resp.read(2), 'Te')
316 self.assertFalse(resp.isclosed())
317 self.assertEqual(resp.read(2), 'xt')
318 self.assertEqual(resp.read(1), '')
319 self.assertTrue(resp.isclosed())
320
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100321 def test_partial_reads_incomplete_body(self):
322 # if the server shuts down the connection before the whole
323 # content-length is delivered, the socket is gracefully closed
324 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
325 sock = FakeSocket(body)
326 resp = httplib.HTTPResponse(sock)
327 resp.begin()
328 self.assertEqual(resp.read(2), 'Te')
329 self.assertFalse(resp.isclosed())
330 self.assertEqual(resp.read(2), 'xt')
331 self.assertEqual(resp.read(1), '')
332 self.assertTrue(resp.isclosed())
333
Georg Brandl71a20892006-10-29 20:24:01 +0000334 def test_host_port(self):
335 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000336
Łukasz Langa7a153902011-10-18 17:16:00 +0200337 # Note that httplib does not accept user:password@ in the host-port.
338 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Georg Brandl71a20892006-10-29 20:24:01 +0000339 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
340
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000341 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
342 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000343 ("www.python.org:80", "www.python.org", 80),
344 ("www.python.org", "www.python.org", 80),
Łukasz Langa7a153902011-10-18 17:16:00 +0200345 ("www.python.org:", "www.python.org", 80),
Georg Brandl71a20892006-10-29 20:24:01 +0000346 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000347 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000348 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000349 if h != c.host:
350 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
351 if p != c.port:
352 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000353
Georg Brandl71a20892006-10-29 20:24:01 +0000354 def test_response_headers(self):
355 # test response with multiple message headers with the same field name.
356 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000357 'Set-Cookie: Customer="WILE_E_COYOTE";'
358 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000359 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
360 ' Path="/acme"\r\n'
361 '\r\n'
362 'No body\r\n')
363 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
364 ', '
365 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
366 s = FakeSocket(text)
367 r = httplib.HTTPResponse(s)
368 r.begin()
369 cookies = r.getheader("Set-Cookie")
370 if cookies != hdr:
371 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000372
Georg Brandl71a20892006-10-29 20:24:01 +0000373 def test_read_head(self):
374 # Test that the library doesn't attempt to read any data
375 # from a HEAD request. (Tickles SF bug #622042.)
376 sock = FakeSocket(
377 'HTTP/1.1 200 OK\r\n'
378 'Content-Length: 14432\r\n'
379 '\r\n',
380 NoEOFStringIO)
381 resp = httplib.HTTPResponse(sock, method="HEAD")
382 resp.begin()
383 if resp.read() != "":
384 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000385
Berker Peksagb7414e02014-08-05 07:15:57 +0300386 def test_too_many_headers(self):
387 headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
388 text = ('HTTP/1.1 200 OK\r\n' + headers)
389 s = FakeSocket(text)
390 r = httplib.HTTPResponse(s)
391 self.assertRaises(httplib.HTTPException, r.begin)
392
Martin v. Löwis040a9272006-11-12 10:32:47 +0000393 def test_send_file(self):
394 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
395 'Accept-Encoding: identity\r\nContent-Length:'
396
397 body = open(__file__, 'rb')
398 conn = httplib.HTTPConnection('example.com')
399 sock = FakeSocket(body)
400 conn.sock = sock
401 conn.request('GET', '/foo', body)
402 self.assertTrue(sock.data.startswith(expected))
Serhiy Storchaka80573bb2015-05-16 18:58:41 +0300403 self.assertIn('def test_send_file', sock.data)
404
405 def test_send_tempfile(self):
406 expected = ('GET /foo HTTP/1.1\r\nHost: example.com\r\n'
407 'Accept-Encoding: identity\r\nContent-Length: 9\r\n\r\n'
408 'fake\ndata')
409
410 with tempfile.TemporaryFile() as body:
411 body.write('fake\ndata')
412 body.seek(0)
413
414 conn = httplib.HTTPConnection('example.com')
415 sock = FakeSocket(body)
416 conn.sock = sock
417 conn.request('GET', '/foo', body)
418 self.assertEqual(sock.data, expected)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000419
Antoine Pitrou72481782009-09-29 17:48:18 +0000420 def test_send(self):
421 expected = 'this is a test this is only a test'
422 conn = httplib.HTTPConnection('example.com')
423 sock = FakeSocket(None)
424 conn.sock = sock
425 conn.send(expected)
Ezio Melotti2623a372010-11-21 13:34:58 +0000426 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000427 sock.data = ''
428 conn.send(array.array('c', expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000429 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000430 sock.data = ''
431 conn.send(StringIO.StringIO(expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000432 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000433
Georg Brandl23635032008-02-24 00:03:22 +0000434 def test_chunked(self):
435 chunked_start = (
436 'HTTP/1.1 200 OK\r\n'
437 'Transfer-Encoding: chunked\r\n\r\n'
438 'a\r\n'
439 'hello worl\r\n'
440 '1\r\n'
441 'd\r\n'
442 )
443 sock = FakeSocket(chunked_start + '0\r\n')
444 resp = httplib.HTTPResponse(sock, method="GET")
445 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000446 self.assertEqual(resp.read(), 'hello world')
Georg Brandl23635032008-02-24 00:03:22 +0000447 resp.close()
448
449 for x in ('', 'foo\r\n'):
450 sock = FakeSocket(chunked_start + x)
451 resp = httplib.HTTPResponse(sock, method="GET")
452 resp.begin()
453 try:
454 resp.read()
455 except httplib.IncompleteRead, i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000456 self.assertEqual(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000457 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
458 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000459 else:
460 self.fail('IncompleteRead expected')
461 finally:
462 resp.close()
463
Senthil Kumaraned9204342010-04-28 17:20:43 +0000464 def test_chunked_head(self):
465 chunked_start = (
466 'HTTP/1.1 200 OK\r\n'
467 'Transfer-Encoding: chunked\r\n\r\n'
468 'a\r\n'
469 'hello world\r\n'
470 '1\r\n'
471 'd\r\n'
472 )
473 sock = FakeSocket(chunked_start + '0\r\n')
474 resp = httplib.HTTPResponse(sock, method="HEAD")
475 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000476 self.assertEqual(resp.read(), '')
477 self.assertEqual(resp.status, 200)
478 self.assertEqual(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000479 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000480
Georg Brandl8c460d52008-02-24 00:14:24 +0000481 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000482 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
483 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000484 resp = httplib.HTTPResponse(sock, method="GET")
485 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000486 self.assertEqual(resp.read(), 'Hello\r\n')
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100487 self.assertTrue(resp.isclosed())
Georg Brandl8c460d52008-02-24 00:14:24 +0000488
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000489 def test_incomplete_read(self):
490 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
491 resp = httplib.HTTPResponse(sock, method="GET")
492 resp.begin()
493 try:
494 resp.read()
495 except httplib.IncompleteRead as i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000496 self.assertEqual(i.partial, 'Hello\r\n')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000497 self.assertEqual(repr(i),
498 "IncompleteRead(7 bytes read, 3 more expected)")
499 self.assertEqual(str(i),
500 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100501 self.assertTrue(resp.isclosed())
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000502 else:
503 self.fail('IncompleteRead expected')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000504
Victor Stinner2c6aee92010-07-24 02:46:16 +0000505 def test_epipe(self):
506 sock = EPipeSocket(
507 "HTTP/1.0 401 Authorization Required\r\n"
508 "Content-type: text/html\r\n"
509 "WWW-Authenticate: Basic realm=\"example\"\r\n",
510 b"Content-Length")
511 conn = httplib.HTTPConnection("example.com")
512 conn.sock = sock
513 self.assertRaises(socket.error,
514 lambda: conn.request("PUT", "/url", "body"))
515 resp = conn.getresponse()
516 self.assertEqual(401, resp.status)
517 self.assertEqual("Basic realm=\"example\"",
518 resp.getheader("www-authenticate"))
519
Senthil Kumarand389cb52010-09-21 01:38:15 +0000520 def test_filenoattr(self):
521 # Just test the fileno attribute in the HTTPResponse Object.
522 body = "HTTP/1.1 200 Ok\r\n\r\nText"
523 sock = FakeSocket(body)
524 resp = httplib.HTTPResponse(sock)
525 self.assertTrue(hasattr(resp,'fileno'),
526 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000527
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000528 # Test lines overflowing the max line size (_MAXLINE in http.client)
529
530 def test_overflowing_status_line(self):
531 self.skipTest("disabled for HTTP 0.9 support")
532 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
533 resp = httplib.HTTPResponse(FakeSocket(body))
534 self.assertRaises((httplib.LineTooLong, httplib.BadStatusLine), resp.begin)
535
536 def test_overflowing_header_line(self):
537 body = (
538 'HTTP/1.1 200 OK\r\n'
539 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
540 )
541 resp = httplib.HTTPResponse(FakeSocket(body))
542 self.assertRaises(httplib.LineTooLong, resp.begin)
543
544 def test_overflowing_chunked_line(self):
545 body = (
546 'HTTP/1.1 200 OK\r\n'
547 'Transfer-Encoding: chunked\r\n\r\n'
548 + '0' * 65536 + 'a\r\n'
549 'hello world\r\n'
550 '0\r\n'
551 )
552 resp = httplib.HTTPResponse(FakeSocket(body))
553 resp.begin()
554 self.assertRaises(httplib.LineTooLong, resp.read)
555
Senthil Kumaranf5aaf6f2012-04-29 10:15:31 +0800556 def test_early_eof(self):
557 # Test httpresponse with no \r\n termination,
558 body = "HTTP/1.1 200 Ok"
559 sock = FakeSocket(body)
560 resp = httplib.HTTPResponse(sock)
561 resp.begin()
562 self.assertEqual(resp.read(), '')
563 self.assertTrue(resp.isclosed())
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000564
Serhiy Storchakad862db02014-12-01 13:07:28 +0200565 def test_error_leak(self):
566 # Test that the socket is not leaked if getresponse() fails
567 conn = httplib.HTTPConnection('example.com')
568 response = []
569 class Response(httplib.HTTPResponse):
570 def __init__(self, *pos, **kw):
571 response.append(self) # Avoid garbage collector closing the socket
572 httplib.HTTPResponse.__init__(self, *pos, **kw)
573 conn.response_class = Response
574 conn.sock = FakeSocket('') # Emulate server dropping connection
575 conn.request('GET', '/')
576 self.assertRaises(httplib.BadStatusLine, conn.getresponse)
577 self.assertTrue(response)
578 #self.assertTrue(response[0].closed)
579 self.assertTrue(conn.sock.file_closed)
580
Martin Panterb75a0e92015-09-07 01:18:47 +0000581 def test_proxy_tunnel_without_status_line(self):
582 # Issue 17849: If a proxy tunnel is created that does not return
583 # a status code, fail.
584 body = 'hello world'
585 conn = httplib.HTTPConnection('example.com', strict=False)
586 conn.set_tunnel('foo')
587 conn.sock = FakeSocket(body)
588 with self.assertRaisesRegexp(socket.error, "Invalid response"):
589 conn._tunnel()
590
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000591class OfflineTest(TestCase):
592 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000593 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000594
Gregory P. Smith9d325212010-01-03 02:06:07 +0000595
Senthil Kumaran812b9752015-01-24 12:58:10 -0800596class TestServerMixin:
597 """A limited socket server mixin.
598
599 This is used by test cases for testing http connection end points.
600 """
Gregory P. Smith9d325212010-01-03 02:06:07 +0000601 def setUp(self):
602 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
603 self.port = test_support.bind_port(self.serv)
604 self.source_port = test_support.find_unused_port()
605 self.serv.listen(5)
606 self.conn = None
607
608 def tearDown(self):
609 if self.conn:
610 self.conn.close()
611 self.conn = None
612 self.serv.close()
613 self.serv = None
614
Senthil Kumaran812b9752015-01-24 12:58:10 -0800615class SourceAddressTest(TestServerMixin, TestCase):
Gregory P. Smith9d325212010-01-03 02:06:07 +0000616 def testHTTPConnectionSourceAddress(self):
617 self.conn = httplib.HTTPConnection(HOST, self.port,
618 source_address=('', self.source_port))
619 self.conn.connect()
620 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
621
622 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
623 'httplib.HTTPSConnection not defined')
624 def testHTTPSConnectionSourceAddress(self):
625 self.conn = httplib.HTTPSConnection(HOST, self.port,
626 source_address=('', self.source_port))
627 # We don't test anything here other the constructor not barfing as
628 # this code doesn't deal with setting up an active running SSL server
629 # for an ssl_wrapped connect() to actually return from.
630
631
Senthil Kumaran812b9752015-01-24 12:58:10 -0800632class HTTPTest(TestServerMixin, TestCase):
633 def testHTTPConnection(self):
634 self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None)
635 self.conn.connect()
636 self.assertEqual(self.conn._conn.host, HOST)
637 self.assertEqual(self.conn._conn.port, self.port)
638
639 def testHTTPWithConnectHostPort(self):
640 testhost = 'unreachable.test.domain'
641 testport = '80'
642 self.conn = httplib.HTTP(host=testhost, port=testport)
643 self.conn.connect(host=HOST, port=self.port)
644 self.assertNotEqual(self.conn._conn.host, testhost)
645 self.assertNotEqual(self.conn._conn.port, testport)
646 self.assertEqual(self.conn._conn.host, HOST)
647 self.assertEqual(self.conn._conn.port, self.port)
648
649
Facundo Batista07c78be2007-03-23 18:54:07 +0000650class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000651 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000652
Facundo Batista07c78be2007-03-23 18:54:07 +0000653 def setUp(self):
654 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000655 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000656 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000657
658 def tearDown(self):
659 self.serv.close()
660 self.serv = None
661
662 def testTimeoutAttribute(self):
663 '''This will prove that the timeout gets through
664 HTTPConnection and into the socket.
665 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000666 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200667 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000668 socket.setdefaulttimeout(30)
669 try:
670 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
671 httpConn.connect()
672 finally:
673 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000674 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000675 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000676
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000677 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200678 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000679 socket.setdefaulttimeout(30)
680 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000681 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
682 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000683 httpConn.connect()
684 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000685 socket.setdefaulttimeout(None)
686 self.assertEqual(httpConn.sock.gettimeout(), None)
687 httpConn.close()
688
689 # a value
690 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
691 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000692 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000693 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000694
Senthil Kumaran812b9752015-01-24 12:58:10 -0800695
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600696class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000697
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600698 def setUp(self):
699 if not hasattr(httplib, 'HTTPSConnection'):
700 self.skipTest('ssl support required')
701
702 def make_server(self, certfile):
703 from test.ssl_servers import make_https_server
704 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000705
706 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600707 # simple test to check it's storing the timeout
708 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
709 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000710
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600711 def test_networked(self):
712 # Default settings: requires a valid cert from a trusted CA
713 import ssl
714 test_support.requires('network')
715 with test_support.transient_internet('self-signed.pythontest.net'):
716 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
717 with self.assertRaises(ssl.SSLError) as exc_info:
718 h.request('GET', '/')
719 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
720
721 def test_networked_noverification(self):
722 # Switch off cert verification
723 import ssl
724 test_support.requires('network')
725 with test_support.transient_internet('self-signed.pythontest.net'):
726 context = ssl._create_stdlib_context()
727 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
728 context=context)
729 h.request('GET', '/')
730 resp = h.getresponse()
731 self.assertIn('nginx', resp.getheader('server'))
732
Benjamin Petersonf671de42014-11-25 15:16:55 -0600733 @test_support.system_must_validate_cert
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600734 def test_networked_trusted_by_default_cert(self):
735 # Default settings: requires a valid cert from a trusted CA
736 test_support.requires('network')
737 with test_support.transient_internet('www.python.org'):
738 h = httplib.HTTPSConnection('www.python.org', 443)
739 h.request('GET', '/')
740 resp = h.getresponse()
741 content_type = resp.getheader('content-type')
742 self.assertIn('text/html', content_type)
743
744 def test_networked_good_cert(self):
745 # We feed the server's cert as a validating cert
746 import ssl
747 test_support.requires('network')
748 with test_support.transient_internet('self-signed.pythontest.net'):
749 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
750 context.verify_mode = ssl.CERT_REQUIRED
751 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
752 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
753 h.request('GET', '/')
754 resp = h.getresponse()
755 server_string = resp.getheader('server')
756 self.assertIn('nginx', server_string)
757
758 def test_networked_bad_cert(self):
759 # We feed a "CA" cert that is unrelated to the server's cert
760 import ssl
761 test_support.requires('network')
762 with test_support.transient_internet('self-signed.pythontest.net'):
763 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
764 context.verify_mode = ssl.CERT_REQUIRED
765 context.load_verify_locations(CERT_localhost)
766 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
767 with self.assertRaises(ssl.SSLError) as exc_info:
768 h.request('GET', '/')
769 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
770
771 def test_local_unknown_cert(self):
772 # The custom cert isn't known to the default trust bundle
773 import ssl
774 server = self.make_server(CERT_localhost)
775 h = httplib.HTTPSConnection('localhost', server.port)
776 with self.assertRaises(ssl.SSLError) as exc_info:
777 h.request('GET', '/')
778 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
779
780 def test_local_good_hostname(self):
781 # The (valid) cert validates the HTTP hostname
782 import ssl
783 server = self.make_server(CERT_localhost)
784 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
785 context.verify_mode = ssl.CERT_REQUIRED
786 context.load_verify_locations(CERT_localhost)
787 h = httplib.HTTPSConnection('localhost', server.port, context=context)
788 h.request('GET', '/nonexistent')
789 resp = h.getresponse()
790 self.assertEqual(resp.status, 404)
791
792 def test_local_bad_hostname(self):
793 # The (valid) cert doesn't validate the HTTP hostname
794 import ssl
795 server = self.make_server(CERT_fakehostname)
796 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
797 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500798 context.check_hostname = True
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600799 context.load_verify_locations(CERT_fakehostname)
800 h = httplib.HTTPSConnection('localhost', server.port, context=context)
801 with self.assertRaises(ssl.CertificateError):
802 h.request('GET', '/')
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500803 h.close()
804 # With context.check_hostname=False, the mismatching is ignored
805 context.check_hostname = False
806 h = httplib.HTTPSConnection('localhost', server.port, context=context)
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600807 h.request('GET', '/nonexistent')
808 resp = h.getresponse()
809 self.assertEqual(resp.status, 404)
810
Łukasz Langa7a153902011-10-18 17:16:00 +0200811 def test_host_port(self):
812 # Check invalid host_port
813
Łukasz Langa7a153902011-10-18 17:16:00 +0200814 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600815 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200816
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600817 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
818 "fe80::207:e9ff:fe9b", 8000),
819 ("www.python.org:443", "www.python.org", 443),
820 ("www.python.org:", "www.python.org", 443),
821 ("www.python.org", "www.python.org", 443),
822 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
823 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
824 443)):
825 c = httplib.HTTPSConnection(hp)
826 self.assertEqual(h, c.host)
827 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200828
829
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700830class TunnelTests(TestCase):
831 def test_connect(self):
832 response_text = (
833 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
834 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
835 'Content-Length: 42\r\n\r\n'
836 )
837
838 def create_connection(address, timeout=None, source_address=None):
839 return FakeSocket(response_text, host=address[0], port=address[1])
840
841 conn = httplib.HTTPConnection('proxy.com')
842 conn._create_connection = create_connection
843
844 # Once connected, we should not be able to tunnel anymore
845 conn.connect()
846 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
847
848 # But if close the connection, we are good.
849 conn.close()
850 conn.set_tunnel('destination.com')
851 conn.request('HEAD', '/', '')
852
853 self.assertEqual(conn.sock.host, 'proxy.com')
854 self.assertEqual(conn.sock.port, 80)
Serhiy Storchaka9d1de8a2015-05-28 22:37:13 +0300855 self.assertIn('CONNECT destination.com', conn.sock.data)
856 # issue22095
857 self.assertNotIn('Host: destination.com:None', conn.sock.data)
858 self.assertIn('Host: destination.com', conn.sock.data)
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700859
Serhiy Storchaka9d1de8a2015-05-28 22:37:13 +0300860 self.assertNotIn('Host: proxy.com', conn.sock.data)
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700861
862 conn.close()
863
864 conn.request('PUT', '/', '')
865 self.assertEqual(conn.sock.host, 'proxy.com')
866 self.assertEqual(conn.sock.port, 80)
867 self.assertTrue('CONNECT destination.com' in conn.sock.data)
868 self.assertTrue('Host: destination.com' in conn.sock.data)
869
870
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600871@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000872def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000873 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Senthil Kumaran812b9752015-01-24 12:58:10 -0800874 HTTPTest, HTTPSTest, SourceAddressTest,
875 TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000876
Georg Brandl71a20892006-10-29 20:24:01 +0000877if __name__ == '__main__':
878 test_main()