blob: 301458910d6bd82e8027878dccfb7c897944d4ce [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
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000581class OfflineTest(TestCase):
582 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000583 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000584
Gregory P. Smith9d325212010-01-03 02:06:07 +0000585
Senthil Kumaran812b9752015-01-24 12:58:10 -0800586class TestServerMixin:
587 """A limited socket server mixin.
588
589 This is used by test cases for testing http connection end points.
590 """
Gregory P. Smith9d325212010-01-03 02:06:07 +0000591 def setUp(self):
592 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
593 self.port = test_support.bind_port(self.serv)
594 self.source_port = test_support.find_unused_port()
595 self.serv.listen(5)
596 self.conn = None
597
598 def tearDown(self):
599 if self.conn:
600 self.conn.close()
601 self.conn = None
602 self.serv.close()
603 self.serv = None
604
Senthil Kumaran812b9752015-01-24 12:58:10 -0800605class SourceAddressTest(TestServerMixin, TestCase):
Gregory P. Smith9d325212010-01-03 02:06:07 +0000606 def testHTTPConnectionSourceAddress(self):
607 self.conn = httplib.HTTPConnection(HOST, self.port,
608 source_address=('', self.source_port))
609 self.conn.connect()
610 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
611
612 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
613 'httplib.HTTPSConnection not defined')
614 def testHTTPSConnectionSourceAddress(self):
615 self.conn = httplib.HTTPSConnection(HOST, self.port,
616 source_address=('', self.source_port))
617 # We don't test anything here other the constructor not barfing as
618 # this code doesn't deal with setting up an active running SSL server
619 # for an ssl_wrapped connect() to actually return from.
620
621
Senthil Kumaran812b9752015-01-24 12:58:10 -0800622class HTTPTest(TestServerMixin, TestCase):
623 def testHTTPConnection(self):
624 self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None)
625 self.conn.connect()
626 self.assertEqual(self.conn._conn.host, HOST)
627 self.assertEqual(self.conn._conn.port, self.port)
628
629 def testHTTPWithConnectHostPort(self):
630 testhost = 'unreachable.test.domain'
631 testport = '80'
632 self.conn = httplib.HTTP(host=testhost, port=testport)
633 self.conn.connect(host=HOST, port=self.port)
634 self.assertNotEqual(self.conn._conn.host, testhost)
635 self.assertNotEqual(self.conn._conn.port, testport)
636 self.assertEqual(self.conn._conn.host, HOST)
637 self.assertEqual(self.conn._conn.port, self.port)
638
639
Facundo Batista07c78be2007-03-23 18:54:07 +0000640class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000641 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000642
Facundo Batista07c78be2007-03-23 18:54:07 +0000643 def setUp(self):
644 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000645 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000646 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000647
648 def tearDown(self):
649 self.serv.close()
650 self.serv = None
651
652 def testTimeoutAttribute(self):
653 '''This will prove that the timeout gets through
654 HTTPConnection and into the socket.
655 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000656 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200657 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000658 socket.setdefaulttimeout(30)
659 try:
660 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
661 httpConn.connect()
662 finally:
663 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000664 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000665 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000666
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000667 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200668 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000669 socket.setdefaulttimeout(30)
670 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000671 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
672 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000673 httpConn.connect()
674 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000675 socket.setdefaulttimeout(None)
676 self.assertEqual(httpConn.sock.gettimeout(), None)
677 httpConn.close()
678
679 # a value
680 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
681 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000682 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000683 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000684
Senthil Kumaran812b9752015-01-24 12:58:10 -0800685
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600686class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000687
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600688 def setUp(self):
689 if not hasattr(httplib, 'HTTPSConnection'):
690 self.skipTest('ssl support required')
691
692 def make_server(self, certfile):
693 from test.ssl_servers import make_https_server
694 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000695
696 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600697 # simple test to check it's storing the timeout
698 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
699 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000700
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600701 def test_networked(self):
702 # Default settings: requires a valid cert from a trusted CA
703 import ssl
704 test_support.requires('network')
705 with test_support.transient_internet('self-signed.pythontest.net'):
706 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
707 with self.assertRaises(ssl.SSLError) as exc_info:
708 h.request('GET', '/')
709 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
710
711 def test_networked_noverification(self):
712 # Switch off cert verification
713 import ssl
714 test_support.requires('network')
715 with test_support.transient_internet('self-signed.pythontest.net'):
716 context = ssl._create_stdlib_context()
717 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
718 context=context)
719 h.request('GET', '/')
720 resp = h.getresponse()
721 self.assertIn('nginx', resp.getheader('server'))
722
Benjamin Petersonf671de42014-11-25 15:16:55 -0600723 @test_support.system_must_validate_cert
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600724 def test_networked_trusted_by_default_cert(self):
725 # Default settings: requires a valid cert from a trusted CA
726 test_support.requires('network')
727 with test_support.transient_internet('www.python.org'):
728 h = httplib.HTTPSConnection('www.python.org', 443)
729 h.request('GET', '/')
730 resp = h.getresponse()
731 content_type = resp.getheader('content-type')
732 self.assertIn('text/html', content_type)
733
734 def test_networked_good_cert(self):
735 # We feed the server's cert as a validating cert
736 import ssl
737 test_support.requires('network')
738 with test_support.transient_internet('self-signed.pythontest.net'):
739 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
740 context.verify_mode = ssl.CERT_REQUIRED
741 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
742 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
743 h.request('GET', '/')
744 resp = h.getresponse()
745 server_string = resp.getheader('server')
746 self.assertIn('nginx', server_string)
747
748 def test_networked_bad_cert(self):
749 # We feed a "CA" cert that is unrelated to the server's cert
750 import ssl
751 test_support.requires('network')
752 with test_support.transient_internet('self-signed.pythontest.net'):
753 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
754 context.verify_mode = ssl.CERT_REQUIRED
755 context.load_verify_locations(CERT_localhost)
756 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
757 with self.assertRaises(ssl.SSLError) as exc_info:
758 h.request('GET', '/')
759 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
760
761 def test_local_unknown_cert(self):
762 # The custom cert isn't known to the default trust bundle
763 import ssl
764 server = self.make_server(CERT_localhost)
765 h = httplib.HTTPSConnection('localhost', server.port)
766 with self.assertRaises(ssl.SSLError) as exc_info:
767 h.request('GET', '/')
768 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
769
770 def test_local_good_hostname(self):
771 # The (valid) cert validates the HTTP hostname
772 import ssl
773 server = self.make_server(CERT_localhost)
774 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
775 context.verify_mode = ssl.CERT_REQUIRED
776 context.load_verify_locations(CERT_localhost)
777 h = httplib.HTTPSConnection('localhost', server.port, context=context)
778 h.request('GET', '/nonexistent')
779 resp = h.getresponse()
780 self.assertEqual(resp.status, 404)
781
782 def test_local_bad_hostname(self):
783 # The (valid) cert doesn't validate the HTTP hostname
784 import ssl
785 server = self.make_server(CERT_fakehostname)
786 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
787 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500788 context.check_hostname = True
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600789 context.load_verify_locations(CERT_fakehostname)
790 h = httplib.HTTPSConnection('localhost', server.port, context=context)
791 with self.assertRaises(ssl.CertificateError):
792 h.request('GET', '/')
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500793 h.close()
794 # With context.check_hostname=False, the mismatching is ignored
795 context.check_hostname = False
796 h = httplib.HTTPSConnection('localhost', server.port, context=context)
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600797 h.request('GET', '/nonexistent')
798 resp = h.getresponse()
799 self.assertEqual(resp.status, 404)
800
Łukasz Langa7a153902011-10-18 17:16:00 +0200801 def test_host_port(self):
802 # Check invalid host_port
803
Łukasz Langa7a153902011-10-18 17:16:00 +0200804 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600805 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200806
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600807 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
808 "fe80::207:e9ff:fe9b", 8000),
809 ("www.python.org:443", "www.python.org", 443),
810 ("www.python.org:", "www.python.org", 443),
811 ("www.python.org", "www.python.org", 443),
812 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
813 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
814 443)):
815 c = httplib.HTTPSConnection(hp)
816 self.assertEqual(h, c.host)
817 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200818
819
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700820class TunnelTests(TestCase):
821 def test_connect(self):
822 response_text = (
823 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
824 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
825 'Content-Length: 42\r\n\r\n'
826 )
827
828 def create_connection(address, timeout=None, source_address=None):
829 return FakeSocket(response_text, host=address[0], port=address[1])
830
831 conn = httplib.HTTPConnection('proxy.com')
832 conn._create_connection = create_connection
833
834 # Once connected, we should not be able to tunnel anymore
835 conn.connect()
836 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
837
838 # But if close the connection, we are good.
839 conn.close()
840 conn.set_tunnel('destination.com')
841 conn.request('HEAD', '/', '')
842
843 self.assertEqual(conn.sock.host, 'proxy.com')
844 self.assertEqual(conn.sock.port, 80)
Serhiy Storchaka9d1de8a2015-05-28 22:37:13 +0300845 self.assertIn('CONNECT destination.com', conn.sock.data)
846 # issue22095
847 self.assertNotIn('Host: destination.com:None', conn.sock.data)
848 self.assertIn('Host: destination.com', conn.sock.data)
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700849
Serhiy Storchaka9d1de8a2015-05-28 22:37:13 +0300850 self.assertNotIn('Host: proxy.com', conn.sock.data)
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700851
852 conn.close()
853
854 conn.request('PUT', '/', '')
855 self.assertEqual(conn.sock.host, 'proxy.com')
856 self.assertEqual(conn.sock.port, 80)
857 self.assertTrue('CONNECT destination.com' in conn.sock.data)
858 self.assertTrue('Host: destination.com' in conn.sock.data)
859
860
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600861@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000862def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000863 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Senthil Kumaran812b9752015-01-24 12:58:10 -0800864 HTTPTest, HTTPSTest, SourceAddressTest,
865 TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000866
Georg Brandl71a20892006-10-29 20:24:01 +0000867if __name__ == '__main__':
868 test_main()