blob: 011609baa8af37e687d633ac74647e7eb0ce1217 [file] [log] [blame]
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +00001import httplib
Antoine Pitrou72481782009-09-29 17:48:18 +00002import array
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00003import StringIO
Facundo Batista07c78be2007-03-23 18:54:07 +00004import socket
Victor Stinner2c6aee92010-07-24 02:46:16 +00005import errno
Benjamin Petersone3e7d402014-11-23 21:02:02 -06006import os
Jeremy Hylton121d34a2003-07-08 12:36:58 +00007
Gregory P. Smith9d325212010-01-03 02:06:07 +00008import unittest
9TestCase = unittest.TestCase
Jeremy Hylton2c178252004-08-07 16:28:14 +000010
11from test import test_support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000012
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -060013here = os.path.dirname(__file__)
14# Self-signed cert file for 'localhost'
15CERT_localhost = os.path.join(here, 'keycert.pem')
16# Self-signed cert file for 'fakehostname'
17CERT_fakehostname = os.path.join(here, 'keycert2.pem')
18# Self-signed cert file for self-signed.pythontest.net
19CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
20
Trent Nelsone41b0062008-04-08 23:47:30 +000021HOST = test_support.HOST
22
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000023class FakeSocket:
Senthil Kumaran36f28f72014-05-16 18:51:46 -070024 def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000025 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000026 self.fileclass = fileclass
Martin v. Löwis040a9272006-11-12 10:32:47 +000027 self.data = ''
Serhiy Storchakad862db02014-12-01 13:07:28 +020028 self.file_closed = False
Senthil Kumaran36f28f72014-05-16 18:51:46 -070029 self.host = host
30 self.port = port
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000031
Jeremy Hylton2c178252004-08-07 16:28:14 +000032 def sendall(self, data):
Antoine Pitrou72481782009-09-29 17:48:18 +000033 self.data += ''.join(data)
Jeremy Hylton2c178252004-08-07 16:28:14 +000034
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000035 def makefile(self, mode, bufsize=None):
36 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000037 raise httplib.UnimplementedFileMode()
Serhiy Storchakad862db02014-12-01 13:07:28 +020038 # keep the file around so we can check how much was read from it
39 self.file = self.fileclass(self.text)
40 self.file.close = self.file_close #nerf close ()
41 return self.file
42
43 def file_close(self):
44 self.file_closed = True
Jeremy Hylton121d34a2003-07-08 12:36:58 +000045
Senthil Kumaran36f28f72014-05-16 18:51:46 -070046 def close(self):
47 pass
48
Victor Stinner2c6aee92010-07-24 02:46:16 +000049class EPipeSocket(FakeSocket):
50
51 def __init__(self, text, pipe_trigger):
52 # When sendall() is called with pipe_trigger, raise EPIPE.
53 FakeSocket.__init__(self, text)
54 self.pipe_trigger = pipe_trigger
55
56 def sendall(self, data):
57 if self.pipe_trigger in data:
58 raise socket.error(errno.EPIPE, "gotcha")
59 self.data += data
60
61 def close(self):
62 pass
63
Jeremy Hylton121d34a2003-07-08 12:36:58 +000064class NoEOFStringIO(StringIO.StringIO):
65 """Like StringIO, but raises AssertionError on EOF.
66
67 This is used below to test that httplib doesn't try to read
68 more from the underlying file than it should.
69 """
70 def read(self, n=-1):
71 data = StringIO.StringIO.read(self, n)
72 if data == '':
73 raise AssertionError('caller tried to read past EOF')
74 return data
75
76 def readline(self, length=None):
77 data = StringIO.StringIO.readline(self, length)
78 if data == '':
79 raise AssertionError('caller tried to read past EOF')
80 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000081
Jeremy Hylton2c178252004-08-07 16:28:14 +000082
83class HeaderTests(TestCase):
84 def test_auto_headers(self):
85 # Some headers are added automatically, but should not be added by
86 # .request() if they are explicitly set.
87
Jeremy Hylton2c178252004-08-07 16:28:14 +000088 class HeaderCountingBuffer(list):
89 def __init__(self):
90 self.count = {}
91 def append(self, item):
92 kv = item.split(':')
93 if len(kv) > 1:
94 # item is a 'Key: Value' header string
95 lcKey = kv[0].lower()
96 self.count.setdefault(lcKey, 0)
97 self.count[lcKey] += 1
98 list.append(self, item)
99
100 for explicit_header in True, False:
101 for header in 'Content-length', 'Host', 'Accept-encoding':
102 conn = httplib.HTTPConnection('example.com')
103 conn.sock = FakeSocket('blahblahblah')
104 conn._buffer = HeaderCountingBuffer()
105
106 body = 'spamspamspam'
107 headers = {}
108 if explicit_header:
109 headers[header] = str(len(body))
110 conn.request('POST', '/', body, headers)
111 self.assertEqual(conn._buffer.count[header.lower()], 1)
112
Senthil Kumaran618802d2012-05-19 16:52:21 +0800113 def test_content_length_0(self):
114
115 class ContentLengthChecker(list):
116 def __init__(self):
117 list.__init__(self)
118 self.content_length = None
119 def append(self, item):
120 kv = item.split(':', 1)
121 if len(kv) > 1 and kv[0].lower() == 'content-length':
122 self.content_length = kv[1].strip()
123 list.append(self, item)
124
125 # POST with empty body
126 conn = httplib.HTTPConnection('example.com')
127 conn.sock = FakeSocket(None)
128 conn._buffer = ContentLengthChecker()
129 conn.request('POST', '/', '')
130 self.assertEqual(conn._buffer.content_length, '0',
131 'Header Content-Length not set')
132
133 # PUT request with empty body
134 conn = httplib.HTTPConnection('example.com')
135 conn.sock = FakeSocket(None)
136 conn._buffer = ContentLengthChecker()
137 conn.request('PUT', '/', '')
138 self.assertEqual(conn._buffer.content_length, '0',
139 'Header Content-Length not set')
140
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000141 def test_putheader(self):
142 conn = httplib.HTTPConnection('example.com')
143 conn.sock = FakeSocket(None)
144 conn.putrequest('GET','/')
145 conn.putheader('Content-length',42)
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200146 self.assertIn('Content-length: 42', conn._buffer)
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000147
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000148 def test_ipv6host_header(self):
149 # Default host header on IPv6 transaction should wrapped by [] if
150 # its actual IPv6 address
151 expected = 'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
152 'Accept-Encoding: identity\r\n\r\n'
153 conn = httplib.HTTPConnection('[2001::]:81')
154 sock = FakeSocket('')
155 conn.sock = sock
156 conn.request('GET', '/foo')
157 self.assertTrue(sock.data.startswith(expected))
158
159 expected = 'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
160 'Accept-Encoding: identity\r\n\r\n'
161 conn = httplib.HTTPConnection('[2001:102A::]')
162 sock = FakeSocket('')
163 conn.sock = sock
164 conn.request('GET', '/foo')
165 self.assertTrue(sock.data.startswith(expected))
166
167
Georg Brandl71a20892006-10-29 20:24:01 +0000168class BasicTest(TestCase):
169 def test_status_lines(self):
170 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000171
Georg Brandl71a20892006-10-29 20:24:01 +0000172 body = "HTTP/1.1 200 Ok\r\n\r\nText"
173 sock = FakeSocket(body)
174 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000175 resp.begin()
Serhiy Storchakac97f5ed2013-12-17 21:49:48 +0200176 self.assertEqual(resp.read(0), '') # Issue #20007
177 self.assertFalse(resp.isclosed())
Georg Brandl71a20892006-10-29 20:24:01 +0000178 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000179 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000180
Georg Brandl71a20892006-10-29 20:24:01 +0000181 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
182 sock = FakeSocket(body)
183 resp = httplib.HTTPResponse(sock)
184 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000185
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000186 def test_bad_status_repr(self):
187 exc = httplib.BadStatusLine('')
Ezio Melotti2623a372010-11-21 13:34:58 +0000188 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000189
Facundo Batista70665902007-10-18 03:16:03 +0000190 def test_partial_reads(self):
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100191 # if we have a length, the system knows when to close itself
Facundo Batista70665902007-10-18 03:16:03 +0000192 # same behaviour than when we read the whole thing with read()
193 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
194 sock = FakeSocket(body)
195 resp = httplib.HTTPResponse(sock)
196 resp.begin()
197 self.assertEqual(resp.read(2), 'Te')
198 self.assertFalse(resp.isclosed())
199 self.assertEqual(resp.read(2), 'xt')
200 self.assertTrue(resp.isclosed())
201
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100202 def test_partial_reads_no_content_length(self):
203 # when no length is present, the socket should be gracefully closed when
204 # all data was read
205 body = "HTTP/1.1 200 Ok\r\n\r\nText"
206 sock = FakeSocket(body)
207 resp = httplib.HTTPResponse(sock)
208 resp.begin()
209 self.assertEqual(resp.read(2), 'Te')
210 self.assertFalse(resp.isclosed())
211 self.assertEqual(resp.read(2), 'xt')
212 self.assertEqual(resp.read(1), '')
213 self.assertTrue(resp.isclosed())
214
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100215 def test_partial_reads_incomplete_body(self):
216 # if the server shuts down the connection before the whole
217 # content-length is delivered, the socket is gracefully closed
218 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
219 sock = FakeSocket(body)
220 resp = httplib.HTTPResponse(sock)
221 resp.begin()
222 self.assertEqual(resp.read(2), 'Te')
223 self.assertFalse(resp.isclosed())
224 self.assertEqual(resp.read(2), 'xt')
225 self.assertEqual(resp.read(1), '')
226 self.assertTrue(resp.isclosed())
227
Georg Brandl71a20892006-10-29 20:24:01 +0000228 def test_host_port(self):
229 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000230
Łukasz Langa7a153902011-10-18 17:16:00 +0200231 # Note that httplib does not accept user:password@ in the host-port.
232 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Georg Brandl71a20892006-10-29 20:24:01 +0000233 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
234
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000235 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
236 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000237 ("www.python.org:80", "www.python.org", 80),
238 ("www.python.org", "www.python.org", 80),
Łukasz Langa7a153902011-10-18 17:16:00 +0200239 ("www.python.org:", "www.python.org", 80),
Georg Brandl71a20892006-10-29 20:24:01 +0000240 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000241 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000242 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000243 if h != c.host:
244 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
245 if p != c.port:
246 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000247
Georg Brandl71a20892006-10-29 20:24:01 +0000248 def test_response_headers(self):
249 # test response with multiple message headers with the same field name.
250 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000251 'Set-Cookie: Customer="WILE_E_COYOTE";'
252 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000253 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
254 ' Path="/acme"\r\n'
255 '\r\n'
256 'No body\r\n')
257 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
258 ', '
259 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
260 s = FakeSocket(text)
261 r = httplib.HTTPResponse(s)
262 r.begin()
263 cookies = r.getheader("Set-Cookie")
264 if cookies != hdr:
265 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000266
Georg Brandl71a20892006-10-29 20:24:01 +0000267 def test_read_head(self):
268 # Test that the library doesn't attempt to read any data
269 # from a HEAD request. (Tickles SF bug #622042.)
270 sock = FakeSocket(
271 'HTTP/1.1 200 OK\r\n'
272 'Content-Length: 14432\r\n'
273 '\r\n',
274 NoEOFStringIO)
275 resp = httplib.HTTPResponse(sock, method="HEAD")
276 resp.begin()
277 if resp.read() != "":
278 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000279
Berker Peksagb7414e02014-08-05 07:15:57 +0300280 def test_too_many_headers(self):
281 headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
282 text = ('HTTP/1.1 200 OK\r\n' + headers)
283 s = FakeSocket(text)
284 r = httplib.HTTPResponse(s)
285 self.assertRaises(httplib.HTTPException, r.begin)
286
Martin v. Löwis040a9272006-11-12 10:32:47 +0000287 def test_send_file(self):
288 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
289 'Accept-Encoding: identity\r\nContent-Length:'
290
291 body = open(__file__, 'rb')
292 conn = httplib.HTTPConnection('example.com')
293 sock = FakeSocket(body)
294 conn.sock = sock
295 conn.request('GET', '/foo', body)
296 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000297
Antoine Pitrou72481782009-09-29 17:48:18 +0000298 def test_send(self):
299 expected = 'this is a test this is only a test'
300 conn = httplib.HTTPConnection('example.com')
301 sock = FakeSocket(None)
302 conn.sock = sock
303 conn.send(expected)
Ezio Melotti2623a372010-11-21 13:34:58 +0000304 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000305 sock.data = ''
306 conn.send(array.array('c', expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000307 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000308 sock.data = ''
309 conn.send(StringIO.StringIO(expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000310 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000311
Georg Brandl23635032008-02-24 00:03:22 +0000312 def test_chunked(self):
313 chunked_start = (
314 'HTTP/1.1 200 OK\r\n'
315 'Transfer-Encoding: chunked\r\n\r\n'
316 'a\r\n'
317 'hello worl\r\n'
318 '1\r\n'
319 'd\r\n'
320 )
321 sock = FakeSocket(chunked_start + '0\r\n')
322 resp = httplib.HTTPResponse(sock, method="GET")
323 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000324 self.assertEqual(resp.read(), 'hello world')
Georg Brandl23635032008-02-24 00:03:22 +0000325 resp.close()
326
327 for x in ('', 'foo\r\n'):
328 sock = FakeSocket(chunked_start + x)
329 resp = httplib.HTTPResponse(sock, method="GET")
330 resp.begin()
331 try:
332 resp.read()
333 except httplib.IncompleteRead, i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000334 self.assertEqual(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000335 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
336 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000337 else:
338 self.fail('IncompleteRead expected')
339 finally:
340 resp.close()
341
Senthil Kumaraned9204342010-04-28 17:20:43 +0000342 def test_chunked_head(self):
343 chunked_start = (
344 'HTTP/1.1 200 OK\r\n'
345 'Transfer-Encoding: chunked\r\n\r\n'
346 'a\r\n'
347 'hello world\r\n'
348 '1\r\n'
349 'd\r\n'
350 )
351 sock = FakeSocket(chunked_start + '0\r\n')
352 resp = httplib.HTTPResponse(sock, method="HEAD")
353 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000354 self.assertEqual(resp.read(), '')
355 self.assertEqual(resp.status, 200)
356 self.assertEqual(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000357 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000358
Georg Brandl8c460d52008-02-24 00:14:24 +0000359 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000360 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
361 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000362 resp = httplib.HTTPResponse(sock, method="GET")
363 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000364 self.assertEqual(resp.read(), 'Hello\r\n')
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100365 self.assertTrue(resp.isclosed())
Georg Brandl8c460d52008-02-24 00:14:24 +0000366
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000367 def test_incomplete_read(self):
368 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
369 resp = httplib.HTTPResponse(sock, method="GET")
370 resp.begin()
371 try:
372 resp.read()
373 except httplib.IncompleteRead as i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000374 self.assertEqual(i.partial, 'Hello\r\n')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000375 self.assertEqual(repr(i),
376 "IncompleteRead(7 bytes read, 3 more expected)")
377 self.assertEqual(str(i),
378 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100379 self.assertTrue(resp.isclosed())
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000380 else:
381 self.fail('IncompleteRead expected')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000382
Victor Stinner2c6aee92010-07-24 02:46:16 +0000383 def test_epipe(self):
384 sock = EPipeSocket(
385 "HTTP/1.0 401 Authorization Required\r\n"
386 "Content-type: text/html\r\n"
387 "WWW-Authenticate: Basic realm=\"example\"\r\n",
388 b"Content-Length")
389 conn = httplib.HTTPConnection("example.com")
390 conn.sock = sock
391 self.assertRaises(socket.error,
392 lambda: conn.request("PUT", "/url", "body"))
393 resp = conn.getresponse()
394 self.assertEqual(401, resp.status)
395 self.assertEqual("Basic realm=\"example\"",
396 resp.getheader("www-authenticate"))
397
Senthil Kumarand389cb52010-09-21 01:38:15 +0000398 def test_filenoattr(self):
399 # Just test the fileno attribute in the HTTPResponse Object.
400 body = "HTTP/1.1 200 Ok\r\n\r\nText"
401 sock = FakeSocket(body)
402 resp = httplib.HTTPResponse(sock)
403 self.assertTrue(hasattr(resp,'fileno'),
404 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000405
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000406 # Test lines overflowing the max line size (_MAXLINE in http.client)
407
408 def test_overflowing_status_line(self):
409 self.skipTest("disabled for HTTP 0.9 support")
410 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
411 resp = httplib.HTTPResponse(FakeSocket(body))
412 self.assertRaises((httplib.LineTooLong, httplib.BadStatusLine), resp.begin)
413
414 def test_overflowing_header_line(self):
415 body = (
416 'HTTP/1.1 200 OK\r\n'
417 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
418 )
419 resp = httplib.HTTPResponse(FakeSocket(body))
420 self.assertRaises(httplib.LineTooLong, resp.begin)
421
422 def test_overflowing_chunked_line(self):
423 body = (
424 'HTTP/1.1 200 OK\r\n'
425 'Transfer-Encoding: chunked\r\n\r\n'
426 + '0' * 65536 + 'a\r\n'
427 'hello world\r\n'
428 '0\r\n'
429 )
430 resp = httplib.HTTPResponse(FakeSocket(body))
431 resp.begin()
432 self.assertRaises(httplib.LineTooLong, resp.read)
433
Senthil Kumaranf5aaf6f2012-04-29 10:15:31 +0800434 def test_early_eof(self):
435 # Test httpresponse with no \r\n termination,
436 body = "HTTP/1.1 200 Ok"
437 sock = FakeSocket(body)
438 resp = httplib.HTTPResponse(sock)
439 resp.begin()
440 self.assertEqual(resp.read(), '')
441 self.assertTrue(resp.isclosed())
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000442
Serhiy Storchakad862db02014-12-01 13:07:28 +0200443 def test_error_leak(self):
444 # Test that the socket is not leaked if getresponse() fails
445 conn = httplib.HTTPConnection('example.com')
446 response = []
447 class Response(httplib.HTTPResponse):
448 def __init__(self, *pos, **kw):
449 response.append(self) # Avoid garbage collector closing the socket
450 httplib.HTTPResponse.__init__(self, *pos, **kw)
451 conn.response_class = Response
452 conn.sock = FakeSocket('') # Emulate server dropping connection
453 conn.request('GET', '/')
454 self.assertRaises(httplib.BadStatusLine, conn.getresponse)
455 self.assertTrue(response)
456 #self.assertTrue(response[0].closed)
457 self.assertTrue(conn.sock.file_closed)
458
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000459class OfflineTest(TestCase):
460 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000461 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000462
Gregory P. Smith9d325212010-01-03 02:06:07 +0000463
464class SourceAddressTest(TestCase):
465 def setUp(self):
466 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
467 self.port = test_support.bind_port(self.serv)
468 self.source_port = test_support.find_unused_port()
469 self.serv.listen(5)
470 self.conn = None
471
472 def tearDown(self):
473 if self.conn:
474 self.conn.close()
475 self.conn = None
476 self.serv.close()
477 self.serv = None
478
479 def testHTTPConnectionSourceAddress(self):
480 self.conn = httplib.HTTPConnection(HOST, self.port,
481 source_address=('', self.source_port))
482 self.conn.connect()
483 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
484
485 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
486 'httplib.HTTPSConnection not defined')
487 def testHTTPSConnectionSourceAddress(self):
488 self.conn = httplib.HTTPSConnection(HOST, self.port,
489 source_address=('', self.source_port))
490 # We don't test anything here other the constructor not barfing as
491 # this code doesn't deal with setting up an active running SSL server
492 # for an ssl_wrapped connect() to actually return from.
493
494
Facundo Batista07c78be2007-03-23 18:54:07 +0000495class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000496 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000497
Facundo Batista07c78be2007-03-23 18:54:07 +0000498 def setUp(self):
499 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000500 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000501 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000502
503 def tearDown(self):
504 self.serv.close()
505 self.serv = None
506
507 def testTimeoutAttribute(self):
508 '''This will prove that the timeout gets through
509 HTTPConnection and into the socket.
510 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000511 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200512 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000513 socket.setdefaulttimeout(30)
514 try:
515 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
516 httpConn.connect()
517 finally:
518 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000519 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000520 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000521
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000522 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200523 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000524 socket.setdefaulttimeout(30)
525 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000526 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
527 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000528 httpConn.connect()
529 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000530 socket.setdefaulttimeout(None)
531 self.assertEqual(httpConn.sock.gettimeout(), None)
532 httpConn.close()
533
534 # a value
535 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
536 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000537 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000538 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000539
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600540class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000541
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600542 def setUp(self):
543 if not hasattr(httplib, 'HTTPSConnection'):
544 self.skipTest('ssl support required')
545
546 def make_server(self, certfile):
547 from test.ssl_servers import make_https_server
548 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000549
550 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600551 # simple test to check it's storing the timeout
552 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
553 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000554
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600555 def test_networked(self):
556 # Default settings: requires a valid cert from a trusted CA
557 import ssl
558 test_support.requires('network')
559 with test_support.transient_internet('self-signed.pythontest.net'):
560 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
561 with self.assertRaises(ssl.SSLError) as exc_info:
562 h.request('GET', '/')
563 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
564
565 def test_networked_noverification(self):
566 # Switch off cert verification
567 import ssl
568 test_support.requires('network')
569 with test_support.transient_internet('self-signed.pythontest.net'):
570 context = ssl._create_stdlib_context()
571 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
572 context=context)
573 h.request('GET', '/')
574 resp = h.getresponse()
575 self.assertIn('nginx', resp.getheader('server'))
576
Benjamin Petersonf671de42014-11-25 15:16:55 -0600577 @test_support.system_must_validate_cert
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600578 def test_networked_trusted_by_default_cert(self):
579 # Default settings: requires a valid cert from a trusted CA
580 test_support.requires('network')
581 with test_support.transient_internet('www.python.org'):
582 h = httplib.HTTPSConnection('www.python.org', 443)
583 h.request('GET', '/')
584 resp = h.getresponse()
585 content_type = resp.getheader('content-type')
586 self.assertIn('text/html', content_type)
587
588 def test_networked_good_cert(self):
589 # We feed the server's cert as a validating cert
590 import ssl
591 test_support.requires('network')
592 with test_support.transient_internet('self-signed.pythontest.net'):
593 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
594 context.verify_mode = ssl.CERT_REQUIRED
595 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
596 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
597 h.request('GET', '/')
598 resp = h.getresponse()
599 server_string = resp.getheader('server')
600 self.assertIn('nginx', server_string)
601
602 def test_networked_bad_cert(self):
603 # We feed a "CA" cert that is unrelated to the server's cert
604 import ssl
605 test_support.requires('network')
606 with test_support.transient_internet('self-signed.pythontest.net'):
607 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
608 context.verify_mode = ssl.CERT_REQUIRED
609 context.load_verify_locations(CERT_localhost)
610 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
611 with self.assertRaises(ssl.SSLError) as exc_info:
612 h.request('GET', '/')
613 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
614
615 def test_local_unknown_cert(self):
616 # The custom cert isn't known to the default trust bundle
617 import ssl
618 server = self.make_server(CERT_localhost)
619 h = httplib.HTTPSConnection('localhost', server.port)
620 with self.assertRaises(ssl.SSLError) as exc_info:
621 h.request('GET', '/')
622 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
623
624 def test_local_good_hostname(self):
625 # The (valid) cert validates the HTTP hostname
626 import ssl
627 server = self.make_server(CERT_localhost)
628 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
629 context.verify_mode = ssl.CERT_REQUIRED
630 context.load_verify_locations(CERT_localhost)
631 h = httplib.HTTPSConnection('localhost', server.port, context=context)
632 h.request('GET', '/nonexistent')
633 resp = h.getresponse()
634 self.assertEqual(resp.status, 404)
635
636 def test_local_bad_hostname(self):
637 # The (valid) cert doesn't validate the HTTP hostname
638 import ssl
639 server = self.make_server(CERT_fakehostname)
640 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
641 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500642 context.check_hostname = True
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600643 context.load_verify_locations(CERT_fakehostname)
644 h = httplib.HTTPSConnection('localhost', server.port, context=context)
645 with self.assertRaises(ssl.CertificateError):
646 h.request('GET', '/')
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500647 h.close()
648 # With context.check_hostname=False, the mismatching is ignored
649 context.check_hostname = False
650 h = httplib.HTTPSConnection('localhost', server.port, context=context)
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600651 h.request('GET', '/nonexistent')
652 resp = h.getresponse()
653 self.assertEqual(resp.status, 404)
654
Łukasz Langa7a153902011-10-18 17:16:00 +0200655 def test_host_port(self):
656 # Check invalid host_port
657
Łukasz Langa7a153902011-10-18 17:16:00 +0200658 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600659 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200660
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600661 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
662 "fe80::207:e9ff:fe9b", 8000),
663 ("www.python.org:443", "www.python.org", 443),
664 ("www.python.org:", "www.python.org", 443),
665 ("www.python.org", "www.python.org", 443),
666 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
667 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
668 443)):
669 c = httplib.HTTPSConnection(hp)
670 self.assertEqual(h, c.host)
671 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200672
673
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700674class TunnelTests(TestCase):
675 def test_connect(self):
676 response_text = (
677 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
678 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
679 'Content-Length: 42\r\n\r\n'
680 )
681
682 def create_connection(address, timeout=None, source_address=None):
683 return FakeSocket(response_text, host=address[0], port=address[1])
684
685 conn = httplib.HTTPConnection('proxy.com')
686 conn._create_connection = create_connection
687
688 # Once connected, we should not be able to tunnel anymore
689 conn.connect()
690 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
691
692 # But if close the connection, we are good.
693 conn.close()
694 conn.set_tunnel('destination.com')
695 conn.request('HEAD', '/', '')
696
697 self.assertEqual(conn.sock.host, 'proxy.com')
698 self.assertEqual(conn.sock.port, 80)
699 self.assertTrue('CONNECT destination.com' in conn.sock.data)
700 self.assertTrue('Host: destination.com' in conn.sock.data)
701
702 self.assertTrue('Host: proxy.com' not in conn.sock.data)
703
704 conn.close()
705
706 conn.request('PUT', '/', '')
707 self.assertEqual(conn.sock.host, 'proxy.com')
708 self.assertEqual(conn.sock.port, 80)
709 self.assertTrue('CONNECT destination.com' in conn.sock.data)
710 self.assertTrue('Host: destination.com' in conn.sock.data)
711
712
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600713@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000714def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000715 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600716 HTTPSTest, SourceAddressTest, TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000717
Georg Brandl71a20892006-10-29 20:24:01 +0000718if __name__ == '__main__':
719 test_main()