blob: 60165c102977707c7963bed4a4828a58c468ab05 [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 httplib
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -06004import os
Jeremy Hylton79fa2b62001-04-13 14:57:44 +00005import StringIO
Facundo Batista07c78be2007-03-23 18:54:07 +00006import socket
Victor Stinner2c6aee92010-07-24 02:46:16 +00007import errno
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 = ''
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()
Jeremy Hylton121d34a2003-07-08 12:36:58 +000038 return self.fileclass(self.text)
39
Senthil Kumaran36f28f72014-05-16 18:51:46 -070040 def close(self):
41 pass
42
Victor Stinner2c6aee92010-07-24 02:46:16 +000043class EPipeSocket(FakeSocket):
44
45 def __init__(self, text, pipe_trigger):
46 # When sendall() is called with pipe_trigger, raise EPIPE.
47 FakeSocket.__init__(self, text)
48 self.pipe_trigger = pipe_trigger
49
50 def sendall(self, data):
51 if self.pipe_trigger in data:
52 raise socket.error(errno.EPIPE, "gotcha")
53 self.data += data
54
55 def close(self):
56 pass
57
Jeremy Hylton121d34a2003-07-08 12:36:58 +000058class NoEOFStringIO(StringIO.StringIO):
59 """Like StringIO, but raises AssertionError on EOF.
60
61 This is used below to test that httplib doesn't try to read
62 more from the underlying file than it should.
63 """
64 def read(self, n=-1):
65 data = StringIO.StringIO.read(self, n)
66 if data == '':
67 raise AssertionError('caller tried to read past EOF')
68 return data
69
70 def readline(self, length=None):
71 data = StringIO.StringIO.readline(self, length)
72 if data == '':
73 raise AssertionError('caller tried to read past EOF')
74 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000075
Jeremy Hylton2c178252004-08-07 16:28:14 +000076
77class HeaderTests(TestCase):
78 def test_auto_headers(self):
79 # Some headers are added automatically, but should not be added by
80 # .request() if they are explicitly set.
81
Jeremy Hylton2c178252004-08-07 16:28:14 +000082 class HeaderCountingBuffer(list):
83 def __init__(self):
84 self.count = {}
85 def append(self, item):
86 kv = item.split(':')
87 if len(kv) > 1:
88 # item is a 'Key: Value' header string
89 lcKey = kv[0].lower()
90 self.count.setdefault(lcKey, 0)
91 self.count[lcKey] += 1
92 list.append(self, item)
93
94 for explicit_header in True, False:
95 for header in 'Content-length', 'Host', 'Accept-encoding':
96 conn = httplib.HTTPConnection('example.com')
97 conn.sock = FakeSocket('blahblahblah')
98 conn._buffer = HeaderCountingBuffer()
99
100 body = 'spamspamspam'
101 headers = {}
102 if explicit_header:
103 headers[header] = str(len(body))
104 conn.request('POST', '/', body, headers)
105 self.assertEqual(conn._buffer.count[header.lower()], 1)
106
Senthil Kumaran618802d2012-05-19 16:52:21 +0800107 def test_content_length_0(self):
108
109 class ContentLengthChecker(list):
110 def __init__(self):
111 list.__init__(self)
112 self.content_length = None
113 def append(self, item):
114 kv = item.split(':', 1)
115 if len(kv) > 1 and kv[0].lower() == 'content-length':
116 self.content_length = kv[1].strip()
117 list.append(self, item)
118
119 # POST with empty body
120 conn = httplib.HTTPConnection('example.com')
121 conn.sock = FakeSocket(None)
122 conn._buffer = ContentLengthChecker()
123 conn.request('POST', '/', '')
124 self.assertEqual(conn._buffer.content_length, '0',
125 'Header Content-Length not set')
126
127 # PUT request with empty body
128 conn = httplib.HTTPConnection('example.com')
129 conn.sock = FakeSocket(None)
130 conn._buffer = ContentLengthChecker()
131 conn.request('PUT', '/', '')
132 self.assertEqual(conn._buffer.content_length, '0',
133 'Header Content-Length not set')
134
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000135 def test_putheader(self):
136 conn = httplib.HTTPConnection('example.com')
137 conn.sock = FakeSocket(None)
138 conn.putrequest('GET','/')
139 conn.putheader('Content-length',42)
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200140 self.assertIn('Content-length: 42', conn._buffer)
Senthil Kumaranaa5f49e2010-10-03 18:26:07 +0000141
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000142 def test_ipv6host_header(self):
143 # Default host header on IPv6 transaction should wrapped by [] if
144 # its actual IPv6 address
145 expected = 'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
146 'Accept-Encoding: identity\r\n\r\n'
147 conn = httplib.HTTPConnection('[2001::]:81')
148 sock = FakeSocket('')
149 conn.sock = sock
150 conn.request('GET', '/foo')
151 self.assertTrue(sock.data.startswith(expected))
152
153 expected = 'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
154 'Accept-Encoding: identity\r\n\r\n'
155 conn = httplib.HTTPConnection('[2001:102A::]')
156 sock = FakeSocket('')
157 conn.sock = sock
158 conn.request('GET', '/foo')
159 self.assertTrue(sock.data.startswith(expected))
160
161
Georg Brandl71a20892006-10-29 20:24:01 +0000162class BasicTest(TestCase):
163 def test_status_lines(self):
164 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000165
Georg Brandl71a20892006-10-29 20:24:01 +0000166 body = "HTTP/1.1 200 Ok\r\n\r\nText"
167 sock = FakeSocket(body)
168 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000169 resp.begin()
Serhiy Storchakac97f5ed2013-12-17 21:49:48 +0200170 self.assertEqual(resp.read(0), '') # Issue #20007
171 self.assertFalse(resp.isclosed())
Georg Brandl71a20892006-10-29 20:24:01 +0000172 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000173 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000174
Georg Brandl71a20892006-10-29 20:24:01 +0000175 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
176 sock = FakeSocket(body)
177 resp = httplib.HTTPResponse(sock)
178 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000179
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000180 def test_bad_status_repr(self):
181 exc = httplib.BadStatusLine('')
Ezio Melotti2623a372010-11-21 13:34:58 +0000182 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000183
Facundo Batista70665902007-10-18 03:16:03 +0000184 def test_partial_reads(self):
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100185 # if we have a length, the system knows when to close itself
Facundo Batista70665902007-10-18 03:16:03 +0000186 # same behaviour than when we read the whole thing with read()
187 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
188 sock = FakeSocket(body)
189 resp = httplib.HTTPResponse(sock)
190 resp.begin()
191 self.assertEqual(resp.read(2), 'Te')
192 self.assertFalse(resp.isclosed())
193 self.assertEqual(resp.read(2), 'xt')
194 self.assertTrue(resp.isclosed())
195
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100196 def test_partial_reads_no_content_length(self):
197 # when no length is present, the socket should be gracefully closed when
198 # all data was read
199 body = "HTTP/1.1 200 Ok\r\n\r\nText"
200 sock = FakeSocket(body)
201 resp = httplib.HTTPResponse(sock)
202 resp.begin()
203 self.assertEqual(resp.read(2), 'Te')
204 self.assertFalse(resp.isclosed())
205 self.assertEqual(resp.read(2), 'xt')
206 self.assertEqual(resp.read(1), '')
207 self.assertTrue(resp.isclosed())
208
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100209 def test_partial_reads_incomplete_body(self):
210 # if the server shuts down the connection before the whole
211 # content-length is delivered, the socket is gracefully closed
212 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
213 sock = FakeSocket(body)
214 resp = httplib.HTTPResponse(sock)
215 resp.begin()
216 self.assertEqual(resp.read(2), 'Te')
217 self.assertFalse(resp.isclosed())
218 self.assertEqual(resp.read(2), 'xt')
219 self.assertEqual(resp.read(1), '')
220 self.assertTrue(resp.isclosed())
221
Georg Brandl71a20892006-10-29 20:24:01 +0000222 def test_host_port(self):
223 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000224
Łukasz Langa7a153902011-10-18 17:16:00 +0200225 # Note that httplib does not accept user:password@ in the host-port.
226 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Georg Brandl71a20892006-10-29 20:24:01 +0000227 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
228
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000229 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
230 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000231 ("www.python.org:80", "www.python.org", 80),
232 ("www.python.org", "www.python.org", 80),
Łukasz Langa7a153902011-10-18 17:16:00 +0200233 ("www.python.org:", "www.python.org", 80),
Georg Brandl71a20892006-10-29 20:24:01 +0000234 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000235 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000236 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000237 if h != c.host:
238 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
239 if p != c.port:
240 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000241
Georg Brandl71a20892006-10-29 20:24:01 +0000242 def test_response_headers(self):
243 # test response with multiple message headers with the same field name.
244 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000245 'Set-Cookie: Customer="WILE_E_COYOTE";'
246 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000247 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
248 ' Path="/acme"\r\n'
249 '\r\n'
250 'No body\r\n')
251 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
252 ', '
253 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
254 s = FakeSocket(text)
255 r = httplib.HTTPResponse(s)
256 r.begin()
257 cookies = r.getheader("Set-Cookie")
258 if cookies != hdr:
259 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000260
Georg Brandl71a20892006-10-29 20:24:01 +0000261 def test_read_head(self):
262 # Test that the library doesn't attempt to read any data
263 # from a HEAD request. (Tickles SF bug #622042.)
264 sock = FakeSocket(
265 'HTTP/1.1 200 OK\r\n'
266 'Content-Length: 14432\r\n'
267 '\r\n',
268 NoEOFStringIO)
269 resp = httplib.HTTPResponse(sock, method="HEAD")
270 resp.begin()
271 if resp.read() != "":
272 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000273
Berker Peksagb7414e02014-08-05 07:15:57 +0300274 def test_too_many_headers(self):
275 headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
276 text = ('HTTP/1.1 200 OK\r\n' + headers)
277 s = FakeSocket(text)
278 r = httplib.HTTPResponse(s)
279 self.assertRaises(httplib.HTTPException, r.begin)
280
Martin v. Löwis040a9272006-11-12 10:32:47 +0000281 def test_send_file(self):
282 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
283 'Accept-Encoding: identity\r\nContent-Length:'
284
285 body = open(__file__, 'rb')
286 conn = httplib.HTTPConnection('example.com')
287 sock = FakeSocket(body)
288 conn.sock = sock
289 conn.request('GET', '/foo', body)
290 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000291
Antoine Pitrou72481782009-09-29 17:48:18 +0000292 def test_send(self):
293 expected = 'this is a test this is only a test'
294 conn = httplib.HTTPConnection('example.com')
295 sock = FakeSocket(None)
296 conn.sock = sock
297 conn.send(expected)
Ezio Melotti2623a372010-11-21 13:34:58 +0000298 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000299 sock.data = ''
300 conn.send(array.array('c', expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000301 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000302 sock.data = ''
303 conn.send(StringIO.StringIO(expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000304 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000305
Georg Brandl23635032008-02-24 00:03:22 +0000306 def test_chunked(self):
307 chunked_start = (
308 'HTTP/1.1 200 OK\r\n'
309 'Transfer-Encoding: chunked\r\n\r\n'
310 'a\r\n'
311 'hello worl\r\n'
312 '1\r\n'
313 'd\r\n'
314 )
315 sock = FakeSocket(chunked_start + '0\r\n')
316 resp = httplib.HTTPResponse(sock, method="GET")
317 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000318 self.assertEqual(resp.read(), 'hello world')
Georg Brandl23635032008-02-24 00:03:22 +0000319 resp.close()
320
321 for x in ('', 'foo\r\n'):
322 sock = FakeSocket(chunked_start + x)
323 resp = httplib.HTTPResponse(sock, method="GET")
324 resp.begin()
325 try:
326 resp.read()
327 except httplib.IncompleteRead, i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000328 self.assertEqual(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000329 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
330 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000331 else:
332 self.fail('IncompleteRead expected')
333 finally:
334 resp.close()
335
Senthil Kumaraned9204342010-04-28 17:20:43 +0000336 def test_chunked_head(self):
337 chunked_start = (
338 'HTTP/1.1 200 OK\r\n'
339 'Transfer-Encoding: chunked\r\n\r\n'
340 'a\r\n'
341 'hello world\r\n'
342 '1\r\n'
343 'd\r\n'
344 )
345 sock = FakeSocket(chunked_start + '0\r\n')
346 resp = httplib.HTTPResponse(sock, method="HEAD")
347 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000348 self.assertEqual(resp.read(), '')
349 self.assertEqual(resp.status, 200)
350 self.assertEqual(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000351 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000352
Georg Brandl8c460d52008-02-24 00:14:24 +0000353 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000354 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
355 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000356 resp = httplib.HTTPResponse(sock, method="GET")
357 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000358 self.assertEqual(resp.read(), 'Hello\r\n')
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100359 self.assertTrue(resp.isclosed())
Georg Brandl8c460d52008-02-24 00:14:24 +0000360
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000361 def test_incomplete_read(self):
362 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
363 resp = httplib.HTTPResponse(sock, method="GET")
364 resp.begin()
365 try:
366 resp.read()
367 except httplib.IncompleteRead as i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000368 self.assertEqual(i.partial, 'Hello\r\n')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000369 self.assertEqual(repr(i),
370 "IncompleteRead(7 bytes read, 3 more expected)")
371 self.assertEqual(str(i),
372 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100373 self.assertTrue(resp.isclosed())
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000374 else:
375 self.fail('IncompleteRead expected')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000376
Victor Stinner2c6aee92010-07-24 02:46:16 +0000377 def test_epipe(self):
378 sock = EPipeSocket(
379 "HTTP/1.0 401 Authorization Required\r\n"
380 "Content-type: text/html\r\n"
381 "WWW-Authenticate: Basic realm=\"example\"\r\n",
382 b"Content-Length")
383 conn = httplib.HTTPConnection("example.com")
384 conn.sock = sock
385 self.assertRaises(socket.error,
386 lambda: conn.request("PUT", "/url", "body"))
387 resp = conn.getresponse()
388 self.assertEqual(401, resp.status)
389 self.assertEqual("Basic realm=\"example\"",
390 resp.getheader("www-authenticate"))
391
Senthil Kumarand389cb52010-09-21 01:38:15 +0000392 def test_filenoattr(self):
393 # Just test the fileno attribute in the HTTPResponse Object.
394 body = "HTTP/1.1 200 Ok\r\n\r\nText"
395 sock = FakeSocket(body)
396 resp = httplib.HTTPResponse(sock)
397 self.assertTrue(hasattr(resp,'fileno'),
398 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000399
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000400 # Test lines overflowing the max line size (_MAXLINE in http.client)
401
402 def test_overflowing_status_line(self):
403 self.skipTest("disabled for HTTP 0.9 support")
404 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
405 resp = httplib.HTTPResponse(FakeSocket(body))
406 self.assertRaises((httplib.LineTooLong, httplib.BadStatusLine), resp.begin)
407
408 def test_overflowing_header_line(self):
409 body = (
410 'HTTP/1.1 200 OK\r\n'
411 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
412 )
413 resp = httplib.HTTPResponse(FakeSocket(body))
414 self.assertRaises(httplib.LineTooLong, resp.begin)
415
416 def test_overflowing_chunked_line(self):
417 body = (
418 'HTTP/1.1 200 OK\r\n'
419 'Transfer-Encoding: chunked\r\n\r\n'
420 + '0' * 65536 + 'a\r\n'
421 'hello world\r\n'
422 '0\r\n'
423 )
424 resp = httplib.HTTPResponse(FakeSocket(body))
425 resp.begin()
426 self.assertRaises(httplib.LineTooLong, resp.read)
427
Senthil Kumaranf5aaf6f2012-04-29 10:15:31 +0800428 def test_early_eof(self):
429 # Test httpresponse with no \r\n termination,
430 body = "HTTP/1.1 200 Ok"
431 sock = FakeSocket(body)
432 resp = httplib.HTTPResponse(sock)
433 resp.begin()
434 self.assertEqual(resp.read(), '')
435 self.assertTrue(resp.isclosed())
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000436
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000437class OfflineTest(TestCase):
438 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000439 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000440
Gregory P. Smith9d325212010-01-03 02:06:07 +0000441
442class SourceAddressTest(TestCase):
443 def setUp(self):
444 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
445 self.port = test_support.bind_port(self.serv)
446 self.source_port = test_support.find_unused_port()
447 self.serv.listen(5)
448 self.conn = None
449
450 def tearDown(self):
451 if self.conn:
452 self.conn.close()
453 self.conn = None
454 self.serv.close()
455 self.serv = None
456
457 def testHTTPConnectionSourceAddress(self):
458 self.conn = httplib.HTTPConnection(HOST, self.port,
459 source_address=('', self.source_port))
460 self.conn.connect()
461 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
462
463 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
464 'httplib.HTTPSConnection not defined')
465 def testHTTPSConnectionSourceAddress(self):
466 self.conn = httplib.HTTPSConnection(HOST, self.port,
467 source_address=('', self.source_port))
468 # We don't test anything here other the constructor not barfing as
469 # this code doesn't deal with setting up an active running SSL server
470 # for an ssl_wrapped connect() to actually return from.
471
472
Facundo Batista07c78be2007-03-23 18:54:07 +0000473class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000474 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000475
Facundo Batista07c78be2007-03-23 18:54:07 +0000476 def setUp(self):
477 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000478 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000479 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000480
481 def tearDown(self):
482 self.serv.close()
483 self.serv = None
484
485 def testTimeoutAttribute(self):
486 '''This will prove that the timeout gets through
487 HTTPConnection and into the socket.
488 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000489 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200490 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000491 socket.setdefaulttimeout(30)
492 try:
493 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
494 httpConn.connect()
495 finally:
496 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000497 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000498 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000499
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000500 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200501 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000502 socket.setdefaulttimeout(30)
503 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000504 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
505 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000506 httpConn.connect()
507 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000508 socket.setdefaulttimeout(None)
509 self.assertEqual(httpConn.sock.gettimeout(), None)
510 httpConn.close()
511
512 # a value
513 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
514 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000515 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000516 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000517
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600518class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000519
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600520 def setUp(self):
521 if not hasattr(httplib, 'HTTPSConnection'):
522 self.skipTest('ssl support required')
523
524 def make_server(self, certfile):
525 from test.ssl_servers import make_https_server
526 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000527
528 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600529 # simple test to check it's storing the timeout
530 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
531 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000532
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600533 def test_networked(self):
534 # Default settings: requires a valid cert from a trusted CA
535 import ssl
536 test_support.requires('network')
537 with test_support.transient_internet('self-signed.pythontest.net'):
538 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
539 with self.assertRaises(ssl.SSLError) as exc_info:
540 h.request('GET', '/')
541 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
542
543 def test_networked_noverification(self):
544 # Switch off cert verification
545 import ssl
546 test_support.requires('network')
547 with test_support.transient_internet('self-signed.pythontest.net'):
548 context = ssl._create_stdlib_context()
549 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
550 context=context)
551 h.request('GET', '/')
552 resp = h.getresponse()
553 self.assertIn('nginx', resp.getheader('server'))
554
555 def test_networked_trusted_by_default_cert(self):
556 # Default settings: requires a valid cert from a trusted CA
557 test_support.requires('network')
558 with test_support.transient_internet('www.python.org'):
559 h = httplib.HTTPSConnection('www.python.org', 443)
560 h.request('GET', '/')
561 resp = h.getresponse()
562 content_type = resp.getheader('content-type')
563 self.assertIn('text/html', content_type)
564
565 def test_networked_good_cert(self):
566 # We feed the server's cert as a validating cert
567 import ssl
568 test_support.requires('network')
569 with test_support.transient_internet('self-signed.pythontest.net'):
570 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
571 context.verify_mode = ssl.CERT_REQUIRED
572 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
573 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
574 h.request('GET', '/')
575 resp = h.getresponse()
576 server_string = resp.getheader('server')
577 self.assertIn('nginx', server_string)
578
579 def test_networked_bad_cert(self):
580 # We feed a "CA" cert that is unrelated to the server's cert
581 import ssl
582 test_support.requires('network')
583 with test_support.transient_internet('self-signed.pythontest.net'):
584 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
585 context.verify_mode = ssl.CERT_REQUIRED
586 context.load_verify_locations(CERT_localhost)
587 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
588 with self.assertRaises(ssl.SSLError) as exc_info:
589 h.request('GET', '/')
590 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
591
592 def test_local_unknown_cert(self):
593 # The custom cert isn't known to the default trust bundle
594 import ssl
595 server = self.make_server(CERT_localhost)
596 h = httplib.HTTPSConnection('localhost', server.port)
597 with self.assertRaises(ssl.SSLError) as exc_info:
598 h.request('GET', '/')
599 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
600
601 def test_local_good_hostname(self):
602 # The (valid) cert validates the HTTP hostname
603 import ssl
604 server = self.make_server(CERT_localhost)
605 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
606 context.verify_mode = ssl.CERT_REQUIRED
607 context.load_verify_locations(CERT_localhost)
608 h = httplib.HTTPSConnection('localhost', server.port, context=context)
609 h.request('GET', '/nonexistent')
610 resp = h.getresponse()
611 self.assertEqual(resp.status, 404)
612
613 def test_local_bad_hostname(self):
614 # The (valid) cert doesn't validate the HTTP hostname
615 import ssl
616 server = self.make_server(CERT_fakehostname)
617 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
618 context.verify_mode = ssl.CERT_REQUIRED
619 context.load_verify_locations(CERT_fakehostname)
620 h = httplib.HTTPSConnection('localhost', server.port, context=context)
621 with self.assertRaises(ssl.CertificateError):
622 h.request('GET', '/')
623 # Same with explicit check_hostname=True
624 h = httplib.HTTPSConnection('localhost', server.port, context=context,
625 check_hostname=True)
626 with self.assertRaises(ssl.CertificateError):
627 h.request('GET', '/')
628 # With check_hostname=False, the mismatching is ignored
629 h = httplib.HTTPSConnection('localhost', server.port, context=context,
630 check_hostname=False)
631 h.request('GET', '/nonexistent')
632 resp = h.getresponse()
633 self.assertEqual(resp.status, 404)
634
Łukasz Langa7a153902011-10-18 17:16:00 +0200635 def test_host_port(self):
636 # Check invalid host_port
637
Łukasz Langa7a153902011-10-18 17:16:00 +0200638 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600639 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200640
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600641 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
642 "fe80::207:e9ff:fe9b", 8000),
643 ("www.python.org:443", "www.python.org", 443),
644 ("www.python.org:", "www.python.org", 443),
645 ("www.python.org", "www.python.org", 443),
646 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
647 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
648 443)):
649 c = httplib.HTTPSConnection(hp)
650 self.assertEqual(h, c.host)
651 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200652
653
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700654class TunnelTests(TestCase):
655 def test_connect(self):
656 response_text = (
657 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
658 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
659 'Content-Length: 42\r\n\r\n'
660 )
661
662 def create_connection(address, timeout=None, source_address=None):
663 return FakeSocket(response_text, host=address[0], port=address[1])
664
665 conn = httplib.HTTPConnection('proxy.com')
666 conn._create_connection = create_connection
667
668 # Once connected, we should not be able to tunnel anymore
669 conn.connect()
670 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
671
672 # But if close the connection, we are good.
673 conn.close()
674 conn.set_tunnel('destination.com')
675 conn.request('HEAD', '/', '')
676
677 self.assertEqual(conn.sock.host, 'proxy.com')
678 self.assertEqual(conn.sock.port, 80)
679 self.assertTrue('CONNECT destination.com' in conn.sock.data)
680 self.assertTrue('Host: destination.com' in conn.sock.data)
681
682 self.assertTrue('Host: proxy.com' not in conn.sock.data)
683
684 conn.close()
685
686 conn.request('PUT', '/', '')
687 self.assertEqual(conn.sock.host, 'proxy.com')
688 self.assertEqual(conn.sock.port, 80)
689 self.assertTrue('CONNECT destination.com' in conn.sock.data)
690 self.assertTrue('Host: destination.com' in conn.sock.data)
691
692
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600693@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000694def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000695 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600696 HTTPSTest, SourceAddressTest, TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000697
Georg Brandl71a20892006-10-29 20:24:01 +0000698if __name__ == '__main__':
699 test_main()