blob: 62612763f06b6c204da36c803f8736955b6f7e2f [file] [log] [blame]
Jeremy Hylton636950f2009-03-28 04:34:21 +00001import errno
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00002from http import client
Jeremy Hylton8fff7922007-08-03 20:56:14 +00003import io
Antoine Pitrou803e6d62010-10-13 10:36:15 +00004import os
Antoine Pitrouead1d622009-09-29 18:44:53 +00005import array
Guido van Rossumd8faa362007-04-27 19:54:29 +00006import socket
Jeremy Hylton121d34a2003-07-08 12:36:58 +00007
Gregory P. Smithb4066372010-01-03 03:28:29 +00008import unittest
9TestCase = unittest.TestCase
Jeremy Hylton2c178252004-08-07 16:28:14 +000010
Benjamin Petersonee8712c2008-05-20 21:35:26 +000011from test import support
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000012
Antoine Pitrou803e6d62010-10-13 10:36:15 +000013here = 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')
Georg Brandlfbaf9312014-11-05 20:37:40 +010018# Self-signed cert file for self-signed.pythontest.net
19CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
Antoine Pitrou803e6d62010-10-13 10:36:15 +000020
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +000021# constants for testing chunked encoding
22chunked_start = (
23 'HTTP/1.1 200 OK\r\n'
24 'Transfer-Encoding: chunked\r\n\r\n'
25 'a\r\n'
26 'hello worl\r\n'
27 '3\r\n'
28 'd! \r\n'
29 '8\r\n'
30 'and now \r\n'
31 '22\r\n'
32 'for something completely different\r\n'
33)
34chunked_expected = b'hello world! and now for something completely different'
35chunk_extension = ";foo=bar"
36last_chunk = "0\r\n"
37last_chunk_extended = "0" + chunk_extension + "\r\n"
38trailers = "X-Dummy: foo\r\nX-Dumm2: bar\r\n"
39chunked_end = "\r\n"
40
Benjamin Petersonee8712c2008-05-20 21:35:26 +000041HOST = support.HOST
Christian Heimes5e696852008-04-09 08:37:03 +000042
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000043class FakeSocket:
Senthil Kumaran9da047b2014-04-14 13:07:56 -040044 def __init__(self, text, fileclass=io.BytesIO, host=None, port=None):
Jeremy Hylton8fff7922007-08-03 20:56:14 +000045 if isinstance(text, str):
Guido van Rossum39478e82007-08-27 17:23:59 +000046 text = text.encode("ascii")
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000047 self.text = text
Jeremy Hylton121d34a2003-07-08 12:36:58 +000048 self.fileclass = fileclass
Martin v. Löwisdd5a8602007-06-30 09:22:09 +000049 self.data = b''
Antoine Pitrou90e47742013-01-02 22:10:47 +010050 self.sendall_calls = 0
Serhiy Storchakab491e052014-12-01 13:07:45 +020051 self.file_closed = False
Senthil Kumaran9da047b2014-04-14 13:07:56 -040052 self.host = host
53 self.port = port
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000054
Jeremy Hylton2c178252004-08-07 16:28:14 +000055 def sendall(self, data):
Antoine Pitrou90e47742013-01-02 22:10:47 +010056 self.sendall_calls += 1
Thomas Wouters89f507f2006-12-13 04:49:30 +000057 self.data += data
Jeremy Hylton2c178252004-08-07 16:28:14 +000058
Jeremy Hylton79fa2b62001-04-13 14:57:44 +000059 def makefile(self, mode, bufsize=None):
60 if mode != 'r' and mode != 'rb':
Jeremy Hylton7c1692d2009-03-27 21:31:03 +000061 raise client.UnimplementedFileMode()
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +000062 # keep the file around so we can check how much was read from it
63 self.file = self.fileclass(self.text)
Serhiy Storchakab491e052014-12-01 13:07:45 +020064 self.file.close = self.file_close #nerf close ()
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +000065 return self.file
Jeremy Hylton121d34a2003-07-08 12:36:58 +000066
Serhiy Storchakab491e052014-12-01 13:07:45 +020067 def file_close(self):
68 self.file_closed = True
Jeremy Hylton121d34a2003-07-08 12:36:58 +000069
Senthil Kumaran9da047b2014-04-14 13:07:56 -040070 def close(self):
71 pass
72
Jeremy Hylton636950f2009-03-28 04:34:21 +000073class EPipeSocket(FakeSocket):
74
75 def __init__(self, text, pipe_trigger):
76 # When sendall() is called with pipe_trigger, raise EPIPE.
77 FakeSocket.__init__(self, text)
78 self.pipe_trigger = pipe_trigger
79
80 def sendall(self, data):
81 if self.pipe_trigger in data:
Andrew Svetlov0832af62012-12-18 23:10:48 +020082 raise OSError(errno.EPIPE, "gotcha")
Jeremy Hylton636950f2009-03-28 04:34:21 +000083 self.data += data
84
85 def close(self):
86 pass
87
Serhiy Storchaka50254c52013-08-29 11:35:43 +030088class NoEOFBytesIO(io.BytesIO):
89 """Like BytesIO, but raises AssertionError on EOF.
Jeremy Hylton121d34a2003-07-08 12:36:58 +000090
Jeremy Hylton7c1692d2009-03-27 21:31:03 +000091 This is used below to test that http.client doesn't try to read
Jeremy Hylton121d34a2003-07-08 12:36:58 +000092 more from the underlying file than it should.
93 """
94 def read(self, n=-1):
Jeremy Hylton8fff7922007-08-03 20:56:14 +000095 data = io.BytesIO.read(self, n)
Jeremy Hyltonda3f2282007-08-29 17:26:34 +000096 if data == b'':
Jeremy Hylton121d34a2003-07-08 12:36:58 +000097 raise AssertionError('caller tried to read past EOF')
98 return data
99
100 def readline(self, length=None):
Jeremy Hylton8fff7922007-08-03 20:56:14 +0000101 data = io.BytesIO.readline(self, length)
Jeremy Hyltonda3f2282007-08-29 17:26:34 +0000102 if data == b'':
Jeremy Hylton121d34a2003-07-08 12:36:58 +0000103 raise AssertionError('caller tried to read past EOF')
104 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000105
Jeremy Hylton2c178252004-08-07 16:28:14 +0000106class HeaderTests(TestCase):
107 def test_auto_headers(self):
108 # Some headers are added automatically, but should not be added by
109 # .request() if they are explicitly set.
110
Jeremy Hylton2c178252004-08-07 16:28:14 +0000111 class HeaderCountingBuffer(list):
112 def __init__(self):
113 self.count = {}
114 def append(self, item):
Guido van Rossum022c4742007-08-29 02:00:20 +0000115 kv = item.split(b':')
Jeremy Hylton2c178252004-08-07 16:28:14 +0000116 if len(kv) > 1:
117 # item is a 'Key: Value' header string
Martin v. Löwisdd5a8602007-06-30 09:22:09 +0000118 lcKey = kv[0].decode('ascii').lower()
Jeremy Hylton2c178252004-08-07 16:28:14 +0000119 self.count.setdefault(lcKey, 0)
120 self.count[lcKey] += 1
121 list.append(self, item)
122
123 for explicit_header in True, False:
124 for header in 'Content-length', 'Host', 'Accept-encoding':
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000125 conn = client.HTTPConnection('example.com')
Jeremy Hylton2c178252004-08-07 16:28:14 +0000126 conn.sock = FakeSocket('blahblahblah')
127 conn._buffer = HeaderCountingBuffer()
128
129 body = 'spamspamspam'
130 headers = {}
131 if explicit_header:
132 headers[header] = str(len(body))
133 conn.request('POST', '/', body, headers)
134 self.assertEqual(conn._buffer.count[header.lower()], 1)
135
Senthil Kumaran5fa4a892012-05-19 16:58:09 +0800136 def test_content_length_0(self):
137
138 class ContentLengthChecker(list):
139 def __init__(self):
140 list.__init__(self)
141 self.content_length = None
142 def append(self, item):
143 kv = item.split(b':', 1)
144 if len(kv) > 1 and kv[0].lower() == b'content-length':
145 self.content_length = kv[1].strip()
146 list.append(self, item)
147
148 # POST with empty body
149 conn = client.HTTPConnection('example.com')
150 conn.sock = FakeSocket(None)
151 conn._buffer = ContentLengthChecker()
152 conn.request('POST', '/', '')
153 self.assertEqual(conn._buffer.content_length, b'0',
154 'Header Content-Length not set')
155
156 # PUT request with empty body
157 conn = client.HTTPConnection('example.com')
158 conn.sock = FakeSocket(None)
159 conn._buffer = ContentLengthChecker()
160 conn.request('PUT', '/', '')
161 self.assertEqual(conn._buffer.content_length, b'0',
162 'Header Content-Length not set')
163
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000164 def test_putheader(self):
165 conn = client.HTTPConnection('example.com')
166 conn.sock = FakeSocket(None)
167 conn.putrequest('GET','/')
168 conn.putheader('Content-length', 42)
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +0200169 self.assertIn(b'Content-length: 42', conn._buffer)
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000170
Senthil Kumaran74ebd9e2010-11-13 12:27:49 +0000171 def test_ipv6host_header(self):
172 # Default host header on IPv6 transaction should wrapped by [] if
173 # its actual IPv6 address
174 expected = b'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
175 b'Accept-Encoding: identity\r\n\r\n'
176 conn = client.HTTPConnection('[2001::]:81')
177 sock = FakeSocket('')
178 conn.sock = sock
179 conn.request('GET', '/foo')
180 self.assertTrue(sock.data.startswith(expected))
181
182 expected = b'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
183 b'Accept-Encoding: identity\r\n\r\n'
184 conn = client.HTTPConnection('[2001:102A::]')
185 sock = FakeSocket('')
186 conn.sock = sock
187 conn.request('GET', '/foo')
188 self.assertTrue(sock.data.startswith(expected))
189
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000190
Thomas Wouters89f507f2006-12-13 04:49:30 +0000191class BasicTest(TestCase):
192 def test_status_lines(self):
193 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000194
Thomas Wouters89f507f2006-12-13 04:49:30 +0000195 body = "HTTP/1.1 200 Ok\r\n\r\nText"
196 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000197 resp = client.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000198 resp.begin()
Serhiy Storchaka1c84ac12013-12-17 21:50:02 +0200199 self.assertEqual(resp.read(0), b'') # Issue #20007
200 self.assertFalse(resp.isclosed())
201 self.assertFalse(resp.closed)
Jeremy Hylton8fff7922007-08-03 20:56:14 +0000202 self.assertEqual(resp.read(), b"Text")
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000203 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200204 self.assertFalse(resp.closed)
205 resp.close()
206 self.assertTrue(resp.closed)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000207
Thomas Wouters89f507f2006-12-13 04:49:30 +0000208 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
209 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000210 resp = client.HTTPResponse(sock)
211 self.assertRaises(client.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000212
Benjamin Peterson11dbfd42010-03-21 22:50:04 +0000213 def test_bad_status_repr(self):
214 exc = client.BadStatusLine('')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000215 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Benjamin Peterson11dbfd42010-03-21 22:50:04 +0000216
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000217 def test_partial_reads(self):
Antoine Pitrou084daa22012-12-15 19:11:54 +0100218 # if we have a length, the system knows when to close itself
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000219 # same behaviour than when we read the whole thing with read()
220 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
221 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000222 resp = client.HTTPResponse(sock)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000223 resp.begin()
224 self.assertEqual(resp.read(2), b'Te')
225 self.assertFalse(resp.isclosed())
226 self.assertEqual(resp.read(2), b'xt')
227 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200228 self.assertFalse(resp.closed)
229 resp.close()
230 self.assertTrue(resp.closed)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000231
Antoine Pitrou38d96432011-12-06 22:33:57 +0100232 def test_partial_readintos(self):
Antoine Pitroud20e7742012-12-15 19:22:30 +0100233 # if we have a length, the system knows when to close itself
Antoine Pitrou38d96432011-12-06 22:33:57 +0100234 # same behaviour than when we read the whole thing with read()
235 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
236 sock = FakeSocket(body)
237 resp = client.HTTPResponse(sock)
238 resp.begin()
239 b = bytearray(2)
240 n = resp.readinto(b)
241 self.assertEqual(n, 2)
242 self.assertEqual(bytes(b), b'Te')
243 self.assertFalse(resp.isclosed())
244 n = resp.readinto(b)
245 self.assertEqual(n, 2)
246 self.assertEqual(bytes(b), b'xt')
247 self.assertTrue(resp.isclosed())
Serhiy Storchakab6c86fd2013-02-06 10:35:40 +0200248 self.assertFalse(resp.closed)
249 resp.close()
250 self.assertTrue(resp.closed)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100251
Antoine Pitrou084daa22012-12-15 19:11:54 +0100252 def test_partial_reads_no_content_length(self):
253 # when no length is present, the socket should be gracefully closed when
254 # all data was read
255 body = "HTTP/1.1 200 Ok\r\n\r\nText"
256 sock = FakeSocket(body)
257 resp = client.HTTPResponse(sock)
258 resp.begin()
259 self.assertEqual(resp.read(2), b'Te')
260 self.assertFalse(resp.isclosed())
261 self.assertEqual(resp.read(2), b'xt')
262 self.assertEqual(resp.read(1), b'')
263 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200264 self.assertFalse(resp.closed)
265 resp.close()
266 self.assertTrue(resp.closed)
Antoine Pitrou084daa22012-12-15 19:11:54 +0100267
Antoine Pitroud20e7742012-12-15 19:22:30 +0100268 def test_partial_readintos_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 = client.HTTPResponse(sock)
274 resp.begin()
275 b = bytearray(2)
276 n = resp.readinto(b)
277 self.assertEqual(n, 2)
278 self.assertEqual(bytes(b), b'Te')
279 self.assertFalse(resp.isclosed())
280 n = resp.readinto(b)
281 self.assertEqual(n, 2)
282 self.assertEqual(bytes(b), b'xt')
283 n = resp.readinto(b)
284 self.assertEqual(n, 0)
285 self.assertTrue(resp.isclosed())
286
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100287 def test_partial_reads_incomplete_body(self):
288 # if the server shuts down the connection before the whole
289 # content-length is delivered, the socket is gracefully closed
290 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
291 sock = FakeSocket(body)
292 resp = client.HTTPResponse(sock)
293 resp.begin()
294 self.assertEqual(resp.read(2), b'Te')
295 self.assertFalse(resp.isclosed())
296 self.assertEqual(resp.read(2), b'xt')
297 self.assertEqual(resp.read(1), b'')
298 self.assertTrue(resp.isclosed())
299
Antoine Pitrou6a35e182013-02-02 23:04:56 +0100300 def test_partial_readintos_incomplete_body(self):
301 # if the server shuts down the connection before the whole
302 # content-length is delivered, the socket is gracefully closed
303 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
304 sock = FakeSocket(body)
305 resp = client.HTTPResponse(sock)
306 resp.begin()
307 b = bytearray(2)
308 n = resp.readinto(b)
309 self.assertEqual(n, 2)
310 self.assertEqual(bytes(b), b'Te')
311 self.assertFalse(resp.isclosed())
312 n = resp.readinto(b)
313 self.assertEqual(n, 2)
314 self.assertEqual(bytes(b), b'xt')
315 n = resp.readinto(b)
316 self.assertEqual(n, 0)
317 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200318 self.assertFalse(resp.closed)
319 resp.close()
320 self.assertTrue(resp.closed)
Antoine Pitrou6a35e182013-02-02 23:04:56 +0100321
Thomas Wouters89f507f2006-12-13 04:49:30 +0000322 def test_host_port(self):
323 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000324
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200325 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000326 self.assertRaises(client.InvalidURL, client.HTTPConnection, hp)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000327
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000328 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
329 "fe80::207:e9ff:fe9b", 8000),
Thomas Wouters89f507f2006-12-13 04:49:30 +0000330 ("www.python.org:80", "www.python.org", 80),
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200331 ("www.python.org:", "www.python.org", 80),
Thomas Wouters89f507f2006-12-13 04:49:30 +0000332 ("www.python.org", "www.python.org", 80),
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200333 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80),
334 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", 80)):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000335 c = client.HTTPConnection(hp)
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000336 self.assertEqual(h, c.host)
337 self.assertEqual(p, c.port)
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000338
Thomas Wouters89f507f2006-12-13 04:49:30 +0000339 def test_response_headers(self):
340 # test response with multiple message headers with the same field name.
341 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000342 'Set-Cookie: Customer="WILE_E_COYOTE"; '
343 'Version="1"; Path="/acme"\r\n'
Thomas Wouters89f507f2006-12-13 04:49:30 +0000344 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
345 ' Path="/acme"\r\n'
346 '\r\n'
347 'No body\r\n')
348 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
349 ', '
350 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
351 s = FakeSocket(text)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000352 r = client.HTTPResponse(s)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000353 r.begin()
354 cookies = r.getheader("Set-Cookie")
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000355 self.assertEqual(cookies, hdr)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000356
Thomas Wouters89f507f2006-12-13 04:49:30 +0000357 def test_read_head(self):
358 # Test that the library doesn't attempt to read any data
359 # from a HEAD request. (Tickles SF bug #622042.)
360 sock = FakeSocket(
361 'HTTP/1.1 200 OK\r\n'
362 'Content-Length: 14432\r\n'
363 '\r\n',
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300364 NoEOFBytesIO)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000365 resp = client.HTTPResponse(sock, method="HEAD")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000366 resp.begin()
Guido van Rossuma00f1232007-09-12 19:43:09 +0000367 if resp.read():
Thomas Wouters89f507f2006-12-13 04:49:30 +0000368 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000369
Antoine Pitrou38d96432011-12-06 22:33:57 +0100370 def test_readinto_head(self):
371 # Test that the library doesn't attempt to read any data
372 # from a HEAD request. (Tickles SF bug #622042.)
373 sock = FakeSocket(
374 'HTTP/1.1 200 OK\r\n'
375 'Content-Length: 14432\r\n'
376 '\r\n',
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300377 NoEOFBytesIO)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100378 resp = client.HTTPResponse(sock, method="HEAD")
379 resp.begin()
380 b = bytearray(5)
381 if resp.readinto(b) != 0:
382 self.fail("Did not expect response from HEAD request")
383 self.assertEqual(bytes(b), b'\x00'*5)
384
Georg Brandlbf3f8eb2013-10-27 07:34:48 +0100385 def test_too_many_headers(self):
386 headers = '\r\n'.join('Header%d: foo' % i
387 for i in range(client._MAXHEADERS + 1)) + '\r\n'
388 text = ('HTTP/1.1 200 OK\r\n' + headers)
389 s = FakeSocket(text)
390 r = client.HTTPResponse(s)
391 self.assertRaisesRegex(client.HTTPException,
392 r"got more than \d+ headers", r.begin)
393
Thomas Wouters89f507f2006-12-13 04:49:30 +0000394 def test_send_file(self):
Guido van Rossum022c4742007-08-29 02:00:20 +0000395 expected = (b'GET /foo HTTP/1.1\r\nHost: example.com\r\n'
396 b'Accept-Encoding: identity\r\nContent-Length:')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000397
Brett Cannon77b7de62010-10-29 23:31:11 +0000398 with open(__file__, 'rb') as body:
399 conn = client.HTTPConnection('example.com')
400 sock = FakeSocket(body)
401 conn.sock = sock
402 conn.request('GET', '/foo', body)
403 self.assertTrue(sock.data.startswith(expected), '%r != %r' %
404 (sock.data[:len(expected)], expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000405
Antoine Pitrouead1d622009-09-29 18:44:53 +0000406 def test_send(self):
407 expected = b'this is a test this is only a test'
408 conn = client.HTTPConnection('example.com')
409 sock = FakeSocket(None)
410 conn.sock = sock
411 conn.send(expected)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000412 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000413 sock.data = b''
414 conn.send(array.array('b', expected))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000415 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000416 sock.data = b''
417 conn.send(io.BytesIO(expected))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000418 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000419
Andrew Svetlov7b2c8bb2013-04-12 22:49:19 +0300420 def test_send_updating_file(self):
421 def data():
422 yield 'data'
423 yield None
424 yield 'data_two'
425
426 class UpdatingFile():
427 mode = 'r'
428 d = data()
429 def read(self, blocksize=-1):
430 return self.d.__next__()
431
432 expected = b'data'
433
434 conn = client.HTTPConnection('example.com')
435 sock = FakeSocket("")
436 conn.sock = sock
437 conn.send(UpdatingFile())
438 self.assertEqual(sock.data, expected)
439
440
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000441 def test_send_iter(self):
442 expected = b'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
443 b'Accept-Encoding: identity\r\nContent-Length: 11\r\n' \
444 b'\r\nonetwothree'
445
446 def body():
447 yield b"one"
448 yield b"two"
449 yield b"three"
450
451 conn = client.HTTPConnection('example.com')
452 sock = FakeSocket("")
453 conn.sock = sock
454 conn.request('GET', '/foo', body(), {'Content-Length': '11'})
Victor Stinner04ba9662011-01-04 00:04:46 +0000455 self.assertEqual(sock.data, expected)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000456
Senthil Kumaraneb71ad42011-08-02 18:33:41 +0800457 def test_send_type_error(self):
458 # See: Issue #12676
459 conn = client.HTTPConnection('example.com')
460 conn.sock = FakeSocket('')
461 with self.assertRaises(TypeError):
462 conn.request('POST', 'test', conn)
463
Christian Heimesa612dc02008-02-24 13:08:18 +0000464 def test_chunked(self):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000465 expected = chunked_expected
466 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000467 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000468 resp.begin()
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100469 self.assertEqual(resp.read(), expected)
Christian Heimesa612dc02008-02-24 13:08:18 +0000470 resp.close()
471
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100472 # Various read sizes
473 for n in range(1, 12):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000474 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100475 resp = client.HTTPResponse(sock, method="GET")
476 resp.begin()
477 self.assertEqual(resp.read(n) + resp.read(n) + resp.read(), expected)
478 resp.close()
479
Christian Heimesa612dc02008-02-24 13:08:18 +0000480 for x in ('', 'foo\r\n'):
481 sock = FakeSocket(chunked_start + x)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000482 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000483 resp.begin()
484 try:
485 resp.read()
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000486 except client.IncompleteRead as i:
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100487 self.assertEqual(i.partial, expected)
488 expected_message = 'IncompleteRead(%d bytes read)' % len(expected)
489 self.assertEqual(repr(i), expected_message)
490 self.assertEqual(str(i), expected_message)
Christian Heimesa612dc02008-02-24 13:08:18 +0000491 else:
492 self.fail('IncompleteRead expected')
493 finally:
494 resp.close()
495
Antoine Pitrou38d96432011-12-06 22:33:57 +0100496 def test_readinto_chunked(self):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000497
498 expected = chunked_expected
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100499 nexpected = len(expected)
500 b = bytearray(128)
501
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000502 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100503 resp = client.HTTPResponse(sock, method="GET")
504 resp.begin()
Antoine Pitrou38d96432011-12-06 22:33:57 +0100505 n = resp.readinto(b)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100506 self.assertEqual(b[:nexpected], expected)
507 self.assertEqual(n, nexpected)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100508 resp.close()
509
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100510 # Various read sizes
511 for n in range(1, 12):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000512 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100513 resp = client.HTTPResponse(sock, method="GET")
514 resp.begin()
515 m = memoryview(b)
516 i = resp.readinto(m[0:n])
517 i += resp.readinto(m[i:n + i])
518 i += resp.readinto(m[i:])
519 self.assertEqual(b[:nexpected], expected)
520 self.assertEqual(i, nexpected)
521 resp.close()
522
Antoine Pitrou38d96432011-12-06 22:33:57 +0100523 for x in ('', 'foo\r\n'):
524 sock = FakeSocket(chunked_start + x)
525 resp = client.HTTPResponse(sock, method="GET")
526 resp.begin()
527 try:
Antoine Pitrou38d96432011-12-06 22:33:57 +0100528 n = resp.readinto(b)
529 except client.IncompleteRead as i:
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100530 self.assertEqual(i.partial, expected)
531 expected_message = 'IncompleteRead(%d bytes read)' % len(expected)
532 self.assertEqual(repr(i), expected_message)
533 self.assertEqual(str(i), expected_message)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100534 else:
535 self.fail('IncompleteRead expected')
536 finally:
537 resp.close()
538
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000539 def test_chunked_head(self):
540 chunked_start = (
541 'HTTP/1.1 200 OK\r\n'
542 'Transfer-Encoding: chunked\r\n\r\n'
543 'a\r\n'
544 'hello world\r\n'
545 '1\r\n'
546 'd\r\n'
547 )
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000548 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000549 resp = client.HTTPResponse(sock, method="HEAD")
550 resp.begin()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000551 self.assertEqual(resp.read(), b'')
552 self.assertEqual(resp.status, 200)
553 self.assertEqual(resp.reason, 'OK')
Senthil Kumaran0b998832010-06-04 17:27:11 +0000554 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200555 self.assertFalse(resp.closed)
556 resp.close()
557 self.assertTrue(resp.closed)
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000558
Antoine Pitrou38d96432011-12-06 22:33:57 +0100559 def test_readinto_chunked_head(self):
560 chunked_start = (
561 'HTTP/1.1 200 OK\r\n'
562 'Transfer-Encoding: chunked\r\n\r\n'
563 'a\r\n'
564 'hello world\r\n'
565 '1\r\n'
566 'd\r\n'
567 )
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000568 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100569 resp = client.HTTPResponse(sock, method="HEAD")
570 resp.begin()
571 b = bytearray(5)
572 n = resp.readinto(b)
573 self.assertEqual(n, 0)
574 self.assertEqual(bytes(b), b'\x00'*5)
575 self.assertEqual(resp.status, 200)
576 self.assertEqual(resp.reason, 'OK')
577 self.assertTrue(resp.isclosed())
Serhiy Storchakab6c86fd2013-02-06 10:35:40 +0200578 self.assertFalse(resp.closed)
579 resp.close()
580 self.assertTrue(resp.closed)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100581
Christian Heimesa612dc02008-02-24 13:08:18 +0000582 def test_negative_content_length(self):
Jeremy Hylton82066952008-12-15 03:08:30 +0000583 sock = FakeSocket(
584 'HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\nHello\r\n')
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000585 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000586 resp.begin()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000587 self.assertEqual(resp.read(), b'Hello\r\n')
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100588 self.assertTrue(resp.isclosed())
Christian Heimesa612dc02008-02-24 13:08:18 +0000589
Benjamin Peterson6accb982009-03-02 22:50:25 +0000590 def test_incomplete_read(self):
591 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000592 resp = client.HTTPResponse(sock, method="GET")
Benjamin Peterson6accb982009-03-02 22:50:25 +0000593 resp.begin()
594 try:
595 resp.read()
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000596 except client.IncompleteRead as i:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000597 self.assertEqual(i.partial, b'Hello\r\n')
Benjamin Peterson6accb982009-03-02 22:50:25 +0000598 self.assertEqual(repr(i),
599 "IncompleteRead(7 bytes read, 3 more expected)")
600 self.assertEqual(str(i),
601 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100602 self.assertTrue(resp.isclosed())
Benjamin Peterson6accb982009-03-02 22:50:25 +0000603 else:
604 self.fail('IncompleteRead expected')
Benjamin Peterson6accb982009-03-02 22:50:25 +0000605
Jeremy Hylton636950f2009-03-28 04:34:21 +0000606 def test_epipe(self):
607 sock = EPipeSocket(
608 "HTTP/1.0 401 Authorization Required\r\n"
609 "Content-type: text/html\r\n"
610 "WWW-Authenticate: Basic realm=\"example\"\r\n",
611 b"Content-Length")
612 conn = client.HTTPConnection("example.com")
613 conn.sock = sock
Andrew Svetlov0832af62012-12-18 23:10:48 +0200614 self.assertRaises(OSError,
Jeremy Hylton636950f2009-03-28 04:34:21 +0000615 lambda: conn.request("PUT", "/url", "body"))
616 resp = conn.getresponse()
617 self.assertEqual(401, resp.status)
618 self.assertEqual("Basic realm=\"example\"",
619 resp.getheader("www-authenticate"))
Christian Heimesa612dc02008-02-24 13:08:18 +0000620
Senthil Kumaran5466bf12010-12-18 16:55:23 +0000621 # Test lines overflowing the max line size (_MAXLINE in http.client)
622
623 def test_overflowing_status_line(self):
624 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
625 resp = client.HTTPResponse(FakeSocket(body))
626 self.assertRaises((client.LineTooLong, client.BadStatusLine), resp.begin)
627
628 def test_overflowing_header_line(self):
629 body = (
630 'HTTP/1.1 200 OK\r\n'
631 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
632 )
633 resp = client.HTTPResponse(FakeSocket(body))
634 self.assertRaises(client.LineTooLong, resp.begin)
635
636 def test_overflowing_chunked_line(self):
637 body = (
638 'HTTP/1.1 200 OK\r\n'
639 'Transfer-Encoding: chunked\r\n\r\n'
640 + '0' * 65536 + 'a\r\n'
641 'hello world\r\n'
642 '0\r\n'
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000643 '\r\n'
Senthil Kumaran5466bf12010-12-18 16:55:23 +0000644 )
645 resp = client.HTTPResponse(FakeSocket(body))
646 resp.begin()
647 self.assertRaises(client.LineTooLong, resp.read)
648
Senthil Kumaran9c29f862012-04-29 10:20:46 +0800649 def test_early_eof(self):
650 # Test httpresponse with no \r\n termination,
651 body = "HTTP/1.1 200 Ok"
652 sock = FakeSocket(body)
653 resp = client.HTTPResponse(sock)
654 resp.begin()
655 self.assertEqual(resp.read(), b'')
656 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200657 self.assertFalse(resp.closed)
658 resp.close()
659 self.assertTrue(resp.closed)
Senthil Kumaran9c29f862012-04-29 10:20:46 +0800660
Antoine Pitrou90e47742013-01-02 22:10:47 +0100661 def test_delayed_ack_opt(self):
662 # Test that Nagle/delayed_ack optimistaion works correctly.
663
664 # For small payloads, it should coalesce the body with
665 # headers, resulting in a single sendall() call
666 conn = client.HTTPConnection('example.com')
667 sock = FakeSocket(None)
668 conn.sock = sock
669 body = b'x' * (conn.mss - 1)
670 conn.request('POST', '/', body)
671 self.assertEqual(sock.sendall_calls, 1)
672
673 # For large payloads, it should send the headers and
674 # then the body, resulting in more than one sendall()
675 # call
676 conn = client.HTTPConnection('example.com')
677 sock = FakeSocket(None)
678 conn.sock = sock
679 body = b'x' * conn.mss
680 conn.request('POST', '/', body)
681 self.assertGreater(sock.sendall_calls, 1)
682
Serhiy Storchakab491e052014-12-01 13:07:45 +0200683 def test_error_leak(self):
684 # Test that the socket is not leaked if getresponse() fails
685 conn = client.HTTPConnection('example.com')
686 response = None
687 class Response(client.HTTPResponse):
688 def __init__(self, *pos, **kw):
689 nonlocal response
690 response = self # Avoid garbage collector closing the socket
691 client.HTTPResponse.__init__(self, *pos, **kw)
692 conn.response_class = Response
693 conn.sock = FakeSocket('') # Emulate server dropping connection
694 conn.request('GET', '/')
695 self.assertRaises(client.BadStatusLine, conn.getresponse)
696 self.assertTrue(response.closed)
697 self.assertTrue(conn.sock.file_closed)
698
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000699 def test_chunked_extension(self):
700 extra = '3;foo=bar\r\n' + 'abc\r\n'
701 expected = chunked_expected + b'abc'
702
703 sock = FakeSocket(chunked_start + extra + last_chunk_extended + chunked_end)
704 resp = client.HTTPResponse(sock, method="GET")
705 resp.begin()
706 self.assertEqual(resp.read(), expected)
707 resp.close()
708
709 def test_chunked_missing_end(self):
710 """some servers may serve up a short chunked encoding stream"""
711 expected = chunked_expected
712 sock = FakeSocket(chunked_start + last_chunk) #no terminating crlf
713 resp = client.HTTPResponse(sock, method="GET")
714 resp.begin()
715 self.assertEqual(resp.read(), expected)
716 resp.close()
717
718 def test_chunked_trailers(self):
719 """See that trailers are read and ignored"""
720 expected = chunked_expected
721 sock = FakeSocket(chunked_start + last_chunk + trailers + chunked_end)
722 resp = client.HTTPResponse(sock, method="GET")
723 resp.begin()
724 self.assertEqual(resp.read(), expected)
725 # we should have reached the end of the file
726 self.assertEqual(sock.file.read(100), b"") #we read to the end
727 resp.close()
728
729 def test_chunked_sync(self):
730 """Check that we don't read past the end of the chunked-encoding stream"""
731 expected = chunked_expected
732 extradata = "extradata"
733 sock = FakeSocket(chunked_start + last_chunk + trailers + chunked_end + extradata)
734 resp = client.HTTPResponse(sock, method="GET")
735 resp.begin()
736 self.assertEqual(resp.read(), expected)
737 # the file should now have our extradata ready to be read
738 self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end
739 resp.close()
740
741 def test_content_length_sync(self):
742 """Check that we don't read past the end of the Content-Length stream"""
743 extradata = "extradata"
744 expected = b"Hello123\r\n"
745 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello123\r\n' + extradata)
746 resp = client.HTTPResponse(sock, method="GET")
747 resp.begin()
748 self.assertEqual(resp.read(), expected)
749 # the file should now have our extradata ready to be read
750 self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end
751 resp.close()
752
753class ExtendedReadTest(TestCase):
754 """
755 Test peek(), read1(), readline()
756 """
757 lines = (
758 'HTTP/1.1 200 OK\r\n'
759 '\r\n'
760 'hello world!\n'
761 'and now \n'
762 'for something completely different\n'
763 'foo'
764 )
765 lines_expected = lines[lines.find('hello'):].encode("ascii")
766 lines_chunked = (
767 'HTTP/1.1 200 OK\r\n'
768 'Transfer-Encoding: chunked\r\n\r\n'
769 'a\r\n'
770 'hello worl\r\n'
771 '3\r\n'
772 'd!\n\r\n'
773 '9\r\n'
774 'and now \n\r\n'
775 '23\r\n'
776 'for something completely different\n\r\n'
777 '3\r\n'
778 'foo\r\n'
779 '0\r\n' # terminating chunk
780 '\r\n' # end of trailers
781 )
782
783 def setUp(self):
784 sock = FakeSocket(self.lines)
785 resp = client.HTTPResponse(sock, method="GET")
786 resp.begin()
787 resp.fp = io.BufferedReader(resp.fp)
788 self.resp = resp
789
790
791
792 def test_peek(self):
793 resp = self.resp
794 # patch up the buffered peek so that it returns not too much stuff
795 oldpeek = resp.fp.peek
796 def mypeek(n=-1):
797 p = oldpeek(n)
798 if n >= 0:
799 return p[:n]
800 return p[:10]
801 resp.fp.peek = mypeek
802
803 all = []
804 while True:
805 # try a short peek
806 p = resp.peek(3)
807 if p:
808 self.assertGreater(len(p), 0)
809 # then unbounded peek
810 p2 = resp.peek()
811 self.assertGreaterEqual(len(p2), len(p))
812 self.assertTrue(p2.startswith(p))
813 next = resp.read(len(p2))
814 self.assertEqual(next, p2)
815 else:
816 next = resp.read()
817 self.assertFalse(next)
818 all.append(next)
819 if not next:
820 break
821 self.assertEqual(b"".join(all), self.lines_expected)
822
823 def test_readline(self):
824 resp = self.resp
825 self._verify_readline(self.resp.readline, self.lines_expected)
826
827 def _verify_readline(self, readline, expected):
828 all = []
829 while True:
830 # short readlines
831 line = readline(5)
832 if line and line != b"foo":
833 if len(line) < 5:
834 self.assertTrue(line.endswith(b"\n"))
835 all.append(line)
836 if not line:
837 break
838 self.assertEqual(b"".join(all), expected)
839
840 def test_read1(self):
841 resp = self.resp
842 def r():
843 res = resp.read1(4)
844 self.assertLessEqual(len(res), 4)
845 return res
846 readliner = Readliner(r)
847 self._verify_readline(readliner.readline, self.lines_expected)
848
849 def test_read1_unbounded(self):
850 resp = self.resp
851 all = []
852 while True:
853 data = resp.read1()
854 if not data:
855 break
856 all.append(data)
857 self.assertEqual(b"".join(all), self.lines_expected)
858
859 def test_read1_bounded(self):
860 resp = self.resp
861 all = []
862 while True:
863 data = resp.read1(10)
864 if not data:
865 break
866 self.assertLessEqual(len(data), 10)
867 all.append(data)
868 self.assertEqual(b"".join(all), self.lines_expected)
869
870 def test_read1_0(self):
871 self.assertEqual(self.resp.read1(0), b"")
872
873 def test_peek_0(self):
874 p = self.resp.peek(0)
875 self.assertLessEqual(0, len(p))
876
877class ExtendedReadTestChunked(ExtendedReadTest):
878 """
879 Test peek(), read1(), readline() in chunked mode
880 """
881 lines = (
882 'HTTP/1.1 200 OK\r\n'
883 'Transfer-Encoding: chunked\r\n\r\n'
884 'a\r\n'
885 'hello worl\r\n'
886 '3\r\n'
887 'd!\n\r\n'
888 '9\r\n'
889 'and now \n\r\n'
890 '23\r\n'
891 'for something completely different\n\r\n'
892 '3\r\n'
893 'foo\r\n'
894 '0\r\n' # terminating chunk
895 '\r\n' # end of trailers
896 )
897
898
899class Readliner:
900 """
901 a simple readline class that uses an arbitrary read function and buffering
902 """
903 def __init__(self, readfunc):
904 self.readfunc = readfunc
905 self.remainder = b""
906
907 def readline(self, limit):
908 data = []
909 datalen = 0
910 read = self.remainder
911 try:
912 while True:
913 idx = read.find(b'\n')
914 if idx != -1:
915 break
916 if datalen + len(read) >= limit:
917 idx = limit - datalen - 1
918 # read more data
919 data.append(read)
920 read = self.readfunc()
921 if not read:
922 idx = 0 #eof condition
923 break
924 idx += 1
925 data.append(read[:idx])
926 self.remainder = read[idx:]
927 return b"".join(data)
928 except:
929 self.remainder = b"".join(data)
930 raise
931
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000932class OfflineTest(TestCase):
933 def test_responses(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000934 self.assertEqual(client.responses[client.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000935
Gregory P. Smithb4066372010-01-03 03:28:29 +0000936
937class SourceAddressTest(TestCase):
938 def setUp(self):
939 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
940 self.port = support.bind_port(self.serv)
941 self.source_port = support.find_unused_port()
Charles-François Natali6e204602014-07-23 19:28:13 +0100942 self.serv.listen()
Gregory P. Smithb4066372010-01-03 03:28:29 +0000943 self.conn = None
944
945 def tearDown(self):
946 if self.conn:
947 self.conn.close()
948 self.conn = None
949 self.serv.close()
950 self.serv = None
951
952 def testHTTPConnectionSourceAddress(self):
953 self.conn = client.HTTPConnection(HOST, self.port,
954 source_address=('', self.source_port))
955 self.conn.connect()
956 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
957
958 @unittest.skipIf(not hasattr(client, 'HTTPSConnection'),
959 'http.client.HTTPSConnection not defined')
960 def testHTTPSConnectionSourceAddress(self):
961 self.conn = client.HTTPSConnection(HOST, self.port,
962 source_address=('', self.source_port))
963 # We don't test anything here other the constructor not barfing as
964 # this code doesn't deal with setting up an active running SSL server
965 # for an ssl_wrapped connect() to actually return from.
966
967
Guido van Rossumd8faa362007-04-27 19:54:29 +0000968class TimeoutTest(TestCase):
Christian Heimes5e696852008-04-09 08:37:03 +0000969 PORT = None
Guido van Rossumd8faa362007-04-27 19:54:29 +0000970
971 def setUp(self):
972 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000973 TimeoutTest.PORT = support.bind_port(self.serv)
Charles-François Natali6e204602014-07-23 19:28:13 +0100974 self.serv.listen()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000975
976 def tearDown(self):
977 self.serv.close()
978 self.serv = None
979
980 def testTimeoutAttribute(self):
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000981 # This will prove that the timeout gets through HTTPConnection
982 # and into the socket.
983
Georg Brandlf78e02b2008-06-10 17:40:04 +0000984 # default -- use global socket timeout
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +0200985 self.assertIsNone(socket.getdefaulttimeout())
Georg Brandlf78e02b2008-06-10 17:40:04 +0000986 socket.setdefaulttimeout(30)
987 try:
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000988 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000989 httpConn.connect()
990 finally:
991 socket.setdefaulttimeout(None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000992 self.assertEqual(httpConn.sock.gettimeout(), 30)
993 httpConn.close()
994
Georg Brandlf78e02b2008-06-10 17:40:04 +0000995 # no timeout -- do not use global socket default
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +0200996 self.assertIsNone(socket.getdefaulttimeout())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000997 socket.setdefaulttimeout(30)
998 try:
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000999 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT,
Christian Heimes5e696852008-04-09 08:37:03 +00001000 timeout=None)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001001 httpConn.connect()
1002 finally:
Georg Brandlf78e02b2008-06-10 17:40:04 +00001003 socket.setdefaulttimeout(None)
1004 self.assertEqual(httpConn.sock.gettimeout(), None)
1005 httpConn.close()
1006
1007 # a value
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001008 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
Georg Brandlf78e02b2008-06-10 17:40:04 +00001009 httpConn.connect()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001010 self.assertEqual(httpConn.sock.gettimeout(), 30)
1011 httpConn.close()
1012
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001013
1014class HTTPSTest(TestCase):
1015
1016 def setUp(self):
1017 if not hasattr(client, 'HTTPSConnection'):
1018 self.skipTest('ssl support required')
1019
1020 def make_server(self, certfile):
1021 from test.ssl_servers import make_https_server
Antoine Pitrouda232592013-02-05 21:20:51 +01001022 return make_https_server(self, certfile=certfile)
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001023
1024 def test_attributes(self):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001025 # simple test to check it's storing the timeout
1026 h = client.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
1027 self.assertEqual(h.timeout, 30)
1028
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001029 def test_networked(self):
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001030 # Default settings: requires a valid cert from a trusted CA
1031 import ssl
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001032 support.requires('network')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001033 with support.transient_internet('self-signed.pythontest.net'):
1034 h = client.HTTPSConnection('self-signed.pythontest.net', 443)
1035 with self.assertRaises(ssl.SSLError) as exc_info:
1036 h.request('GET', '/')
1037 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
1038
1039 def test_networked_noverification(self):
1040 # Switch off cert verification
1041 import ssl
1042 support.requires('network')
1043 with support.transient_internet('self-signed.pythontest.net'):
1044 context = ssl._create_unverified_context()
1045 h = client.HTTPSConnection('self-signed.pythontest.net', 443,
1046 context=context)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001047 h.request('GET', '/')
1048 resp = h.getresponse()
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001049 self.assertIn('nginx', resp.getheader('server'))
1050
Benjamin Peterson2615e9e2014-11-25 15:16:55 -06001051 @support.system_must_validate_cert
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001052 def test_networked_trusted_by_default_cert(self):
1053 # Default settings: requires a valid cert from a trusted CA
1054 support.requires('network')
1055 with support.transient_internet('www.python.org'):
1056 h = client.HTTPSConnection('www.python.org', 443)
1057 h.request('GET', '/')
1058 resp = h.getresponse()
1059 content_type = resp.getheader('content-type')
1060 self.assertIn('text/html', content_type)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001061
1062 def test_networked_good_cert(self):
Georg Brandlfbaf9312014-11-05 20:37:40 +01001063 # We feed the server's cert as a validating cert
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001064 import ssl
1065 support.requires('network')
Georg Brandlfbaf9312014-11-05 20:37:40 +01001066 with support.transient_internet('self-signed.pythontest.net'):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001067 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1068 context.verify_mode = ssl.CERT_REQUIRED
Georg Brandlfbaf9312014-11-05 20:37:40 +01001069 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
1070 h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001071 h.request('GET', '/')
1072 resp = h.getresponse()
Georg Brandlfbaf9312014-11-05 20:37:40 +01001073 server_string = resp.getheader('server')
1074 self.assertIn('nginx', server_string)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001075
1076 def test_networked_bad_cert(self):
1077 # We feed a "CA" cert that is unrelated to the server's cert
1078 import ssl
1079 support.requires('network')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001080 with support.transient_internet('self-signed.pythontest.net'):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001081 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1082 context.verify_mode = ssl.CERT_REQUIRED
1083 context.load_verify_locations(CERT_localhost)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001084 h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
1085 with self.assertRaises(ssl.SSLError) as exc_info:
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001086 h.request('GET', '/')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001087 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
1088
1089 def test_local_unknown_cert(self):
1090 # The custom cert isn't known to the default trust bundle
1091 import ssl
1092 server = self.make_server(CERT_localhost)
1093 h = client.HTTPSConnection('localhost', server.port)
1094 with self.assertRaises(ssl.SSLError) as exc_info:
1095 h.request('GET', '/')
1096 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001097
1098 def test_local_good_hostname(self):
1099 # The (valid) cert validates the HTTP hostname
1100 import ssl
Brett Cannon252365b2011-08-04 22:43:11 -07001101 server = self.make_server(CERT_localhost)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001102 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1103 context.verify_mode = ssl.CERT_REQUIRED
1104 context.load_verify_locations(CERT_localhost)
1105 h = client.HTTPSConnection('localhost', server.port, context=context)
1106 h.request('GET', '/nonexistent')
1107 resp = h.getresponse()
1108 self.assertEqual(resp.status, 404)
1109
1110 def test_local_bad_hostname(self):
1111 # The (valid) cert doesn't validate the HTTP hostname
1112 import ssl
Brett Cannon252365b2011-08-04 22:43:11 -07001113 server = self.make_server(CERT_fakehostname)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001114 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1115 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Petersona090f012014-12-07 13:18:25 -05001116 context.check_hostname = True
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001117 context.load_verify_locations(CERT_fakehostname)
1118 h = client.HTTPSConnection('localhost', server.port, context=context)
1119 with self.assertRaises(ssl.CertificateError):
1120 h.request('GET', '/')
1121 # Same with explicit check_hostname=True
1122 h = client.HTTPSConnection('localhost', server.port, context=context,
1123 check_hostname=True)
1124 with self.assertRaises(ssl.CertificateError):
1125 h.request('GET', '/')
1126 # With check_hostname=False, the mismatching is ignored
Benjamin Petersona090f012014-12-07 13:18:25 -05001127 context.check_hostname = False
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001128 h = client.HTTPSConnection('localhost', server.port, context=context,
1129 check_hostname=False)
1130 h.request('GET', '/nonexistent')
1131 resp = h.getresponse()
1132 self.assertEqual(resp.status, 404)
Benjamin Petersona090f012014-12-07 13:18:25 -05001133 # The context's check_hostname setting is used if one isn't passed to
1134 # HTTPSConnection.
1135 context.check_hostname = False
1136 h = client.HTTPSConnection('localhost', server.port, context=context)
1137 h.request('GET', '/nonexistent')
1138 self.assertEqual(h.getresponse().status, 404)
1139 # Passing check_hostname to HTTPSConnection should override the
1140 # context's setting.
1141 h = client.HTTPSConnection('localhost', server.port, context=context,
1142 check_hostname=True)
1143 with self.assertRaises(ssl.CertificateError):
1144 h.request('GET', '/')
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001145
Petri Lehtinene119c402011-10-26 21:29:15 +03001146 @unittest.skipIf(not hasattr(client, 'HTTPSConnection'),
1147 'http.client.HTTPSConnection not available')
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +02001148 def test_host_port(self):
1149 # Check invalid host_port
1150
1151 for hp in ("www.python.org:abc", "user:password@www.python.org"):
1152 self.assertRaises(client.InvalidURL, client.HTTPSConnection, hp)
1153
1154 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
1155 "fe80::207:e9ff:fe9b", 8000),
1156 ("www.python.org:443", "www.python.org", 443),
1157 ("www.python.org:", "www.python.org", 443),
1158 ("www.python.org", "www.python.org", 443),
1159 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
1160 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
1161 443)):
1162 c = client.HTTPSConnection(hp)
1163 self.assertEqual(h, c.host)
1164 self.assertEqual(p, c.port)
1165
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001166
Jeremy Hylton236654b2009-03-27 20:24:34 +00001167class RequestBodyTest(TestCase):
1168 """Test cases where a request includes a message body."""
1169
1170 def setUp(self):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001171 self.conn = client.HTTPConnection('example.com')
Jeremy Hylton636950f2009-03-28 04:34:21 +00001172 self.conn.sock = self.sock = FakeSocket("")
Jeremy Hylton236654b2009-03-27 20:24:34 +00001173 self.conn.sock = self.sock
1174
1175 def get_headers_and_fp(self):
1176 f = io.BytesIO(self.sock.data)
1177 f.readline() # read the request line
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001178 message = client.parse_headers(f)
Jeremy Hylton236654b2009-03-27 20:24:34 +00001179 return message, f
1180
1181 def test_manual_content_length(self):
1182 # Set an incorrect content-length so that we can verify that
1183 # it will not be over-ridden by the library.
1184 self.conn.request("PUT", "/url", "body",
1185 {"Content-Length": "42"})
1186 message, f = self.get_headers_and_fp()
1187 self.assertEqual("42", message.get("content-length"))
1188 self.assertEqual(4, len(f.read()))
1189
1190 def test_ascii_body(self):
1191 self.conn.request("PUT", "/url", "body")
1192 message, f = self.get_headers_and_fp()
1193 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001194 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001195 self.assertEqual("4", message.get("content-length"))
1196 self.assertEqual(b'body', f.read())
1197
1198 def test_latin1_body(self):
1199 self.conn.request("PUT", "/url", "body\xc1")
1200 message, f = self.get_headers_and_fp()
1201 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001202 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001203 self.assertEqual("5", message.get("content-length"))
1204 self.assertEqual(b'body\xc1', f.read())
1205
1206 def test_bytes_body(self):
1207 self.conn.request("PUT", "/url", b"body\xc1")
1208 message, f = self.get_headers_and_fp()
1209 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001210 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001211 self.assertEqual("5", message.get("content-length"))
1212 self.assertEqual(b'body\xc1', f.read())
1213
1214 def test_file_body(self):
Victor Stinner18d15cb2011-09-21 01:09:04 +02001215 self.addCleanup(support.unlink, support.TESTFN)
Brett Cannon77b7de62010-10-29 23:31:11 +00001216 with open(support.TESTFN, "w") as f:
1217 f.write("body")
1218 with open(support.TESTFN) as f:
1219 self.conn.request("PUT", "/url", f)
1220 message, f = self.get_headers_and_fp()
1221 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001222 self.assertIsNone(message.get_charset())
Brett Cannon77b7de62010-10-29 23:31:11 +00001223 self.assertEqual("4", message.get("content-length"))
1224 self.assertEqual(b'body', f.read())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001225
1226 def test_binary_file_body(self):
Victor Stinner18d15cb2011-09-21 01:09:04 +02001227 self.addCleanup(support.unlink, support.TESTFN)
Brett Cannon77b7de62010-10-29 23:31:11 +00001228 with open(support.TESTFN, "wb") as f:
1229 f.write(b"body\xc1")
1230 with open(support.TESTFN, "rb") as f:
1231 self.conn.request("PUT", "/url", f)
1232 message, f = self.get_headers_and_fp()
1233 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001234 self.assertIsNone(message.get_charset())
Brett Cannon77b7de62010-10-29 23:31:11 +00001235 self.assertEqual("5", message.get("content-length"))
1236 self.assertEqual(b'body\xc1', f.read())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001237
Senthil Kumaran9f8dc442010-08-02 11:04:58 +00001238
1239class HTTPResponseTest(TestCase):
1240
1241 def setUp(self):
1242 body = "HTTP/1.1 200 Ok\r\nMy-Header: first-value\r\nMy-Header: \
1243 second-value\r\n\r\nText"
1244 sock = FakeSocket(body)
1245 self.resp = client.HTTPResponse(sock)
1246 self.resp.begin()
1247
1248 def test_getting_header(self):
1249 header = self.resp.getheader('My-Header')
1250 self.assertEqual(header, 'first-value, second-value')
1251
1252 header = self.resp.getheader('My-Header', 'some default')
1253 self.assertEqual(header, 'first-value, second-value')
1254
1255 def test_getting_nonexistent_header_with_string_default(self):
1256 header = self.resp.getheader('No-Such-Header', 'default-value')
1257 self.assertEqual(header, 'default-value')
1258
1259 def test_getting_nonexistent_header_with_iterable_default(self):
1260 header = self.resp.getheader('No-Such-Header', ['default', 'values'])
1261 self.assertEqual(header, 'default, values')
1262
1263 header = self.resp.getheader('No-Such-Header', ('default', 'values'))
1264 self.assertEqual(header, 'default, values')
1265
1266 def test_getting_nonexistent_header_without_default(self):
1267 header = self.resp.getheader('No-Such-Header')
1268 self.assertEqual(header, None)
1269
1270 def test_getting_header_defaultint(self):
1271 header = self.resp.getheader('No-Such-Header',default=42)
1272 self.assertEqual(header, 42)
1273
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001274class TunnelTests(TestCase):
1275
1276 def test_connect(self):
1277 response_text = (
1278 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
1279 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
1280 'Content-Length: 42\r\n\r\n'
1281 )
1282
1283 def create_connection(address, timeout=None, source_address=None):
1284 return FakeSocket(response_text, host=address[0],
1285 port=address[1])
1286
1287 conn = client.HTTPConnection('proxy.com')
1288 conn._create_connection = create_connection
1289
1290 # Once connected, we shouldn't be able to tunnel anymore
1291 conn.connect()
1292 self.assertRaises(RuntimeError, conn.set_tunnel,
1293 'destination.com')
1294
1295 # But if we close the connection, we're good
1296 conn.close()
1297 conn.set_tunnel('destination.com')
1298 conn.request('HEAD', '/', '')
1299
1300 self.assertEqual(conn.sock.host, 'proxy.com')
1301 self.assertEqual(conn.sock.port, 80)
Serhiy Storchaka4ac7ed92014-12-12 09:29:15 +02001302 self.assertIn(b'CONNECT destination.com', conn.sock.data)
1303 # issue22095
1304 self.assertNotIn(b'Host: destination.com:None', conn.sock.data)
1305 self.assertIn(b'Host: destination.com', conn.sock.data)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001306
1307 # This test should be removed when CONNECT gets the HTTP/1.1 blessing
Serhiy Storchaka4ac7ed92014-12-12 09:29:15 +02001308 self.assertNotIn(b'Host: proxy.com', conn.sock.data)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001309
1310 conn.close()
1311 conn.request('PUT', '/', '')
1312 self.assertEqual(conn.sock.host, 'proxy.com')
1313 self.assertEqual(conn.sock.port, 80)
1314 self.assertTrue(b'CONNECT destination.com' in conn.sock.data)
1315 self.assertTrue(b'Host: destination.com' in conn.sock.data)
1316
Benjamin Peterson9566de12014-12-13 16:13:24 -05001317@support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +00001318def test_main(verbose=None):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001319 support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001320 HTTPSTest, RequestBodyTest, SourceAddressTest,
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +00001321 HTTPResponseTest, ExtendedReadTest,
Senthil Kumaran166214c2014-04-14 13:10:05 -04001322 ExtendedReadTestChunked, TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +00001323
Thomas Wouters89f507f2006-12-13 04:49:30 +00001324if __name__ == '__main__':
1325 test_main()