blob: e68555a1691e86c259ec82bbde30d5314e7a7c65 [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 = ''
Senthil Kumaran36f28f72014-05-16 18:51:46 -070028 self.host = host
29 self.port = port
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000030
Jeremy Hylton2c178252004-08-07 16:28:14 +000031 def sendall(self, data):
Antoine Pitrou72481782009-09-29 17:48:18 +000032 self.data += ''.join(data)
Jeremy Hylton2c178252004-08-07 16:28:14 +000033
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000034 def makefile(self, mode, bufsize=None):
35 if mode != 'r' and mode != 'rb':
Neal Norwitz28bb5722002-04-01 19:00:50 +000036 raise httplib.UnimplementedFileMode()
Jeremy Hylton121d34a2003-07-08 12:36:58 +000037 return self.fileclass(self.text)
38
Senthil Kumaran36f28f72014-05-16 18:51:46 -070039 def close(self):
40 pass
41
Victor Stinner2c6aee92010-07-24 02:46:16 +000042class EPipeSocket(FakeSocket):
43
44 def __init__(self, text, pipe_trigger):
45 # When sendall() is called with pipe_trigger, raise EPIPE.
46 FakeSocket.__init__(self, text)
47 self.pipe_trigger = pipe_trigger
48
49 def sendall(self, data):
50 if self.pipe_trigger in data:
51 raise socket.error(errno.EPIPE, "gotcha")
52 self.data += data
53
54 def close(self):
55 pass
56
Jeremy Hylton121d34a2003-07-08 12:36:58 +000057class NoEOFStringIO(StringIO.StringIO):
58 """Like StringIO, but raises AssertionError on EOF.
59
60 This is used below to test that httplib doesn't try to read
61 more from the underlying file than it should.
62 """
63 def read(self, n=-1):
64 data = StringIO.StringIO.read(self, n)
65 if data == '':
66 raise AssertionError('caller tried to read past EOF')
67 return data
68
69 def readline(self, length=None):
70 data = StringIO.StringIO.readline(self, length)
71 if data == '':
72 raise AssertionError('caller tried to read past EOF')
73 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000074
Jeremy Hylton2c178252004-08-07 16:28:14 +000075
76class HeaderTests(TestCase):
77 def test_auto_headers(self):
78 # Some headers are added automatically, but should not be added by
79 # .request() if they are explicitly set.
80
Jeremy Hylton2c178252004-08-07 16:28:14 +000081 class HeaderCountingBuffer(list):
82 def __init__(self):
83 self.count = {}
84 def append(self, item):
85 kv = item.split(':')
86 if len(kv) > 1:
87 # item is a 'Key: Value' header string
88 lcKey = kv[0].lower()
89 self.count.setdefault(lcKey, 0)
90 self.count[lcKey] += 1
91 list.append(self, item)
92
93 for explicit_header in True, False:
94 for header in 'Content-length', 'Host', 'Accept-encoding':
95 conn = httplib.HTTPConnection('example.com')
96 conn.sock = FakeSocket('blahblahblah')
97 conn._buffer = HeaderCountingBuffer()
98
99 body = 'spamspamspam'
100 headers = {}
101 if explicit_header:
102 headers[header] = str(len(body))
103 conn.request('POST', '/', body, headers)
104 self.assertEqual(conn._buffer.count[header.lower()], 1)
105
Senthil Kumaran618802d2012-05-19 16:52:21 +0800106 def test_content_length_0(self):
107
108 class ContentLengthChecker(list):
109 def __init__(self):
110 list.__init__(self)
111 self.content_length = None
112 def append(self, item):
113 kv = item.split(':', 1)
114 if len(kv) > 1 and kv[0].lower() == 'content-length':
115 self.content_length = kv[1].strip()
116 list.append(self, item)
117
118 # POST with empty body
119 conn = httplib.HTTPConnection('example.com')
120 conn.sock = FakeSocket(None)
121 conn._buffer = ContentLengthChecker()
122 conn.request('POST', '/', '')
123 self.assertEqual(conn._buffer.content_length, '0',
124 'Header Content-Length not set')
125
126 # PUT request with empty body
127 conn = httplib.HTTPConnection('example.com')
128 conn.sock = FakeSocket(None)
129 conn._buffer = ContentLengthChecker()
130 conn.request('PUT', '/', '')
131 self.assertEqual(conn._buffer.content_length, '0',
132 'Header Content-Length not set')
133
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000134 def test_putheader(self):
135 conn = httplib.HTTPConnection('example.com')
136 conn.sock = FakeSocket(None)
137 conn.putrequest('GET','/')
138 conn.putheader('Content-length',42)
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200139 self.assertIn('Content-length: 42', conn._buffer)
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000140
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000141 def test_ipv6host_header(self):
142 # Default host header on IPv6 transaction should wrapped by [] if
143 # its actual IPv6 address
144 expected = 'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
145 'Accept-Encoding: identity\r\n\r\n'
146 conn = httplib.HTTPConnection('[2001::]:81')
147 sock = FakeSocket('')
148 conn.sock = sock
149 conn.request('GET', '/foo')
150 self.assertTrue(sock.data.startswith(expected))
151
152 expected = 'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
153 'Accept-Encoding: identity\r\n\r\n'
154 conn = httplib.HTTPConnection('[2001:102A::]')
155 sock = FakeSocket('')
156 conn.sock = sock
157 conn.request('GET', '/foo')
158 self.assertTrue(sock.data.startswith(expected))
159
160
Georg Brandl71a20892006-10-29 20:24:01 +0000161class BasicTest(TestCase):
162 def test_status_lines(self):
163 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000164
Georg Brandl71a20892006-10-29 20:24:01 +0000165 body = "HTTP/1.1 200 Ok\r\n\r\nText"
166 sock = FakeSocket(body)
167 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000168 resp.begin()
Serhiy Storchakac97f5ed2013-12-17 21:49:48 +0200169 self.assertEqual(resp.read(0), '') # Issue #20007
170 self.assertFalse(resp.isclosed())
Georg Brandl71a20892006-10-29 20:24:01 +0000171 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000172 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000173
Georg Brandl71a20892006-10-29 20:24:01 +0000174 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
175 sock = FakeSocket(body)
176 resp = httplib.HTTPResponse(sock)
177 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000178
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000179 def test_bad_status_repr(self):
180 exc = httplib.BadStatusLine('')
Ezio Melotti2623a372010-11-21 13:34:58 +0000181 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000182
Facundo Batista70665902007-10-18 03:16:03 +0000183 def test_partial_reads(self):
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100184 # if we have a length, the system knows when to close itself
Facundo Batista70665902007-10-18 03:16:03 +0000185 # same behaviour than when we read the whole thing with read()
186 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
187 sock = FakeSocket(body)
188 resp = httplib.HTTPResponse(sock)
189 resp.begin()
190 self.assertEqual(resp.read(2), 'Te')
191 self.assertFalse(resp.isclosed())
192 self.assertEqual(resp.read(2), 'xt')
193 self.assertTrue(resp.isclosed())
194
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100195 def test_partial_reads_no_content_length(self):
196 # when no length is present, the socket should be gracefully closed when
197 # all data was read
198 body = "HTTP/1.1 200 Ok\r\n\r\nText"
199 sock = FakeSocket(body)
200 resp = httplib.HTTPResponse(sock)
201 resp.begin()
202 self.assertEqual(resp.read(2), 'Te')
203 self.assertFalse(resp.isclosed())
204 self.assertEqual(resp.read(2), 'xt')
205 self.assertEqual(resp.read(1), '')
206 self.assertTrue(resp.isclosed())
207
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100208 def test_partial_reads_incomplete_body(self):
209 # if the server shuts down the connection before the whole
210 # content-length is delivered, the socket is gracefully closed
211 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
212 sock = FakeSocket(body)
213 resp = httplib.HTTPResponse(sock)
214 resp.begin()
215 self.assertEqual(resp.read(2), 'Te')
216 self.assertFalse(resp.isclosed())
217 self.assertEqual(resp.read(2), 'xt')
218 self.assertEqual(resp.read(1), '')
219 self.assertTrue(resp.isclosed())
220
Georg Brandl71a20892006-10-29 20:24:01 +0000221 def test_host_port(self):
222 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000223
Łukasz Langa7a153902011-10-18 17:16:00 +0200224 # Note that httplib does not accept user:password@ in the host-port.
225 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Georg Brandl71a20892006-10-29 20:24:01 +0000226 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
227
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000228 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
229 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000230 ("www.python.org:80", "www.python.org", 80),
231 ("www.python.org", "www.python.org", 80),
Łukasz Langa7a153902011-10-18 17:16:00 +0200232 ("www.python.org:", "www.python.org", 80),
Georg Brandl71a20892006-10-29 20:24:01 +0000233 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000234 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000235 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000236 if h != c.host:
237 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
238 if p != c.port:
239 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000240
Georg Brandl71a20892006-10-29 20:24:01 +0000241 def test_response_headers(self):
242 # test response with multiple message headers with the same field name.
243 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000244 'Set-Cookie: Customer="WILE_E_COYOTE";'
245 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000246 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
247 ' Path="/acme"\r\n'
248 '\r\n'
249 'No body\r\n')
250 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
251 ', '
252 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
253 s = FakeSocket(text)
254 r = httplib.HTTPResponse(s)
255 r.begin()
256 cookies = r.getheader("Set-Cookie")
257 if cookies != hdr:
258 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000259
Georg Brandl71a20892006-10-29 20:24:01 +0000260 def test_read_head(self):
261 # Test that the library doesn't attempt to read any data
262 # from a HEAD request. (Tickles SF bug #622042.)
263 sock = FakeSocket(
264 'HTTP/1.1 200 OK\r\n'
265 'Content-Length: 14432\r\n'
266 '\r\n',
267 NoEOFStringIO)
268 resp = httplib.HTTPResponse(sock, method="HEAD")
269 resp.begin()
270 if resp.read() != "":
271 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000272
Berker Peksagb7414e02014-08-05 07:15:57 +0300273 def test_too_many_headers(self):
274 headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
275 text = ('HTTP/1.1 200 OK\r\n' + headers)
276 s = FakeSocket(text)
277 r = httplib.HTTPResponse(s)
278 self.assertRaises(httplib.HTTPException, r.begin)
279
Martin v. Löwis040a9272006-11-12 10:32:47 +0000280 def test_send_file(self):
281 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
282 'Accept-Encoding: identity\r\nContent-Length:'
283
284 body = open(__file__, 'rb')
285 conn = httplib.HTTPConnection('example.com')
286 sock = FakeSocket(body)
287 conn.sock = sock
288 conn.request('GET', '/foo', body)
289 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000290
Antoine Pitrou72481782009-09-29 17:48:18 +0000291 def test_send(self):
292 expected = 'this is a test this is only a test'
293 conn = httplib.HTTPConnection('example.com')
294 sock = FakeSocket(None)
295 conn.sock = sock
296 conn.send(expected)
Ezio Melotti2623a372010-11-21 13:34:58 +0000297 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000298 sock.data = ''
299 conn.send(array.array('c', expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000300 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000301 sock.data = ''
302 conn.send(StringIO.StringIO(expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000303 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000304
Georg Brandl23635032008-02-24 00:03:22 +0000305 def test_chunked(self):
306 chunked_start = (
307 'HTTP/1.1 200 OK\r\n'
308 'Transfer-Encoding: chunked\r\n\r\n'
309 'a\r\n'
310 'hello worl\r\n'
311 '1\r\n'
312 'd\r\n'
313 )
314 sock = FakeSocket(chunked_start + '0\r\n')
315 resp = httplib.HTTPResponse(sock, method="GET")
316 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000317 self.assertEqual(resp.read(), 'hello world')
Georg Brandl23635032008-02-24 00:03:22 +0000318 resp.close()
319
320 for x in ('', 'foo\r\n'):
321 sock = FakeSocket(chunked_start + x)
322 resp = httplib.HTTPResponse(sock, method="GET")
323 resp.begin()
324 try:
325 resp.read()
326 except httplib.IncompleteRead, i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000327 self.assertEqual(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000328 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
329 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000330 else:
331 self.fail('IncompleteRead expected')
332 finally:
333 resp.close()
334
Senthil Kumaraned9204342010-04-28 17:20:43 +0000335 def test_chunked_head(self):
336 chunked_start = (
337 'HTTP/1.1 200 OK\r\n'
338 'Transfer-Encoding: chunked\r\n\r\n'
339 'a\r\n'
340 'hello world\r\n'
341 '1\r\n'
342 'd\r\n'
343 )
344 sock = FakeSocket(chunked_start + '0\r\n')
345 resp = httplib.HTTPResponse(sock, method="HEAD")
346 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000347 self.assertEqual(resp.read(), '')
348 self.assertEqual(resp.status, 200)
349 self.assertEqual(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000350 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000351
Georg Brandl8c460d52008-02-24 00:14:24 +0000352 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000353 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
354 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000355 resp = httplib.HTTPResponse(sock, method="GET")
356 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000357 self.assertEqual(resp.read(), 'Hello\r\n')
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100358 self.assertTrue(resp.isclosed())
Georg Brandl8c460d52008-02-24 00:14:24 +0000359
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000360 def test_incomplete_read(self):
361 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
362 resp = httplib.HTTPResponse(sock, method="GET")
363 resp.begin()
364 try:
365 resp.read()
366 except httplib.IncompleteRead as i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000367 self.assertEqual(i.partial, 'Hello\r\n')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000368 self.assertEqual(repr(i),
369 "IncompleteRead(7 bytes read, 3 more expected)")
370 self.assertEqual(str(i),
371 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100372 self.assertTrue(resp.isclosed())
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000373 else:
374 self.fail('IncompleteRead expected')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000375
Victor Stinner2c6aee92010-07-24 02:46:16 +0000376 def test_epipe(self):
377 sock = EPipeSocket(
378 "HTTP/1.0 401 Authorization Required\r\n"
379 "Content-type: text/html\r\n"
380 "WWW-Authenticate: Basic realm=\"example\"\r\n",
381 b"Content-Length")
382 conn = httplib.HTTPConnection("example.com")
383 conn.sock = sock
384 self.assertRaises(socket.error,
385 lambda: conn.request("PUT", "/url", "body"))
386 resp = conn.getresponse()
387 self.assertEqual(401, resp.status)
388 self.assertEqual("Basic realm=\"example\"",
389 resp.getheader("www-authenticate"))
390
Senthil Kumarand389cb52010-09-21 01:38:15 +0000391 def test_filenoattr(self):
392 # Just test the fileno attribute in the HTTPResponse Object.
393 body = "HTTP/1.1 200 Ok\r\n\r\nText"
394 sock = FakeSocket(body)
395 resp = httplib.HTTPResponse(sock)
396 self.assertTrue(hasattr(resp,'fileno'),
397 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000398
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000399 # Test lines overflowing the max line size (_MAXLINE in http.client)
400
401 def test_overflowing_status_line(self):
402 self.skipTest("disabled for HTTP 0.9 support")
403 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
404 resp = httplib.HTTPResponse(FakeSocket(body))
405 self.assertRaises((httplib.LineTooLong, httplib.BadStatusLine), resp.begin)
406
407 def test_overflowing_header_line(self):
408 body = (
409 'HTTP/1.1 200 OK\r\n'
410 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
411 )
412 resp = httplib.HTTPResponse(FakeSocket(body))
413 self.assertRaises(httplib.LineTooLong, resp.begin)
414
415 def test_overflowing_chunked_line(self):
416 body = (
417 'HTTP/1.1 200 OK\r\n'
418 'Transfer-Encoding: chunked\r\n\r\n'
419 + '0' * 65536 + 'a\r\n'
420 'hello world\r\n'
421 '0\r\n'
422 )
423 resp = httplib.HTTPResponse(FakeSocket(body))
424 resp.begin()
425 self.assertRaises(httplib.LineTooLong, resp.read)
426
Senthil Kumaranf5aaf6f2012-04-29 10:15:31 +0800427 def test_early_eof(self):
428 # Test httpresponse with no \r\n termination,
429 body = "HTTP/1.1 200 Ok"
430 sock = FakeSocket(body)
431 resp = httplib.HTTPResponse(sock)
432 resp.begin()
433 self.assertEqual(resp.read(), '')
434 self.assertTrue(resp.isclosed())
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000435
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000436class OfflineTest(TestCase):
437 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000438 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000439
Gregory P. Smith9d325212010-01-03 02:06:07 +0000440
441class SourceAddressTest(TestCase):
442 def setUp(self):
443 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
444 self.port = test_support.bind_port(self.serv)
445 self.source_port = test_support.find_unused_port()
446 self.serv.listen(5)
447 self.conn = None
448
449 def tearDown(self):
450 if self.conn:
451 self.conn.close()
452 self.conn = None
453 self.serv.close()
454 self.serv = None
455
456 def testHTTPConnectionSourceAddress(self):
457 self.conn = httplib.HTTPConnection(HOST, self.port,
458 source_address=('', self.source_port))
459 self.conn.connect()
460 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
461
462 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
463 'httplib.HTTPSConnection not defined')
464 def testHTTPSConnectionSourceAddress(self):
465 self.conn = httplib.HTTPSConnection(HOST, self.port,
466 source_address=('', self.source_port))
467 # We don't test anything here other the constructor not barfing as
468 # this code doesn't deal with setting up an active running SSL server
469 # for an ssl_wrapped connect() to actually return from.
470
471
Facundo Batista07c78be2007-03-23 18:54:07 +0000472class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000473 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000474
Facundo Batista07c78be2007-03-23 18:54:07 +0000475 def setUp(self):
476 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000477 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000478 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000479
480 def tearDown(self):
481 self.serv.close()
482 self.serv = None
483
484 def testTimeoutAttribute(self):
485 '''This will prove that the timeout gets through
486 HTTPConnection and into the socket.
487 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000488 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200489 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000490 socket.setdefaulttimeout(30)
491 try:
492 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
493 httpConn.connect()
494 finally:
495 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000496 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000497 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000498
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000499 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200500 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000501 socket.setdefaulttimeout(30)
502 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000503 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
504 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000505 httpConn.connect()
506 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000507 socket.setdefaulttimeout(None)
508 self.assertEqual(httpConn.sock.gettimeout(), None)
509 httpConn.close()
510
511 # a value
512 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
513 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000514 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000515 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000516
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600517class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000518
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600519 def setUp(self):
520 if not hasattr(httplib, 'HTTPSConnection'):
521 self.skipTest('ssl support required')
522
523 def make_server(self, certfile):
524 from test.ssl_servers import make_https_server
525 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000526
527 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600528 # simple test to check it's storing the timeout
529 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
530 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000531
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600532 def test_networked(self):
533 # Default settings: requires a valid cert from a trusted CA
534 import ssl
535 test_support.requires('network')
536 with test_support.transient_internet('self-signed.pythontest.net'):
537 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
538 with self.assertRaises(ssl.SSLError) as exc_info:
539 h.request('GET', '/')
540 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
541
542 def test_networked_noverification(self):
543 # Switch off cert verification
544 import ssl
545 test_support.requires('network')
546 with test_support.transient_internet('self-signed.pythontest.net'):
547 context = ssl._create_stdlib_context()
548 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
549 context=context)
550 h.request('GET', '/')
551 resp = h.getresponse()
552 self.assertIn('nginx', resp.getheader('server'))
553
554 def test_networked_trusted_by_default_cert(self):
555 # Default settings: requires a valid cert from a trusted CA
556 test_support.requires('network')
557 with test_support.transient_internet('www.python.org'):
558 h = httplib.HTTPSConnection('www.python.org', 443)
559 h.request('GET', '/')
560 resp = h.getresponse()
561 content_type = resp.getheader('content-type')
562 self.assertIn('text/html', content_type)
563
564 def test_networked_good_cert(self):
565 # We feed the server's cert as a validating cert
566 import ssl
567 test_support.requires('network')
568 with test_support.transient_internet('self-signed.pythontest.net'):
569 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
570 context.verify_mode = ssl.CERT_REQUIRED
571 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
572 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
573 h.request('GET', '/')
574 resp = h.getresponse()
575 server_string = resp.getheader('server')
576 self.assertIn('nginx', server_string)
577
578 def test_networked_bad_cert(self):
579 # We feed a "CA" cert that is unrelated to the server's cert
580 import ssl
581 test_support.requires('network')
582 with test_support.transient_internet('self-signed.pythontest.net'):
583 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
584 context.verify_mode = ssl.CERT_REQUIRED
585 context.load_verify_locations(CERT_localhost)
586 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
587 with self.assertRaises(ssl.SSLError) as exc_info:
588 h.request('GET', '/')
589 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
590
591 def test_local_unknown_cert(self):
592 # The custom cert isn't known to the default trust bundle
593 import ssl
594 server = self.make_server(CERT_localhost)
595 h = httplib.HTTPSConnection('localhost', server.port)
596 with self.assertRaises(ssl.SSLError) as exc_info:
597 h.request('GET', '/')
598 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
599
600 def test_local_good_hostname(self):
601 # The (valid) cert validates the HTTP hostname
602 import ssl
603 server = self.make_server(CERT_localhost)
604 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
605 context.verify_mode = ssl.CERT_REQUIRED
606 context.load_verify_locations(CERT_localhost)
607 h = httplib.HTTPSConnection('localhost', server.port, context=context)
608 h.request('GET', '/nonexistent')
609 resp = h.getresponse()
610 self.assertEqual(resp.status, 404)
611
612 def test_local_bad_hostname(self):
613 # The (valid) cert doesn't validate the HTTP hostname
614 import ssl
615 server = self.make_server(CERT_fakehostname)
616 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
617 context.verify_mode = ssl.CERT_REQUIRED
618 context.load_verify_locations(CERT_fakehostname)
619 h = httplib.HTTPSConnection('localhost', server.port, context=context)
620 with self.assertRaises(ssl.CertificateError):
621 h.request('GET', '/')
622 # Same with explicit check_hostname=True
623 h = httplib.HTTPSConnection('localhost', server.port, context=context,
624 check_hostname=True)
625 with self.assertRaises(ssl.CertificateError):
626 h.request('GET', '/')
627 # With check_hostname=False, the mismatching is ignored
628 h = httplib.HTTPSConnection('localhost', server.port, context=context,
629 check_hostname=False)
630 h.request('GET', '/nonexistent')
631 resp = h.getresponse()
632 self.assertEqual(resp.status, 404)
633
Łukasz Langa7a153902011-10-18 17:16:00 +0200634 def test_host_port(self):
635 # Check invalid host_port
636
Łukasz Langa7a153902011-10-18 17:16:00 +0200637 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600638 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200639
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600640 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
641 "fe80::207:e9ff:fe9b", 8000),
642 ("www.python.org:443", "www.python.org", 443),
643 ("www.python.org:", "www.python.org", 443),
644 ("www.python.org", "www.python.org", 443),
645 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
646 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
647 443)):
648 c = httplib.HTTPSConnection(hp)
649 self.assertEqual(h, c.host)
650 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200651
652
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700653class TunnelTests(TestCase):
654 def test_connect(self):
655 response_text = (
656 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
657 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
658 'Content-Length: 42\r\n\r\n'
659 )
660
661 def create_connection(address, timeout=None, source_address=None):
662 return FakeSocket(response_text, host=address[0], port=address[1])
663
664 conn = httplib.HTTPConnection('proxy.com')
665 conn._create_connection = create_connection
666
667 # Once connected, we should not be able to tunnel anymore
668 conn.connect()
669 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
670
671 # But if close the connection, we are good.
672 conn.close()
673 conn.set_tunnel('destination.com')
674 conn.request('HEAD', '/', '')
675
676 self.assertEqual(conn.sock.host, 'proxy.com')
677 self.assertEqual(conn.sock.port, 80)
678 self.assertTrue('CONNECT destination.com' in conn.sock.data)
679 self.assertTrue('Host: destination.com' in conn.sock.data)
680
681 self.assertTrue('Host: proxy.com' not in conn.sock.data)
682
683 conn.close()
684
685 conn.request('PUT', '/', '')
686 self.assertEqual(conn.sock.host, 'proxy.com')
687 self.assertEqual(conn.sock.port, 80)
688 self.assertTrue('CONNECT destination.com' in conn.sock.data)
689 self.assertTrue('Host: destination.com' in conn.sock.data)
690
691
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600692@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000693def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000694 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600695 HTTPSTest, SourceAddressTest, TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000696
Georg Brandl71a20892006-10-29 20:24:01 +0000697if __name__ == '__main__':
698 test_main()