blob: 29614e39dbf40971d612406b887aa59b618da8ca [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
Serhiy Storchaka59bdf632015-03-12 11:12:51 +0200148 conn.putheader('Foo', ' bar ')
149 self.assertIn(b'Foo: bar ', conn._buffer)
150 conn.putheader('Bar', '\tbaz\t')
151 self.assertIn(b'Bar: \tbaz\t', conn._buffer)
152 conn.putheader('Authorization', 'Bearer mytoken')
153 self.assertIn(b'Authorization: Bearer mytoken', conn._buffer)
154 conn.putheader('IterHeader', 'IterA', 'IterB')
155 self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer)
156 conn.putheader('LatinHeader', b'\xFF')
157 self.assertIn(b'LatinHeader: \xFF', conn._buffer)
158 conn.putheader('Utf8Header', b'\xc3\x80')
159 self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer)
160 conn.putheader('C1-Control', b'next\x85line')
161 self.assertIn(b'C1-Control: next\x85line', conn._buffer)
162 conn.putheader('Embedded-Fold-Space', 'is\r\n allowed')
163 self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer)
164 conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed')
165 self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer)
166 conn.putheader('Key Space', 'value')
167 self.assertIn(b'Key Space: value', conn._buffer)
168 conn.putheader('KeySpace ', 'value')
169 self.assertIn(b'KeySpace : value', conn._buffer)
170 conn.putheader(b'Nonbreak\xa0Space', 'value')
171 self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer)
172 conn.putheader(b'\xa0NonbreakSpace', 'value')
173 self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer)
174
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000175 def test_ipv6host_header(self):
176 # Default host header on IPv6 transaction should wrapped by [] if
177 # its actual IPv6 address
178 expected = 'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
179 'Accept-Encoding: identity\r\n\r\n'
180 conn = httplib.HTTPConnection('[2001::]:81')
181 sock = FakeSocket('')
182 conn.sock = sock
183 conn.request('GET', '/foo')
184 self.assertTrue(sock.data.startswith(expected))
185
186 expected = 'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
187 'Accept-Encoding: identity\r\n\r\n'
188 conn = httplib.HTTPConnection('[2001:102A::]')
189 sock = FakeSocket('')
190 conn.sock = sock
191 conn.request('GET', '/foo')
192 self.assertTrue(sock.data.startswith(expected))
193
Benjamin Petersonbfd976f2015-01-25 23:34:42 -0500194 def test_malformed_headers_coped_with(self):
195 # Issue 19996
196 body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n"
197 sock = FakeSocket(body)
198 resp = httplib.HTTPResponse(sock)
199 resp.begin()
200
201 self.assertEqual(resp.getheader('First'), 'val')
202 self.assertEqual(resp.getheader('Second'), 'val')
203
Serhiy Storchaka59bdf632015-03-12 11:12:51 +0200204 def test_invalid_headers(self):
205 conn = httplib.HTTPConnection('example.com')
206 conn.sock = FakeSocket('')
207 conn.putrequest('GET', '/')
208
209 # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no
210 # longer allowed in header names
211 cases = (
212 (b'Invalid\r\nName', b'ValidValue'),
213 (b'Invalid\rName', b'ValidValue'),
214 (b'Invalid\nName', b'ValidValue'),
215 (b'\r\nInvalidName', b'ValidValue'),
216 (b'\rInvalidName', b'ValidValue'),
217 (b'\nInvalidName', b'ValidValue'),
218 (b' InvalidName', b'ValidValue'),
219 (b'\tInvalidName', b'ValidValue'),
220 (b'Invalid:Name', b'ValidValue'),
221 (b':InvalidName', b'ValidValue'),
222 (b'ValidName', b'Invalid\r\nValue'),
223 (b'ValidName', b'Invalid\rValue'),
224 (b'ValidName', b'Invalid\nValue'),
225 (b'ValidName', b'InvalidValue\r\n'),
226 (b'ValidName', b'InvalidValue\r'),
227 (b'ValidName', b'InvalidValue\n'),
228 )
229 for name, value in cases:
230 with self.assertRaisesRegexp(ValueError, 'Invalid header'):
231 conn.putheader(name, value)
232
Senthil Kumaran501bfd82010-11-14 03:31:52 +0000233
Georg Brandl71a20892006-10-29 20:24:01 +0000234class BasicTest(TestCase):
235 def test_status_lines(self):
236 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000237
Georg Brandl71a20892006-10-29 20:24:01 +0000238 body = "HTTP/1.1 200 Ok\r\n\r\nText"
239 sock = FakeSocket(body)
240 resp = httplib.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000241 resp.begin()
Serhiy Storchakac97f5ed2013-12-17 21:49:48 +0200242 self.assertEqual(resp.read(0), '') # Issue #20007
243 self.assertFalse(resp.isclosed())
Georg Brandl71a20892006-10-29 20:24:01 +0000244 self.assertEqual(resp.read(), 'Text')
Facundo Batista70665902007-10-18 03:16:03 +0000245 self.assertTrue(resp.isclosed())
Jeremy Hyltonba603192003-01-23 18:02:20 +0000246
Georg Brandl71a20892006-10-29 20:24:01 +0000247 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
248 sock = FakeSocket(body)
249 resp = httplib.HTTPResponse(sock)
250 self.assertRaises(httplib.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000251
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000252 def test_bad_status_repr(self):
253 exc = httplib.BadStatusLine('')
Ezio Melotti2623a372010-11-21 13:34:58 +0000254 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Dirkjan Ochtmanebc73dc2010-02-24 04:49:00 +0000255
Facundo Batista70665902007-10-18 03:16:03 +0000256 def test_partial_reads(self):
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100257 # if we have a length, the system knows when to close itself
Facundo Batista70665902007-10-18 03:16:03 +0000258 # same behaviour than when we read the whole thing with read()
259 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
260 sock = FakeSocket(body)
261 resp = httplib.HTTPResponse(sock)
262 resp.begin()
263 self.assertEqual(resp.read(2), 'Te')
264 self.assertFalse(resp.isclosed())
265 self.assertEqual(resp.read(2), 'xt')
266 self.assertTrue(resp.isclosed())
267
Antoine Pitrou4113d2b2012-12-15 19:11:54 +0100268 def test_partial_reads_no_content_length(self):
269 # when no length is present, the socket should be gracefully closed when
270 # all data was read
271 body = "HTTP/1.1 200 Ok\r\n\r\nText"
272 sock = FakeSocket(body)
273 resp = httplib.HTTPResponse(sock)
274 resp.begin()
275 self.assertEqual(resp.read(2), 'Te')
276 self.assertFalse(resp.isclosed())
277 self.assertEqual(resp.read(2), 'xt')
278 self.assertEqual(resp.read(1), '')
279 self.assertTrue(resp.isclosed())
280
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100281 def test_partial_reads_incomplete_body(self):
282 # if the server shuts down the connection before the whole
283 # content-length is delivered, the socket is gracefully closed
284 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
285 sock = FakeSocket(body)
286 resp = httplib.HTTPResponse(sock)
287 resp.begin()
288 self.assertEqual(resp.read(2), 'Te')
289 self.assertFalse(resp.isclosed())
290 self.assertEqual(resp.read(2), 'xt')
291 self.assertEqual(resp.read(1), '')
292 self.assertTrue(resp.isclosed())
293
Georg Brandl71a20892006-10-29 20:24:01 +0000294 def test_host_port(self):
295 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000296
Łukasz Langa7a153902011-10-18 17:16:00 +0200297 # Note that httplib does not accept user:password@ in the host-port.
298 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Georg Brandl71a20892006-10-29 20:24:01 +0000299 self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
300
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000301 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
302 8000),
Georg Brandl71a20892006-10-29 20:24:01 +0000303 ("www.python.org:80", "www.python.org", 80),
304 ("www.python.org", "www.python.org", 80),
Łukasz Langa7a153902011-10-18 17:16:00 +0200305 ("www.python.org:", "www.python.org", 80),
Georg Brandl71a20892006-10-29 20:24:01 +0000306 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80)):
Martin v. Löwis74a249e2004-09-14 21:45:36 +0000307 http = httplib.HTTP(hp)
Georg Brandl71a20892006-10-29 20:24:01 +0000308 c = http._conn
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000309 if h != c.host:
310 self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
311 if p != c.port:
312 self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000313
Georg Brandl71a20892006-10-29 20:24:01 +0000314 def test_response_headers(self):
315 # test response with multiple message headers with the same field name.
316 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000317 'Set-Cookie: Customer="WILE_E_COYOTE";'
318 ' Version="1"; Path="/acme"\r\n'
Georg Brandl71a20892006-10-29 20:24:01 +0000319 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
320 ' Path="/acme"\r\n'
321 '\r\n'
322 'No body\r\n')
323 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
324 ', '
325 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
326 s = FakeSocket(text)
327 r = httplib.HTTPResponse(s)
328 r.begin()
329 cookies = r.getheader("Set-Cookie")
330 if cookies != hdr:
331 self.fail("multiple headers not combined properly")
Jeremy Hyltonba603192003-01-23 18:02:20 +0000332
Georg Brandl71a20892006-10-29 20:24:01 +0000333 def test_read_head(self):
334 # Test that the library doesn't attempt to read any data
335 # from a HEAD request. (Tickles SF bug #622042.)
336 sock = FakeSocket(
337 'HTTP/1.1 200 OK\r\n'
338 'Content-Length: 14432\r\n'
339 '\r\n',
340 NoEOFStringIO)
341 resp = httplib.HTTPResponse(sock, method="HEAD")
342 resp.begin()
343 if resp.read() != "":
344 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000345
Berker Peksagb7414e02014-08-05 07:15:57 +0300346 def test_too_many_headers(self):
347 headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
348 text = ('HTTP/1.1 200 OK\r\n' + headers)
349 s = FakeSocket(text)
350 r = httplib.HTTPResponse(s)
351 self.assertRaises(httplib.HTTPException, r.begin)
352
Martin v. Löwis040a9272006-11-12 10:32:47 +0000353 def test_send_file(self):
354 expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
355 'Accept-Encoding: identity\r\nContent-Length:'
356
357 body = open(__file__, 'rb')
358 conn = httplib.HTTPConnection('example.com')
359 sock = FakeSocket(body)
360 conn.sock = sock
361 conn.request('GET', '/foo', body)
362 self.assertTrue(sock.data.startswith(expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000363
Antoine Pitrou72481782009-09-29 17:48:18 +0000364 def test_send(self):
365 expected = 'this is a test this is only a test'
366 conn = httplib.HTTPConnection('example.com')
367 sock = FakeSocket(None)
368 conn.sock = sock
369 conn.send(expected)
Ezio Melotti2623a372010-11-21 13:34:58 +0000370 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000371 sock.data = ''
372 conn.send(array.array('c', expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000373 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000374 sock.data = ''
375 conn.send(StringIO.StringIO(expected))
Ezio Melotti2623a372010-11-21 13:34:58 +0000376 self.assertEqual(expected, sock.data)
Antoine Pitrou72481782009-09-29 17:48:18 +0000377
Georg Brandl23635032008-02-24 00:03:22 +0000378 def test_chunked(self):
379 chunked_start = (
380 'HTTP/1.1 200 OK\r\n'
381 'Transfer-Encoding: chunked\r\n\r\n'
382 'a\r\n'
383 'hello worl\r\n'
384 '1\r\n'
385 'd\r\n'
386 )
387 sock = FakeSocket(chunked_start + '0\r\n')
388 resp = httplib.HTTPResponse(sock, method="GET")
389 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000390 self.assertEqual(resp.read(), 'hello world')
Georg Brandl23635032008-02-24 00:03:22 +0000391 resp.close()
392
393 for x in ('', 'foo\r\n'):
394 sock = FakeSocket(chunked_start + x)
395 resp = httplib.HTTPResponse(sock, method="GET")
396 resp.begin()
397 try:
398 resp.read()
399 except httplib.IncompleteRead, i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000400 self.assertEqual(i.partial, 'hello world')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000401 self.assertEqual(repr(i),'IncompleteRead(11 bytes read)')
402 self.assertEqual(str(i),'IncompleteRead(11 bytes read)')
Georg Brandl23635032008-02-24 00:03:22 +0000403 else:
404 self.fail('IncompleteRead expected')
405 finally:
406 resp.close()
407
Senthil Kumaraned9204342010-04-28 17:20:43 +0000408 def test_chunked_head(self):
409 chunked_start = (
410 'HTTP/1.1 200 OK\r\n'
411 'Transfer-Encoding: chunked\r\n\r\n'
412 'a\r\n'
413 'hello world\r\n'
414 '1\r\n'
415 'd\r\n'
416 )
417 sock = FakeSocket(chunked_start + '0\r\n')
418 resp = httplib.HTTPResponse(sock, method="HEAD")
419 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000420 self.assertEqual(resp.read(), '')
421 self.assertEqual(resp.status, 200)
422 self.assertEqual(resp.reason, 'OK')
Senthil Kumaranfb695012010-06-04 17:17:09 +0000423 self.assertTrue(resp.isclosed())
Senthil Kumaraned9204342010-04-28 17:20:43 +0000424
Georg Brandl8c460d52008-02-24 00:14:24 +0000425 def test_negative_content_length(self):
Jeremy Hylton21d2e592008-11-29 00:09:16 +0000426 sock = FakeSocket('HTTP/1.1 200 OK\r\n'
427 'Content-Length: -1\r\n\r\nHello\r\n')
Georg Brandl8c460d52008-02-24 00:14:24 +0000428 resp = httplib.HTTPResponse(sock, method="GET")
429 resp.begin()
Ezio Melotti2623a372010-11-21 13:34:58 +0000430 self.assertEqual(resp.read(), 'Hello\r\n')
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100431 self.assertTrue(resp.isclosed())
Georg Brandl8c460d52008-02-24 00:14:24 +0000432
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000433 def test_incomplete_read(self):
434 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
435 resp = httplib.HTTPResponse(sock, method="GET")
436 resp.begin()
437 try:
438 resp.read()
439 except httplib.IncompleteRead as i:
Ezio Melotti2623a372010-11-21 13:34:58 +0000440 self.assertEqual(i.partial, 'Hello\r\n')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000441 self.assertEqual(repr(i),
442 "IncompleteRead(7 bytes read, 3 more expected)")
443 self.assertEqual(str(i),
444 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroud66c0ee2013-02-02 22:49:34 +0100445 self.assertTrue(resp.isclosed())
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000446 else:
447 self.fail('IncompleteRead expected')
Benjamin Peterson7d49bba2009-03-02 22:41:42 +0000448
Victor Stinner2c6aee92010-07-24 02:46:16 +0000449 def test_epipe(self):
450 sock = EPipeSocket(
451 "HTTP/1.0 401 Authorization Required\r\n"
452 "Content-type: text/html\r\n"
453 "WWW-Authenticate: Basic realm=\"example\"\r\n",
454 b"Content-Length")
455 conn = httplib.HTTPConnection("example.com")
456 conn.sock = sock
457 self.assertRaises(socket.error,
458 lambda: conn.request("PUT", "/url", "body"))
459 resp = conn.getresponse()
460 self.assertEqual(401, resp.status)
461 self.assertEqual("Basic realm=\"example\"",
462 resp.getheader("www-authenticate"))
463
Senthil Kumarand389cb52010-09-21 01:38:15 +0000464 def test_filenoattr(self):
465 # Just test the fileno attribute in the HTTPResponse Object.
466 body = "HTTP/1.1 200 Ok\r\n\r\nText"
467 sock = FakeSocket(body)
468 resp = httplib.HTTPResponse(sock)
469 self.assertTrue(hasattr(resp,'fileno'),
470 'HTTPResponse should expose a fileno attribute')
Georg Brandl23635032008-02-24 00:03:22 +0000471
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000472 # Test lines overflowing the max line size (_MAXLINE in http.client)
473
474 def test_overflowing_status_line(self):
475 self.skipTest("disabled for HTTP 0.9 support")
476 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
477 resp = httplib.HTTPResponse(FakeSocket(body))
478 self.assertRaises((httplib.LineTooLong, httplib.BadStatusLine), resp.begin)
479
480 def test_overflowing_header_line(self):
481 body = (
482 'HTTP/1.1 200 OK\r\n'
483 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
484 )
485 resp = httplib.HTTPResponse(FakeSocket(body))
486 self.assertRaises(httplib.LineTooLong, resp.begin)
487
488 def test_overflowing_chunked_line(self):
489 body = (
490 'HTTP/1.1 200 OK\r\n'
491 'Transfer-Encoding: chunked\r\n\r\n'
492 + '0' * 65536 + 'a\r\n'
493 'hello world\r\n'
494 '0\r\n'
495 )
496 resp = httplib.HTTPResponse(FakeSocket(body))
497 resp.begin()
498 self.assertRaises(httplib.LineTooLong, resp.read)
499
Senthil Kumaranf5aaf6f2012-04-29 10:15:31 +0800500 def test_early_eof(self):
501 # Test httpresponse with no \r\n termination,
502 body = "HTTP/1.1 200 Ok"
503 sock = FakeSocket(body)
504 resp = httplib.HTTPResponse(sock)
505 resp.begin()
506 self.assertEqual(resp.read(), '')
507 self.assertTrue(resp.isclosed())
Antoine Pitroud7b6ac62010-12-18 18:18:21 +0000508
Serhiy Storchakad862db02014-12-01 13:07:28 +0200509 def test_error_leak(self):
510 # Test that the socket is not leaked if getresponse() fails
511 conn = httplib.HTTPConnection('example.com')
512 response = []
513 class Response(httplib.HTTPResponse):
514 def __init__(self, *pos, **kw):
515 response.append(self) # Avoid garbage collector closing the socket
516 httplib.HTTPResponse.__init__(self, *pos, **kw)
517 conn.response_class = Response
518 conn.sock = FakeSocket('') # Emulate server dropping connection
519 conn.request('GET', '/')
520 self.assertRaises(httplib.BadStatusLine, conn.getresponse)
521 self.assertTrue(response)
522 #self.assertTrue(response[0].closed)
523 self.assertTrue(conn.sock.file_closed)
524
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000525class OfflineTest(TestCase):
526 def test_responses(self):
Ezio Melotti2623a372010-11-21 13:34:58 +0000527 self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000528
Gregory P. Smith9d325212010-01-03 02:06:07 +0000529
Senthil Kumaran812b9752015-01-24 12:58:10 -0800530class TestServerMixin:
531 """A limited socket server mixin.
532
533 This is used by test cases for testing http connection end points.
534 """
Gregory P. Smith9d325212010-01-03 02:06:07 +0000535 def setUp(self):
536 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
537 self.port = test_support.bind_port(self.serv)
538 self.source_port = test_support.find_unused_port()
539 self.serv.listen(5)
540 self.conn = None
541
542 def tearDown(self):
543 if self.conn:
544 self.conn.close()
545 self.conn = None
546 self.serv.close()
547 self.serv = None
548
Senthil Kumaran812b9752015-01-24 12:58:10 -0800549class SourceAddressTest(TestServerMixin, TestCase):
Gregory P. Smith9d325212010-01-03 02:06:07 +0000550 def testHTTPConnectionSourceAddress(self):
551 self.conn = httplib.HTTPConnection(HOST, self.port,
552 source_address=('', self.source_port))
553 self.conn.connect()
554 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
555
556 @unittest.skipIf(not hasattr(httplib, 'HTTPSConnection'),
557 'httplib.HTTPSConnection not defined')
558 def testHTTPSConnectionSourceAddress(self):
559 self.conn = httplib.HTTPSConnection(HOST, self.port,
560 source_address=('', self.source_port))
561 # We don't test anything here other the constructor not barfing as
562 # this code doesn't deal with setting up an active running SSL server
563 # for an ssl_wrapped connect() to actually return from.
564
565
Senthil Kumaran812b9752015-01-24 12:58:10 -0800566class HTTPTest(TestServerMixin, TestCase):
567 def testHTTPConnection(self):
568 self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None)
569 self.conn.connect()
570 self.assertEqual(self.conn._conn.host, HOST)
571 self.assertEqual(self.conn._conn.port, self.port)
572
573 def testHTTPWithConnectHostPort(self):
574 testhost = 'unreachable.test.domain'
575 testport = '80'
576 self.conn = httplib.HTTP(host=testhost, port=testport)
577 self.conn.connect(host=HOST, port=self.port)
578 self.assertNotEqual(self.conn._conn.host, testhost)
579 self.assertNotEqual(self.conn._conn.port, testport)
580 self.assertEqual(self.conn._conn.host, HOST)
581 self.assertEqual(self.conn._conn.port, self.port)
582
583
Facundo Batista07c78be2007-03-23 18:54:07 +0000584class TimeoutTest(TestCase):
Trent Nelsone41b0062008-04-08 23:47:30 +0000585 PORT = None
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000586
Facundo Batista07c78be2007-03-23 18:54:07 +0000587 def setUp(self):
588 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000589 TimeoutTest.PORT = test_support.bind_port(self.serv)
Facundo Batistaf1966292007-03-25 03:20:05 +0000590 self.serv.listen(5)
Facundo Batista07c78be2007-03-23 18:54:07 +0000591
592 def tearDown(self):
593 self.serv.close()
594 self.serv = None
595
596 def testTimeoutAttribute(self):
597 '''This will prove that the timeout gets through
598 HTTPConnection and into the socket.
599 '''
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000600 # default -- use global socket timeout
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200601 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000602 socket.setdefaulttimeout(30)
603 try:
604 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
605 httpConn.connect()
606 finally:
607 socket.setdefaulttimeout(None)
Facundo Batista14553b02007-03-23 20:23:08 +0000608 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000609 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000610
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000611 # no timeout -- do not use global socket default
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200612 self.assertIsNone(socket.getdefaulttimeout())
Facundo Batista14553b02007-03-23 20:23:08 +0000613 socket.setdefaulttimeout(30)
614 try:
Trent Nelson6c4a7c62008-04-09 00:34:53 +0000615 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
616 timeout=None)
Facundo Batista14553b02007-03-23 20:23:08 +0000617 httpConn.connect()
618 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000619 socket.setdefaulttimeout(None)
620 self.assertEqual(httpConn.sock.gettimeout(), None)
621 httpConn.close()
622
623 # a value
624 httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
625 httpConn.connect()
Facundo Batista14553b02007-03-23 20:23:08 +0000626 self.assertEqual(httpConn.sock.gettimeout(), 30)
Facundo Batistaf1966292007-03-25 03:20:05 +0000627 httpConn.close()
Facundo Batista07c78be2007-03-23 18:54:07 +0000628
Senthil Kumaran812b9752015-01-24 12:58:10 -0800629
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600630class HTTPSTest(TestCase):
Facundo Batista07c78be2007-03-23 18:54:07 +0000631
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600632 def setUp(self):
633 if not hasattr(httplib, 'HTTPSConnection'):
634 self.skipTest('ssl support required')
635
636 def make_server(self, certfile):
637 from test.ssl_servers import make_https_server
638 return make_https_server(self, certfile=certfile)
Facundo Batista70f996b2007-05-21 17:32:32 +0000639
640 def test_attributes(self):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600641 # simple test to check it's storing the timeout
642 h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
643 self.assertEqual(h.timeout, 30)
Facundo Batista70f996b2007-05-21 17:32:32 +0000644
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600645 def test_networked(self):
646 # Default settings: requires a valid cert from a trusted CA
647 import ssl
648 test_support.requires('network')
649 with test_support.transient_internet('self-signed.pythontest.net'):
650 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
651 with self.assertRaises(ssl.SSLError) as exc_info:
652 h.request('GET', '/')
653 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
654
655 def test_networked_noverification(self):
656 # Switch off cert verification
657 import ssl
658 test_support.requires('network')
659 with test_support.transient_internet('self-signed.pythontest.net'):
660 context = ssl._create_stdlib_context()
661 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
662 context=context)
663 h.request('GET', '/')
664 resp = h.getresponse()
665 self.assertIn('nginx', resp.getheader('server'))
666
Benjamin Petersonf671de42014-11-25 15:16:55 -0600667 @test_support.system_must_validate_cert
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600668 def test_networked_trusted_by_default_cert(self):
669 # Default settings: requires a valid cert from a trusted CA
670 test_support.requires('network')
671 with test_support.transient_internet('www.python.org'):
672 h = httplib.HTTPSConnection('www.python.org', 443)
673 h.request('GET', '/')
674 resp = h.getresponse()
675 content_type = resp.getheader('content-type')
676 self.assertIn('text/html', content_type)
677
678 def test_networked_good_cert(self):
679 # We feed the server's cert as a validating cert
680 import ssl
681 test_support.requires('network')
682 with test_support.transient_internet('self-signed.pythontest.net'):
683 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
684 context.verify_mode = ssl.CERT_REQUIRED
685 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
686 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
687 h.request('GET', '/')
688 resp = h.getresponse()
689 server_string = resp.getheader('server')
690 self.assertIn('nginx', server_string)
691
692 def test_networked_bad_cert(self):
693 # We feed a "CA" cert that is unrelated to the server's cert
694 import ssl
695 test_support.requires('network')
696 with test_support.transient_internet('self-signed.pythontest.net'):
697 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
698 context.verify_mode = ssl.CERT_REQUIRED
699 context.load_verify_locations(CERT_localhost)
700 h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
701 with self.assertRaises(ssl.SSLError) as exc_info:
702 h.request('GET', '/')
703 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
704
705 def test_local_unknown_cert(self):
706 # The custom cert isn't known to the default trust bundle
707 import ssl
708 server = self.make_server(CERT_localhost)
709 h = httplib.HTTPSConnection('localhost', server.port)
710 with self.assertRaises(ssl.SSLError) as exc_info:
711 h.request('GET', '/')
712 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
713
714 def test_local_good_hostname(self):
715 # The (valid) cert validates the HTTP hostname
716 import ssl
717 server = self.make_server(CERT_localhost)
718 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
719 context.verify_mode = ssl.CERT_REQUIRED
720 context.load_verify_locations(CERT_localhost)
721 h = httplib.HTTPSConnection('localhost', server.port, context=context)
722 h.request('GET', '/nonexistent')
723 resp = h.getresponse()
724 self.assertEqual(resp.status, 404)
725
726 def test_local_bad_hostname(self):
727 # The (valid) cert doesn't validate the HTTP hostname
728 import ssl
729 server = self.make_server(CERT_fakehostname)
730 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
731 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500732 context.check_hostname = True
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600733 context.load_verify_locations(CERT_fakehostname)
734 h = httplib.HTTPSConnection('localhost', server.port, context=context)
735 with self.assertRaises(ssl.CertificateError):
736 h.request('GET', '/')
Benjamin Peterson227f6e02014-12-07 13:41:26 -0500737 h.close()
738 # With context.check_hostname=False, the mismatching is ignored
739 context.check_hostname = False
740 h = httplib.HTTPSConnection('localhost', server.port, context=context)
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600741 h.request('GET', '/nonexistent')
742 resp = h.getresponse()
743 self.assertEqual(resp.status, 404)
744
Łukasz Langa7a153902011-10-18 17:16:00 +0200745 def test_host_port(self):
746 # Check invalid host_port
747
Łukasz Langa7a153902011-10-18 17:16:00 +0200748 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600749 self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
Łukasz Langa7a153902011-10-18 17:16:00 +0200750
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600751 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
752 "fe80::207:e9ff:fe9b", 8000),
753 ("www.python.org:443", "www.python.org", 443),
754 ("www.python.org:", "www.python.org", 443),
755 ("www.python.org", "www.python.org", 443),
756 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
757 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
758 443)):
759 c = httplib.HTTPSConnection(hp)
760 self.assertEqual(h, c.host)
761 self.assertEqual(p, c.port)
Łukasz Langa7a153902011-10-18 17:16:00 +0200762
763
Senthil Kumaran36f28f72014-05-16 18:51:46 -0700764class TunnelTests(TestCase):
765 def test_connect(self):
766 response_text = (
767 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
768 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
769 'Content-Length: 42\r\n\r\n'
770 )
771
772 def create_connection(address, timeout=None, source_address=None):
773 return FakeSocket(response_text, host=address[0], port=address[1])
774
775 conn = httplib.HTTPConnection('proxy.com')
776 conn._create_connection = create_connection
777
778 # Once connected, we should not be able to tunnel anymore
779 conn.connect()
780 self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
781
782 # But if close the connection, we are good.
783 conn.close()
784 conn.set_tunnel('destination.com')
785 conn.request('HEAD', '/', '')
786
787 self.assertEqual(conn.sock.host, 'proxy.com')
788 self.assertEqual(conn.sock.port, 80)
789 self.assertTrue('CONNECT destination.com' in conn.sock.data)
790 self.assertTrue('Host: destination.com' in conn.sock.data)
791
792 self.assertTrue('Host: proxy.com' not in conn.sock.data)
793
794 conn.close()
795
796 conn.request('PUT', '/', '')
797 self.assertEqual(conn.sock.host, 'proxy.com')
798 self.assertEqual(conn.sock.port, 80)
799 self.assertTrue('CONNECT destination.com' in conn.sock.data)
800 self.assertTrue('Host: destination.com' in conn.sock.data)
801
802
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -0600803@test_support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +0000804def test_main(verbose=None):
Trent Nelsone41b0062008-04-08 23:47:30 +0000805 test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Senthil Kumaran812b9752015-01-24 12:58:10 -0800806 HTTPTest, HTTPSTest, SourceAddressTest,
807 TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +0000808
Georg Brandl71a20892006-10-29 20:24:01 +0000809if __name__ == '__main__':
810 test_main()