blob: fc7c5710e46d89c1e06920c504d1dcead9349b20 [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
Jeremy Hylton121d34a2003-07-08 12:36:58 +00008
Gregory P. Smith9d325212010-01-03 02:06:07 +00009import unittest
10TestCase = unittest.TestCase
Jeremy Hylton2c178252004-08-07 16:28:14 +000011
12from test import test_support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000013
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -060014here = os.path.dirname(__file__)
15# Self-signed cert file for 'localhost'
16CERT_localhost = os.path.join(here, 'keycert.pem')
17# Self-signed cert file for 'fakehostname'
18CERT_fakehostname = os.path.join(here, 'keycert2.pem')
19# Self-signed cert file for self-signed.pythontest.net
20CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
21
Trent Nelsone41b0062008-04-08 23:47:30 +000022HOST = test_support.HOST
23
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000024class FakeSocket:
Senthil Kumaran36f28f72014-05-16 18:51:46 -070025 def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000026 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000027 self.fileclass = fileclass
Martin v. Löwis040a9272006-11-12 10:32:47 +000028 self.data = ''
Serhiy Storchakad862db02014-12-01 13:07:28 +020029 self.file_closed = False
Senthil Kumaran36f28f72014-05-16 18:51:46 -070030 self.host = host
31 self.port = port
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000032
Jeremy Hylton2c178252004-08-07 16:28:14 +000033 def sendall(self, data):
Antoine Pitrou72481782009-09-29 17:48:18 +000034 self.data += ''.join(data)
Jeremy Hylton2c178252004-08-07 16:28:14 +000035
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000036 def makefile(self, mode, bufsize=None):
37 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000038 raise httplib.UnimplementedFileMode()
Serhiy Storchakad862db02014-12-01 13:07:28 +020039 # keep the file around so we can check how much was read from it
40 self.file = self.fileclass(self.text)
41 self.file.close = self.file_close #nerf close ()
42 return self.file
43
44 def file_close(self):
45 self.file_closed = True
Jeremy Hylton121d34a2003-07-08 12:36:58 +000046
Senthil Kumaran36f28f72014-05-16 18:51:46 -070047 def close(self):
48 pass
49
Victor Stinner2c6aee92010-07-24 02:46:16 +000050class EPipeSocket(FakeSocket):
51
52 def __init__(self, text, pipe_trigger):
53 # When sendall() is called with pipe_trigger, raise EPIPE.
54 FakeSocket.__init__(self, text)
55 self.pipe_trigger = pipe_trigger
56
57 def sendall(self, data):
58 if self.pipe_trigger in data:
59 raise socket.error(errno.EPIPE, "gotcha")
60 self.data += data
61
62 def close(self):
63 pass
64
Jeremy Hylton121d34a2003-07-08 12:36:58 +000065class NoEOFStringIO(StringIO.StringIO):
66 """Like StringIO, but raises AssertionError on EOF.
67
68 This is used below to test that httplib doesn't try to read
69 more from the underlying file than it should.
70 """
71 def read(self, n=-1):
72 data = StringIO.StringIO.read(self, n)
73 if data == '':
74 raise AssertionError('caller tried to read past EOF')
75 return data
76
77 def readline(self, length=None):
78 data = StringIO.StringIO.readline(self, length)
79 if data == '':
80 raise AssertionError('caller tried to read past EOF')
81 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000082
Jeremy Hylton2c178252004-08-07 16:28:14 +000083
84class HeaderTests(TestCase):
85 def test_auto_headers(self):
86 # Some headers are added automatically, but should not be added by
87 # .request() if they are explicitly set.
88
Jeremy Hylton2c178252004-08-07 16:28:14 +000089 class HeaderCountingBuffer(list):
90 def __init__(self):
91 self.count = {}
92 def append(self, item):
93 kv = item.split(':')
94 if len(kv) > 1:
95 # item is a 'Key: Value' header string
96 lcKey = kv[0].lower()
97 self.count.setdefault(lcKey, 0)
98 self.count[lcKey] += 1
99 list.append(self, item)
100
101 for explicit_header in True, False:
102 for header in 'Content-length', 'Host', 'Accept-encoding':
103 conn = httplib.HTTPConnection('example.com')
104 conn.sock = FakeSocket('blahblahblah')
105 conn._buffer = HeaderCountingBuffer()
106
107 body = 'spamspamspam'
108 headers = {}
109 if explicit_header:
110 headers[header] = str(len(body))
111 conn.request('POST', '/', body, headers)
112 self.assertEqual(conn._buffer.count[header.lower()], 1)
113
Senthil Kumaran618802d2012-05-19 16:52:21 +0800114 def test_content_length_0(self):
115
116 class ContentLengthChecker(list):
117 def __init__(self):
118 list.__init__(self)
119 self.content_length = None
120 def append(self, item):
121 kv = item.split(':', 1)
122 if len(kv) > 1 and kv[0].lower() == 'content-length':
123 self.content_length = kv[1].strip()
124 list.append(self, item)
125
R David Murrayb4b000f2015-03-22 15:15:44 -0400126 # Here, we're testing that methods expecting a body get a
127 # content-length set to zero if the body is empty (either None or '')
128 bodies = (None, '')
129 methods_with_body = ('PUT', 'POST', 'PATCH')
130 for method, body in itertools.product(methods_with_body, bodies):
131 conn = httplib.HTTPConnection('example.com')
132 conn.sock = FakeSocket(None)
133 conn._buffer = ContentLengthChecker()
134 conn.request(method, '/', body)
135 self.assertEqual(
136 conn._buffer.content_length, '0',
137 'Header Content-Length incorrect on {}'.format(method)
138 )
Senthil Kumaran618802d2012-05-19 16:52:21 +0800139
R David Murrayb4b000f2015-03-22 15:15:44 -0400140 # For these methods, we make sure that content-length is not set when
141 # the body is None because it might cause unexpected behaviour on the
142 # server.
143 methods_without_body = (
144 'GET', 'CONNECT', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE',
145 )
146 for method in methods_without_body:
147 conn = httplib.HTTPConnection('example.com')
148 conn.sock = FakeSocket(None)
149 conn._buffer = ContentLengthChecker()
150 conn.request(method, '/', None)
151 self.assertEqual(
152 conn._buffer.content_length, None,
153 'Header Content-Length set for empty body on {}'.format(method)
154 )
155
156 # If the body is set to '', that's considered to be "present but
157 # empty" rather than "missing", so content length would be set, even
158 # for methods that don't expect a body.
159 for method in methods_without_body:
160 conn = httplib.HTTPConnection('example.com')
161 conn.sock = FakeSocket(None)
162 conn._buffer = ContentLengthChecker()
163 conn.request(method, '/', '')
164 self.assertEqual(
165 conn._buffer.content_length, '0',
166 'Header Content-Length incorrect on {}'.format(method)
167 )
168
169 # If the body is set, make sure Content-Length is set.
170 for method in itertools.chain(methods_without_body, methods_with_body):
171 conn = httplib.HTTPConnection('example.com')
172 conn.sock = FakeSocket(None)
173 conn._buffer = ContentLengthChecker()
174 conn.request(method, '/', ' ')
175 self.assertEqual(
176 conn._buffer.content_length, '1',
177 'Header Content-Length incorrect on {}'.format(method)
178 )
Senthil Kumaran618802d2012-05-19 16:52:21 +0800179
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000180 def test_putheader(self):
181 conn = httplib.HTTPConnection('example.com')
182 conn.sock = FakeSocket(None)
183 conn.putrequest('GET','/')
184 conn.putheader('Content-length',42)
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200185 self.assertIn('Content-length: 42', conn._buffer)
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000186
Serhiy Storchaka59bdf632015-03-12 11:12:51 +0200187 conn.putheader('Foo', ' bar ')
188 self.assertIn(b'Foo: bar ', conn._buffer)
189 conn.putheader('Bar', '\tbaz\t')
190 self.assertIn(b'Bar: \tbaz\t', conn._buffer)
191 conn.putheader('Authorization', 'Bearer mytoken')
192 self.assertIn(b'Authorization: Bearer mytoken', conn._buffer)
193 conn.putheader('IterHeader', 'IterA', 'IterB')
194 self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer)
195 conn.putheader('LatinHeader', b'\xFF')
196 self.assertIn(b'LatinHeader: \xFF', conn._buffer)
197 conn.putheader('Utf8Header', b'\xc3\x80')
198 self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer)
199 conn.putheader('C1-Control', b'next\x85line')
200 self.assertIn(b'C1-Control: next\x85line', conn._buffer)
201 conn.putheader('Embedded-Fold-Space', 'is\r\n allowed')
202 self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer)
203 conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed')
204 self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer)
205 conn.putheader('Key Space', 'value')
206 self.assertIn(b'Key Space: value', conn._buffer)
207 conn.putheader('KeySpace ', 'value')
208 self.assertIn(b'KeySpace : value', conn._buffer)
209 conn.putheader(b'Nonbreak\xa0Space', 'value')
210 self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer)
211 conn.putheader(b'\xa0NonbreakSpace', 'value')
212 self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer)
213
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000214 def test_ipv6host_header(self):
215 # Default host header on IPv6 transaction should wrapped by [] if
216 # its actual IPv6 address
217 expected = 'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
218 'Accept-Encoding: identity\r\n\r\n'
219 conn = httplib.HTTPConnection('[2001::]:81')
220 sock = FakeSocket('')
221 conn.sock = sock
222 conn.request('GET', '/foo')
223 self.assertTrue(sock.data.startswith(expected))
224
225 expected = 'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
226 'Accept-Encoding: identity\r\n\r\n'
227 conn = httplib.HTTPConnection('[2001:102A::]')
228 sock = FakeSocket('')
229 conn.sock = sock
230 conn.request('GET', '/foo')
231 self.assertTrue(sock.data.startswith(expected))
232
Benjamin Petersonbfd976f2015-01-25 23:34:42 -0500233 def test_malformed_headers_coped_with(self):
234 # Issue 19996
235 body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n"
236 sock = FakeSocket(body)
237 resp = httplib.HTTPResponse(sock)
238 resp.begin()
239
240 self.assertEqual(resp.getheader('First'), 'val')
241 self.assertEqual(resp.getheader('Second'), 'val')
242
Serhiy Storchaka59bdf632015-03-12 11:12:51 +0200243 def test_invalid_headers(self):
244 conn = httplib.HTTPConnection('example.com')
245 conn.sock = FakeSocket('')
246 conn.putrequest('GET', '/')
247
248 # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no
249 # longer allowed in header names
250 cases = (
251 (b'Invalid\r\nName', b'ValidValue'),
252 (b'Invalid\rName', b'ValidValue'),
253 (b'Invalid\nName', b'ValidValue'),
254 (b'\r\nInvalidName', b'ValidValue'),
255 (b'\rInvalidName', b'ValidValue'),
256 (b'\nInvalidName', b'ValidValue'),
257 (b' InvalidName', b'ValidValue'),
258 (b'\tInvalidName', b'ValidValue'),
259 (b'Invalid:Name', b'ValidValue'),
260 (b':InvalidName', b'ValidValue'),
261 (b'ValidName', b'Invalid\r\nValue'),
262 (b'ValidName', b'Invalid\rValue'),
263 (b'ValidName', b'Invalid\nValue'),
264 (b'ValidName', b'InvalidValue\r\n'),
265 (b'ValidName', b'InvalidValue\r'),
266 (b'ValidName', b'InvalidValue\n'),
267 )
268 for name, value in cases:
269 with self.assertRaisesRegexp(ValueError, 'Invalid header'):
270 conn.putheader(name, value)
271
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000272
Georg Brandl71a20892006-10-29 20:24:01 +0000273class BasicTest(TestCase):
274 def test_status_lines(self):
275 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000276
Georg Brandl71a20892006-10-29 20:24:01 +0000277 body = "HTTP/1.1 200 Ok\r\n\r\nText"
278 sock = FakeSocket(body)
279 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000280 resp.begin()
Serhiy Storchakac97f5ed2013-12-17 21:49:48 +0200281 self.assertEqual(resp.read(0), '') # Issue #20007
282 self.assertFalse(resp.isclosed())
Georg Brandl71a20892006-10-29 20:24:01 +0000283 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000284 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000285
Georg Brandl71a20892006-10-29 20:24:01 +0000286 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
287 sock = FakeSocket(body)
288 resp = httplib.HTTPResponse(sock)
289 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000290
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000291 def test_bad_status_repr(self):
292 exc = httplib.BadStatusLine('')
Ezio Melotti2623a372010-11-21 13:34:58 +0000293 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000294
Facundo Batista70665902007-10-18 03:16:03 +0000295 def test_partial_reads(self):
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100296 # if we have a length, the system knows when to close itself
Facundo Batista70665902007-10-18 03:16:03 +0000297 # same behaviour than when we read the whole thing with read()
298 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
299 sock = FakeSocket(body)
300 resp = httplib.HTTPResponse(sock)
301 resp.begin()
302 self.assertEqual(resp.read(2), 'Te')
303 self.assertFalse(resp.isclosed())
304 self.assertEqual(resp.read(2), 'xt')
305 self.assertTrue(resp.isclosed())
306
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100307 def test_partial_reads_no_content_length(self):
308 # when no length is present, the socket should be gracefully closed when
309 # all data was read
310 body = "HTTP/1.1 200 Ok\r\n\r\nText"
311 sock = FakeSocket(body)
312 resp = httplib.HTTPResponse(sock)
313 resp.begin()
314 self.assertEqual(resp.read(2), 'Te')
315 self.assertFalse(resp.isclosed())
316 self.assertEqual(resp.read(2), 'xt')
317 self.assertEqual(resp.read(1), '')
318 self.assertTrue(resp.isclosed())
319
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100320 def test_partial_reads_incomplete_body(self):
321 # if the server shuts down the connection before the whole
322 # content-length is delivered, the socket is gracefully closed
323 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
324 sock = FakeSocket(body)
325 resp = httplib.HTTPResponse(sock)
326 resp.begin()
327 self.assertEqual(resp.read(2), 'Te')
328 self.assertFalse(resp.isclosed())
329 self.assertEqual(resp.read(2), 'xt')
330 self.assertEqual(resp.read(1), '')
331 self.assertTrue(resp.isclosed())
332
Georg Brandl71a20892006-10-29 20:24:01 +0000333 def test_host_port(self):
334 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000335
Łukasz Langa7a153902011-10-18 17:16:00 +0200336 # Note that httplib does not accept user:password@ in the host-port.
337 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Georg Brandl71a20892006-10-29 20:24:01 +0000338 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
339
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000340 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
341 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000342 ("www.python.org:80", "www.python.org", 80),
343 ("www.python.org", "www.python.org", 80),
Łukasz Langa7a153902011-10-18 17:16:00 +0200344 ("www.python.org:", "www.python.org", 80),
Georg Brandl71a20892006-10-29 20:24:01 +0000345 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000346 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000347 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000348 if h != c.host:
349 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
350 if p != c.port:
351 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000352
Georg Brandl71a20892006-10-29 20:24:01 +0000353 def test_response_headers(self):
354 # test response with multiple message headers with the same field name.
355 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000356 'Set-Cookie: Customer="WILE_E_COYOTE";'
357 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000358 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
359 ' Path="/acme"\r\n'
360 '\r\n'
361 'No body\r\n')
362 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
363 ', '
364 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
365 s = FakeSocket(text)
366 r = httplib.HTTPResponse(s)
367 r.begin()
368 cookies = r.getheader("Set-Cookie")
369 if cookies != hdr:
370 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000371
Georg Brandl71a20892006-10-29 20:24:01 +0000372 def test_read_head(self):
373 # Test that the library doesn't attempt to read any data
374 # from a HEAD request. (Tickles SF bug #622042.)
375 sock = FakeSocket(
376 'HTTP/1.1 200 OK\r\n'
377 'Content-Length: 14432\r\n'
378 '\r\n',
379 NoEOFStringIO)
380 resp = httplib.HTTPResponse(sock, method="HEAD")
381 resp.begin()
382 if resp.read() != "":
383 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000384
Berker Peksagb7414e02014-08-05 07:15:57 +0300385 def test_too_many_headers(self):
386 headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
387 text = ('HTTP/1.1 200 OK\r\n' + headers)
388 s = FakeSocket(text)
389 r = httplib.HTTPResponse(s)
390 self.assertRaises(httplib.HTTPException, r.begin)
391
Martin v. Löwis040a9272006-11-12 10:32:47 +0000392 def test_send_file(self):
393 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
394 'Accept-Encoding: identity\r\nContent-Length:'
395
396 body = open(__file__, 'rb')
397 conn = httplib.HTTPConnection('example.com')
398 sock = FakeSocket(body)
399 conn.sock = sock
400 conn.request('GET', '/foo', body)
401 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000402
Antoine Pitrou72481782009-09-29 17:48:18 +0000403 def test_send(self):
404 expected = 'this is a test this is only a test'
405 conn = httplib.HTTPConnection('example.com')
406 sock = FakeSocket(None)
407 conn.sock = sock
408 conn.send(expected)
Ezio Melotti2623a372010-11-21 13:34:58 +0000409 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000410 sock.data = ''
411 conn.send(array.array('c', expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000412 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000413 sock.data = ''
414 conn.send(StringIO.StringIO(expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000415 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000416
Georg Brandl23635032008-02-24 00:03:22 +0000417 def test_chunked(self):
418 chunked_start = (
419 'HTTP/1.1 200 OK\r\n'
420 'Transfer-Encoding: chunked\r\n\r\n'
421 'a\r\n'
422 'hello worl\r\n'
423 '1\r\n'
424 'd\r\n'
425 )
426 sock = FakeSocket(chunked_start + '0\r\n')
427 resp = httplib.HTTPResponse(sock, method="GET")
428 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000429 self.assertEqual(resp.read(), 'hello world')
Georg Brandl23635032008-02-24 00:03:22 +0000430 resp.close()
431
432 for x in ('', 'foo\r\n'):
433 sock = FakeSocket(chunked_start + x)
434 resp = httplib.HTTPResponse(sock, method="GET")
435 resp.begin()
436 try:
437 resp.read()
438 except httplib.IncompleteRead, i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000439 self.assertEqual(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000440 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
441 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000442 else:
443 self.fail('IncompleteRead expected')
444 finally:
445 resp.close()
446
Senthil Kumaraned9204342010-04-28 17:20:43 +0000447 def test_chunked_head(self):
448 chunked_start = (
449 'HTTP/1.1 200 OK\r\n'
450 'Transfer-Encoding: chunked\r\n\r\n'
451 'a\r\n'
452 'hello world\r\n'
453 '1\r\n'
454 'd\r\n'
455 )
456 sock = FakeSocket(chunked_start + '0\r\n')
457 resp = httplib.HTTPResponse(sock, method="HEAD")
458 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000459 self.assertEqual(resp.read(), '')
460 self.assertEqual(resp.status, 200)
461 self.assertEqual(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000462 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000463
Georg Brandl8c460d52008-02-24 00:14:24 +0000464 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000465 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
466 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000467 resp = httplib.HTTPResponse(sock, method="GET")
468 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000469 self.assertEqual(resp.read(), 'Hello\r\n')
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100470 self.assertTrue(resp.isclosed())
Georg Brandl8c460d52008-02-24 00:14:24 +0000471
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000472 def test_incomplete_read(self):
473 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
474 resp = httplib.HTTPResponse(sock, method="GET")
475 resp.begin()
476 try:
477 resp.read()
478 except httplib.IncompleteRead as i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000479 self.assertEqual(i.partial, 'Hello\r\n')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000480 self.assertEqual(repr(i),
481 "IncompleteRead(7 bytes read, 3 more expected)")
482 self.assertEqual(str(i),
483 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100484 self.assertTrue(resp.isclosed())
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000485 else:
486 self.fail('IncompleteRead expected')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000487
Victor Stinner2c6aee92010-07-24 02:46:16 +0000488 def test_epipe(self):
489 sock = EPipeSocket(
490 "HTTP/1.0 401 Authorization Required\r\n"
491 "Content-type: text/html\r\n"
492 "WWW-Authenticate: Basic realm=\"example\"\r\n",
493 b"Content-Length")
494 conn = httplib.HTTPConnection("example.com")
495 conn.sock = sock
496 self.assertRaises(socket.error,
497 lambda: conn.request("PUT", "/url", "body"))
498 resp = conn.getresponse()
499 self.assertEqual(401, resp.status)
500 self.assertEqual("Basic realm=\"example\"",
501 resp.getheader("www-authenticate"))
502
Senthil Kumarand389cb52010-09-21 01:38:15 +0000503 def test_filenoattr(self):
504 # Just test the fileno attribute in the HTTPResponse Object.
505 body = "HTTP/1.1 200 Ok\r\n\r\nText"
506 sock = FakeSocket(body)
507 resp = httplib.HTTPResponse(sock)
508 self.assertTrue(hasattr(resp,'fileno'),
509 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000510
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000511 # Test lines overflowing the max line size (_MAXLINE in http.client)
512
513 def test_overflowing_status_line(self):
514 self.skipTest("disabled for HTTP 0.9 support")
515 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
516 resp = httplib.HTTPResponse(FakeSocket(body))
517 self.assertRaises((httplib.LineTooLong, httplib.BadStatusLine), resp.begin)
518
519 def test_overflowing_header_line(self):
520 body = (
521 'HTTP/1.1 200 OK\r\n'
522 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
523 )
524 resp = httplib.HTTPResponse(FakeSocket(body))
525 self.assertRaises(httplib.LineTooLong, resp.begin)
526
527 def test_overflowing_chunked_line(self):
528 body = (
529 'HTTP/1.1 200 OK\r\n'
530 'Transfer-Encoding: chunked\r\n\r\n'
531 + '0' * 65536 + 'a\r\n'
532 'hello world\r\n'
533 '0\r\n'
534 )
535 resp = httplib.HTTPResponse(FakeSocket(body))
536 resp.begin()
537 self.assertRaises(httplib.LineTooLong, resp.read)
538
Senthil Kumaranf5aaf6f2012-04-29 10:15:31 +0800539 def test_early_eof(self):
540 # Test httpresponse with no \r\n termination,
541 body = "HTTP/1.1 200 Ok"
542 sock = FakeSocket(body)
543 resp = httplib.HTTPResponse(sock)
544 resp.begin()
545 self.assertEqual(resp.read(), '')
546 self.assertTrue(resp.isclosed())
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000547
Serhiy Storchakad862db02014-12-01 13:07:28 +0200548 def test_error_leak(self):
549 # Test that the socket is not leaked if getresponse() fails
550 conn = httplib.HTTPConnection('example.com')
551 response = []
552 class Response(httplib.HTTPResponse):
553 def __init__(self, *pos, **kw):
554 response.append(self) # Avoid garbage collector closing the socket
555 httplib.HTTPResponse.__init__(self, *pos, **kw)
556 conn.response_class = Response
557 conn.sock = FakeSocket('') # Emulate server dropping connection
558 conn.request('GET', '/')
559 self.assertRaises(httplib.BadStatusLine, conn.getresponse)
560 self.assertTrue(response)
561 #self.assertTrue(response[0].closed)
562 self.assertTrue(conn.sock.file_closed)
563
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000564class OfflineTest(TestCase):
565 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000566 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000567
Gregory P. Smith9d325212010-01-03 02:06:07 +0000568
Senthil Kumaran812b9752015-01-24 12:58:10 -0800569class TestServerMixin:
570 """A limited socket server mixin.
571
572 This is used by test cases for testing http connection end points.
573 """
Gregory P. Smith9d325212010-01-03 02:06:07 +0000574 def setUp(self):
575 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
576 self.port = test_support.bind_port(self.serv)
577 self.source_port = test_support.find_unused_port()
578 self.serv.listen(5)
579 self.conn = None
580
581 def tearDown(self):
582 if self.conn:
583 self.conn.close()
584 self.conn = None
585 self.serv.close()
586 self.serv = None
587
Senthil Kumaran812b9752015-01-24 12:58:10 -0800588class SourceAddressTest(TestServerMixin, TestCase):
Gregory P. Smith9d325212010-01-03 02:06:07 +0000589 def testHTTPConnectionSourceAddress(self):
590 self.conn = httplib.HTTPConnection(HOST, self.port,
591 source_address=('', self.source_port))
592 self.conn.connect()
593 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
594
595 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
596 'httplib.HTTPSConnection not defined')
597 def testHTTPSConnectionSourceAddress(self):
598 self.conn = httplib.HTTPSConnection(HOST, self.port,
599 source_address=('', self.source_port))
600 # We don't test anything here other the constructor not barfing as
601 # this code doesn't deal with setting up an active running SSL server
602 # for an ssl_wrapped connect() to actually return from.
603
604
Senthil Kumaran812b9752015-01-24 12:58:10 -0800605class HTTPTest(TestServerMixin, TestCase):
606 def testHTTPConnection(self):
607 self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None)
608 self.conn.connect()
609 self.assertEqual(self.conn._conn.host, HOST)
610 self.assertEqual(self.conn._conn.port, self.port)
611
612 def testHTTPWithConnectHostPort(self):
613 testhost = 'unreachable.test.domain'
614 testport = '80'
615 self.conn = httplib.HTTP(host=testhost, port=testport)
616 self.conn.connect(host=HOST, port=self.port)
617 self.assertNotEqual(self.conn._conn.host, testhost)
618 self.assertNotEqual(self.conn._conn.port, testport)
619 self.assertEqual(self.conn._conn.host, HOST)
620 self.assertEqual(self.conn._conn.port, self.port)
621
622
Facundo Batista07c78be2007-03-23 18:54:07 +0000623class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000624 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000625
Facundo Batista07c78be2007-03-23 18:54:07 +0000626 def setUp(self):
627 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000628 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000629 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000630
631 def tearDown(self):
632 self.serv.close()
633 self.serv = None
634
635 def testTimeoutAttribute(self):
636 '''This will prove that the timeout gets through
637 HTTPConnection and into the socket.
638 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000639 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200640 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000641 socket.setdefaulttimeout(30)
642 try:
643 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
644 httpConn.connect()
645 finally:
646 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000647 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000648 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000649
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000650 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200651 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000652 socket.setdefaulttimeout(30)
653 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000654 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
655 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000656 httpConn.connect()
657 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000658 socket.setdefaulttimeout(None)
659 self.assertEqual(httpConn.sock.gettimeout(), None)
660 httpConn.close()
661
662 # a value
663 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
664 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000665 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000666 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000667
Senthil Kumaran812b9752015-01-24 12:58:10 -0800668
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600669class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000670
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600671 def setUp(self):
672 if not hasattr(httplib, 'HTTPSConnection'):
673 self.skipTest('ssl support required')
674
675 def make_server(self, certfile):
676 from test.ssl_servers import make_https_server
677 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000678
679 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600680 # simple test to check it's storing the timeout
681 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
682 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000683
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600684 def test_networked(self):
685 # Default settings: requires a valid cert from a trusted CA
686 import ssl
687 test_support.requires('network')
688 with test_support.transient_internet('self-signed.pythontest.net'):
689 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
690 with self.assertRaises(ssl.SSLError) as exc_info:
691 h.request('GET', '/')
692 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
693
694 def test_networked_noverification(self):
695 # Switch off cert verification
696 import ssl
697 test_support.requires('network')
698 with test_support.transient_internet('self-signed.pythontest.net'):
699 context = ssl._create_stdlib_context()
700 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
701 context=context)
702 h.request('GET', '/')
703 resp = h.getresponse()
704 self.assertIn('nginx', resp.getheader('server'))
705
Benjamin Petersonf671de42014-11-25 15:16:55 -0600706 @test_support.system_must_validate_cert
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600707 def test_networked_trusted_by_default_cert(self):
708 # Default settings: requires a valid cert from a trusted CA
709 test_support.requires('network')
710 with test_support.transient_internet('www.python.org'):
711 h = httplib.HTTPSConnection('www.python.org', 443)
712 h.request('GET', '/')
713 resp = h.getresponse()
714 content_type = resp.getheader('content-type')
715 self.assertIn('text/html', content_type)
716
717 def test_networked_good_cert(self):
718 # We feed the server's cert as a validating cert
719 import ssl
720 test_support.requires('network')
721 with test_support.transient_internet('self-signed.pythontest.net'):
722 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
723 context.verify_mode = ssl.CERT_REQUIRED
724 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
725 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
726 h.request('GET', '/')
727 resp = h.getresponse()
728 server_string = resp.getheader('server')
729 self.assertIn('nginx', server_string)
730
731 def test_networked_bad_cert(self):
732 # We feed a "CA" cert that is unrelated to the server's cert
733 import ssl
734 test_support.requires('network')
735 with test_support.transient_internet('self-signed.pythontest.net'):
736 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
737 context.verify_mode = ssl.CERT_REQUIRED
738 context.load_verify_locations(CERT_localhost)
739 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
740 with self.assertRaises(ssl.SSLError) as exc_info:
741 h.request('GET', '/')
742 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
743
744 def test_local_unknown_cert(self):
745 # The custom cert isn't known to the default trust bundle
746 import ssl
747 server = self.make_server(CERT_localhost)
748 h = httplib.HTTPSConnection('localhost', server.port)
749 with self.assertRaises(ssl.SSLError) as exc_info:
750 h.request('GET', '/')
751 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
752
753 def test_local_good_hostname(self):
754 # The (valid) cert validates the HTTP hostname
755 import ssl
756 server = self.make_server(CERT_localhost)
757 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
758 context.verify_mode = ssl.CERT_REQUIRED
759 context.load_verify_locations(CERT_localhost)
760 h = httplib.HTTPSConnection('localhost', server.port, context=context)
761 h.request('GET', '/nonexistent')
762 resp = h.getresponse()
763 self.assertEqual(resp.status, 404)
764
765 def test_local_bad_hostname(self):
766 # The (valid) cert doesn't validate the HTTP hostname
767 import ssl
768 server = self.make_server(CERT_fakehostname)
769 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
770 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500771 context.check_hostname = True
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600772 context.load_verify_locations(CERT_fakehostname)
773 h = httplib.HTTPSConnection('localhost', server.port, context=context)
774 with self.assertRaises(ssl.CertificateError):
775 h.request('GET', '/')
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500776 h.close()
777 # With context.check_hostname=False, the mismatching is ignored
778 context.check_hostname = False
779 h = httplib.HTTPSConnection('localhost', server.port, context=context)
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600780 h.request('GET', '/nonexistent')
781 resp = h.getresponse()
782 self.assertEqual(resp.status, 404)
783
Łukasz Langa7a153902011-10-18 17:16:00 +0200784 def test_host_port(self):
785 # Check invalid host_port
786
Łukasz Langa7a153902011-10-18 17:16:00 +0200787 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600788 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200789
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600790 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
791 "fe80::207:e9ff:fe9b", 8000),
792 ("www.python.org:443", "www.python.org", 443),
793 ("www.python.org:", "www.python.org", 443),
794 ("www.python.org", "www.python.org", 443),
795 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
796 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
797 443)):
798 c = httplib.HTTPSConnection(hp)
799 self.assertEqual(h, c.host)
800 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200801
802
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700803class TunnelTests(TestCase):
804 def test_connect(self):
805 response_text = (
806 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
807 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
808 'Content-Length: 42\r\n\r\n'
809 )
810
811 def create_connection(address, timeout=None, source_address=None):
812 return FakeSocket(response_text, host=address[0], port=address[1])
813
814 conn = httplib.HTTPConnection('proxy.com')
815 conn._create_connection = create_connection
816
817 # Once connected, we should not be able to tunnel anymore
818 conn.connect()
819 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
820
821 # But if close the connection, we are good.
822 conn.close()
823 conn.set_tunnel('destination.com')
824 conn.request('HEAD', '/', '')
825
826 self.assertEqual(conn.sock.host, 'proxy.com')
827 self.assertEqual(conn.sock.port, 80)
828 self.assertTrue('CONNECT destination.com' in conn.sock.data)
829 self.assertTrue('Host: destination.com' in conn.sock.data)
830
831 self.assertTrue('Host: proxy.com' not in conn.sock.data)
832
833 conn.close()
834
835 conn.request('PUT', '/', '')
836 self.assertEqual(conn.sock.host, 'proxy.com')
837 self.assertEqual(conn.sock.port, 80)
838 self.assertTrue('CONNECT destination.com' in conn.sock.data)
839 self.assertTrue('Host: destination.com' in conn.sock.data)
840
841
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600842@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000843def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000844 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Senthil Kumaran812b9752015-01-24 12:58:10 -0800845 HTTPTest, HTTPSTest, SourceAddressTest,
846 TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000847
Georg Brandl71a20892006-10-29 20:24:01 +0000848if __name__ == '__main__':
849 test_main()