blob: 08efa19d80644fea9f9c1ff21bd8d44e8ebeb634 [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
Benjamin Peterson9d8a3ad2015-01-23 11:02:57 -050073 def setsockopt(self, level, optname, value):
74 pass
75
Jeremy Hylton636950f2009-03-28 04:34:21 +000076class EPipeSocket(FakeSocket):
77
78 def __init__(self, text, pipe_trigger):
79 # When sendall() is called with pipe_trigger, raise EPIPE.
80 FakeSocket.__init__(self, text)
81 self.pipe_trigger = pipe_trigger
82
83 def sendall(self, data):
84 if self.pipe_trigger in data:
Andrew Svetlov0832af62012-12-18 23:10:48 +020085 raise OSError(errno.EPIPE, "gotcha")
Jeremy Hylton636950f2009-03-28 04:34:21 +000086 self.data += data
87
88 def close(self):
89 pass
90
Serhiy Storchaka50254c52013-08-29 11:35:43 +030091class NoEOFBytesIO(io.BytesIO):
92 """Like BytesIO, but raises AssertionError on EOF.
Jeremy Hylton121d34a2003-07-08 12:36:58 +000093
Jeremy Hylton7c1692d2009-03-27 21:31:03 +000094 This is used below to test that http.client doesn't try to read
Jeremy Hylton121d34a2003-07-08 12:36:58 +000095 more from the underlying file than it should.
96 """
97 def read(self, n=-1):
Jeremy Hylton8fff7922007-08-03 20:56:14 +000098 data = io.BytesIO.read(self, n)
Jeremy Hyltonda3f2282007-08-29 17:26:34 +000099 if data == b'':
Jeremy Hylton121d34a2003-07-08 12:36:58 +0000100 raise AssertionError('caller tried to read past EOF')
101 return data
102
103 def readline(self, length=None):
Jeremy Hylton8fff7922007-08-03 20:56:14 +0000104 data = io.BytesIO.readline(self, length)
Jeremy Hyltonda3f2282007-08-29 17:26:34 +0000105 if data == b'':
Jeremy Hylton121d34a2003-07-08 12:36:58 +0000106 raise AssertionError('caller tried to read past EOF')
107 return data
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000108
Jeremy Hylton2c178252004-08-07 16:28:14 +0000109class HeaderTests(TestCase):
110 def test_auto_headers(self):
111 # Some headers are added automatically, but should not be added by
112 # .request() if they are explicitly set.
113
Jeremy Hylton2c178252004-08-07 16:28:14 +0000114 class HeaderCountingBuffer(list):
115 def __init__(self):
116 self.count = {}
117 def append(self, item):
Guido van Rossum022c4742007-08-29 02:00:20 +0000118 kv = item.split(b':')
Jeremy Hylton2c178252004-08-07 16:28:14 +0000119 if len(kv) > 1:
120 # item is a 'Key: Value' header string
Martin v. Löwisdd5a8602007-06-30 09:22:09 +0000121 lcKey = kv[0].decode('ascii').lower()
Jeremy Hylton2c178252004-08-07 16:28:14 +0000122 self.count.setdefault(lcKey, 0)
123 self.count[lcKey] += 1
124 list.append(self, item)
125
126 for explicit_header in True, False:
127 for header in 'Content-length', 'Host', 'Accept-encoding':
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000128 conn = client.HTTPConnection('example.com')
Jeremy Hylton2c178252004-08-07 16:28:14 +0000129 conn.sock = FakeSocket('blahblahblah')
130 conn._buffer = HeaderCountingBuffer()
131
132 body = 'spamspamspam'
133 headers = {}
134 if explicit_header:
135 headers[header] = str(len(body))
136 conn.request('POST', '/', body, headers)
137 self.assertEqual(conn._buffer.count[header.lower()], 1)
138
Senthil Kumaran5fa4a892012-05-19 16:58:09 +0800139 def test_content_length_0(self):
140
141 class ContentLengthChecker(list):
142 def __init__(self):
143 list.__init__(self)
144 self.content_length = None
145 def append(self, item):
146 kv = item.split(b':', 1)
147 if len(kv) > 1 and kv[0].lower() == b'content-length':
148 self.content_length = kv[1].strip()
149 list.append(self, item)
150
151 # POST with empty body
152 conn = client.HTTPConnection('example.com')
153 conn.sock = FakeSocket(None)
154 conn._buffer = ContentLengthChecker()
155 conn.request('POST', '/', '')
156 self.assertEqual(conn._buffer.content_length, b'0',
157 'Header Content-Length not set')
158
159 # PUT request with empty body
160 conn = client.HTTPConnection('example.com')
161 conn.sock = FakeSocket(None)
162 conn._buffer = ContentLengthChecker()
163 conn.request('PUT', '/', '')
164 self.assertEqual(conn._buffer.content_length, b'0',
165 'Header Content-Length not set')
166
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000167 def test_putheader(self):
168 conn = client.HTTPConnection('example.com')
169 conn.sock = FakeSocket(None)
170 conn.putrequest('GET','/')
171 conn.putheader('Content-length', 42)
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +0200172 self.assertIn(b'Content-length: 42', conn._buffer)
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000173
Senthil Kumaran74ebd9e2010-11-13 12:27:49 +0000174 def test_ipv6host_header(self):
175 # Default host header on IPv6 transaction should wrapped by [] if
176 # its actual IPv6 address
177 expected = b'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
178 b'Accept-Encoding: identity\r\n\r\n'
179 conn = client.HTTPConnection('[2001::]:81')
180 sock = FakeSocket('')
181 conn.sock = sock
182 conn.request('GET', '/foo')
183 self.assertTrue(sock.data.startswith(expected))
184
185 expected = b'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
186 b'Accept-Encoding: identity\r\n\r\n'
187 conn = client.HTTPConnection('[2001:102A::]')
188 sock = FakeSocket('')
189 conn.sock = sock
190 conn.request('GET', '/foo')
191 self.assertTrue(sock.data.startswith(expected))
192
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000193
Thomas Wouters89f507f2006-12-13 04:49:30 +0000194class BasicTest(TestCase):
195 def test_status_lines(self):
196 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000197
Thomas Wouters89f507f2006-12-13 04:49:30 +0000198 body = "HTTP/1.1 200 Ok\r\n\r\nText"
199 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000200 resp = client.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000201 resp.begin()
Serhiy Storchaka1c84ac12013-12-17 21:50:02 +0200202 self.assertEqual(resp.read(0), b'') # Issue #20007
203 self.assertFalse(resp.isclosed())
204 self.assertFalse(resp.closed)
Jeremy Hylton8fff7922007-08-03 20:56:14 +0000205 self.assertEqual(resp.read(), b"Text")
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000206 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200207 self.assertFalse(resp.closed)
208 resp.close()
209 self.assertTrue(resp.closed)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000210
Thomas Wouters89f507f2006-12-13 04:49:30 +0000211 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
212 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000213 resp = client.HTTPResponse(sock)
214 self.assertRaises(client.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000215
Benjamin Peterson11dbfd42010-03-21 22:50:04 +0000216 def test_bad_status_repr(self):
217 exc = client.BadStatusLine('')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000218 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Benjamin Peterson11dbfd42010-03-21 22:50:04 +0000219
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000220 def test_partial_reads(self):
Antoine Pitrou084daa22012-12-15 19:11:54 +0100221 # if we have a length, the system knows when to close itself
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000222 # same behaviour than when we read the whole thing with read()
223 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
224 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000225 resp = client.HTTPResponse(sock)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000226 resp.begin()
227 self.assertEqual(resp.read(2), b'Te')
228 self.assertFalse(resp.isclosed())
229 self.assertEqual(resp.read(2), b'xt')
230 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200231 self.assertFalse(resp.closed)
232 resp.close()
233 self.assertTrue(resp.closed)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000234
Antoine Pitrou38d96432011-12-06 22:33:57 +0100235 def test_partial_readintos(self):
Antoine Pitroud20e7742012-12-15 19:22:30 +0100236 # if we have a length, the system knows when to close itself
Antoine Pitrou38d96432011-12-06 22:33:57 +0100237 # same behaviour than when we read the whole thing with read()
238 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
239 sock = FakeSocket(body)
240 resp = client.HTTPResponse(sock)
241 resp.begin()
242 b = bytearray(2)
243 n = resp.readinto(b)
244 self.assertEqual(n, 2)
245 self.assertEqual(bytes(b), b'Te')
246 self.assertFalse(resp.isclosed())
247 n = resp.readinto(b)
248 self.assertEqual(n, 2)
249 self.assertEqual(bytes(b), b'xt')
250 self.assertTrue(resp.isclosed())
Serhiy Storchakab6c86fd2013-02-06 10:35:40 +0200251 self.assertFalse(resp.closed)
252 resp.close()
253 self.assertTrue(resp.closed)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100254
Antoine Pitrou084daa22012-12-15 19:11:54 +0100255 def test_partial_reads_no_content_length(self):
256 # when no length is present, the socket should be gracefully closed when
257 # all data was read
258 body = "HTTP/1.1 200 Ok\r\n\r\nText"
259 sock = FakeSocket(body)
260 resp = client.HTTPResponse(sock)
261 resp.begin()
262 self.assertEqual(resp.read(2), b'Te')
263 self.assertFalse(resp.isclosed())
264 self.assertEqual(resp.read(2), b'xt')
265 self.assertEqual(resp.read(1), b'')
266 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200267 self.assertFalse(resp.closed)
268 resp.close()
269 self.assertTrue(resp.closed)
Antoine Pitrou084daa22012-12-15 19:11:54 +0100270
Antoine Pitroud20e7742012-12-15 19:22:30 +0100271 def test_partial_readintos_no_content_length(self):
272 # when no length is present, the socket should be gracefully closed when
273 # all data was read
274 body = "HTTP/1.1 200 Ok\r\n\r\nText"
275 sock = FakeSocket(body)
276 resp = client.HTTPResponse(sock)
277 resp.begin()
278 b = bytearray(2)
279 n = resp.readinto(b)
280 self.assertEqual(n, 2)
281 self.assertEqual(bytes(b), b'Te')
282 self.assertFalse(resp.isclosed())
283 n = resp.readinto(b)
284 self.assertEqual(n, 2)
285 self.assertEqual(bytes(b), b'xt')
286 n = resp.readinto(b)
287 self.assertEqual(n, 0)
288 self.assertTrue(resp.isclosed())
289
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100290 def test_partial_reads_incomplete_body(self):
291 # if the server shuts down the connection before the whole
292 # content-length is delivered, the socket is gracefully closed
293 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
294 sock = FakeSocket(body)
295 resp = client.HTTPResponse(sock)
296 resp.begin()
297 self.assertEqual(resp.read(2), b'Te')
298 self.assertFalse(resp.isclosed())
299 self.assertEqual(resp.read(2), b'xt')
300 self.assertEqual(resp.read(1), b'')
301 self.assertTrue(resp.isclosed())
302
Antoine Pitrou6a35e182013-02-02 23:04:56 +0100303 def test_partial_readintos_incomplete_body(self):
304 # if the server shuts down the connection before the whole
305 # content-length is delivered, the socket is gracefully closed
306 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
307 sock = FakeSocket(body)
308 resp = client.HTTPResponse(sock)
309 resp.begin()
310 b = bytearray(2)
311 n = resp.readinto(b)
312 self.assertEqual(n, 2)
313 self.assertEqual(bytes(b), b'Te')
314 self.assertFalse(resp.isclosed())
315 n = resp.readinto(b)
316 self.assertEqual(n, 2)
317 self.assertEqual(bytes(b), b'xt')
318 n = resp.readinto(b)
319 self.assertEqual(n, 0)
320 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200321 self.assertFalse(resp.closed)
322 resp.close()
323 self.assertTrue(resp.closed)
Antoine Pitrou6a35e182013-02-02 23:04:56 +0100324
Thomas Wouters89f507f2006-12-13 04:49:30 +0000325 def test_host_port(self):
326 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000327
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200328 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000329 self.assertRaises(client.InvalidURL, client.HTTPConnection, hp)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000330
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000331 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
332 "fe80::207:e9ff:fe9b", 8000),
Thomas Wouters89f507f2006-12-13 04:49:30 +0000333 ("www.python.org:80", "www.python.org", 80),
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200334 ("www.python.org:", "www.python.org", 80),
Thomas Wouters89f507f2006-12-13 04:49:30 +0000335 ("www.python.org", "www.python.org", 80),
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200336 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80),
337 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", 80)):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000338 c = client.HTTPConnection(hp)
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000339 self.assertEqual(h, c.host)
340 self.assertEqual(p, c.port)
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000341
Thomas Wouters89f507f2006-12-13 04:49:30 +0000342 def test_response_headers(self):
343 # test response with multiple message headers with the same field name.
344 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000345 'Set-Cookie: Customer="WILE_E_COYOTE"; '
346 'Version="1"; Path="/acme"\r\n'
Thomas Wouters89f507f2006-12-13 04:49:30 +0000347 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
348 ' Path="/acme"\r\n'
349 '\r\n'
350 'No body\r\n')
351 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
352 ', '
353 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
354 s = FakeSocket(text)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000355 r = client.HTTPResponse(s)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000356 r.begin()
357 cookies = r.getheader("Set-Cookie")
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000358 self.assertEqual(cookies, hdr)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000359
Thomas Wouters89f507f2006-12-13 04:49:30 +0000360 def test_read_head(self):
361 # Test that the library doesn't attempt to read any data
362 # from a HEAD request. (Tickles SF bug #622042.)
363 sock = FakeSocket(
364 'HTTP/1.1 200 OK\r\n'
365 'Content-Length: 14432\r\n'
366 '\r\n',
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300367 NoEOFBytesIO)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000368 resp = client.HTTPResponse(sock, method="HEAD")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000369 resp.begin()
Guido van Rossuma00f1232007-09-12 19:43:09 +0000370 if resp.read():
Thomas Wouters89f507f2006-12-13 04:49:30 +0000371 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000372
Antoine Pitrou38d96432011-12-06 22:33:57 +0100373 def test_readinto_head(self):
374 # Test that the library doesn't attempt to read any data
375 # from a HEAD request. (Tickles SF bug #622042.)
376 sock = FakeSocket(
377 'HTTP/1.1 200 OK\r\n'
378 'Content-Length: 14432\r\n'
379 '\r\n',
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300380 NoEOFBytesIO)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100381 resp = client.HTTPResponse(sock, method="HEAD")
382 resp.begin()
383 b = bytearray(5)
384 if resp.readinto(b) != 0:
385 self.fail("Did not expect response from HEAD request")
386 self.assertEqual(bytes(b), b'\x00'*5)
387
Georg Brandlbf3f8eb2013-10-27 07:34:48 +0100388 def test_too_many_headers(self):
389 headers = '\r\n'.join('Header%d: foo' % i
390 for i in range(client._MAXHEADERS + 1)) + '\r\n'
391 text = ('HTTP/1.1 200 OK\r\n' + headers)
392 s = FakeSocket(text)
393 r = client.HTTPResponse(s)
394 self.assertRaisesRegex(client.HTTPException,
395 r"got more than \d+ headers", r.begin)
396
Thomas Wouters89f507f2006-12-13 04:49:30 +0000397 def test_send_file(self):
Guido van Rossum022c4742007-08-29 02:00:20 +0000398 expected = (b'GET /foo HTTP/1.1\r\nHost: example.com\r\n'
399 b'Accept-Encoding: identity\r\nContent-Length:')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000400
Brett Cannon77b7de62010-10-29 23:31:11 +0000401 with open(__file__, 'rb') as body:
402 conn = client.HTTPConnection('example.com')
403 sock = FakeSocket(body)
404 conn.sock = sock
405 conn.request('GET', '/foo', body)
406 self.assertTrue(sock.data.startswith(expected), '%r != %r' %
407 (sock.data[:len(expected)], expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000408
Antoine Pitrouead1d622009-09-29 18:44:53 +0000409 def test_send(self):
410 expected = b'this is a test this is only a test'
411 conn = client.HTTPConnection('example.com')
412 sock = FakeSocket(None)
413 conn.sock = sock
414 conn.send(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(array.array('b', expected))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000418 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000419 sock.data = b''
420 conn.send(io.BytesIO(expected))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000421 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000422
Andrew Svetlov7b2c8bb2013-04-12 22:49:19 +0300423 def test_send_updating_file(self):
424 def data():
425 yield 'data'
426 yield None
427 yield 'data_two'
428
429 class UpdatingFile():
430 mode = 'r'
431 d = data()
432 def read(self, blocksize=-1):
433 return self.d.__next__()
434
435 expected = b'data'
436
437 conn = client.HTTPConnection('example.com')
438 sock = FakeSocket("")
439 conn.sock = sock
440 conn.send(UpdatingFile())
441 self.assertEqual(sock.data, expected)
442
443
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000444 def test_send_iter(self):
445 expected = b'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
446 b'Accept-Encoding: identity\r\nContent-Length: 11\r\n' \
447 b'\r\nonetwothree'
448
449 def body():
450 yield b"one"
451 yield b"two"
452 yield b"three"
453
454 conn = client.HTTPConnection('example.com')
455 sock = FakeSocket("")
456 conn.sock = sock
457 conn.request('GET', '/foo', body(), {'Content-Length': '11'})
Victor Stinner04ba9662011-01-04 00:04:46 +0000458 self.assertEqual(sock.data, expected)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000459
Senthil Kumaraneb71ad42011-08-02 18:33:41 +0800460 def test_send_type_error(self):
461 # See: Issue #12676
462 conn = client.HTTPConnection('example.com')
463 conn.sock = FakeSocket('')
464 with self.assertRaises(TypeError):
465 conn.request('POST', 'test', conn)
466
Christian Heimesa612dc02008-02-24 13:08:18 +0000467 def test_chunked(self):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000468 expected = chunked_expected
469 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000470 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000471 resp.begin()
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100472 self.assertEqual(resp.read(), expected)
Christian Heimesa612dc02008-02-24 13:08:18 +0000473 resp.close()
474
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100475 # Various read sizes
476 for n in range(1, 12):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000477 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100478 resp = client.HTTPResponse(sock, method="GET")
479 resp.begin()
480 self.assertEqual(resp.read(n) + resp.read(n) + resp.read(), expected)
481 resp.close()
482
Christian Heimesa612dc02008-02-24 13:08:18 +0000483 for x in ('', 'foo\r\n'):
484 sock = FakeSocket(chunked_start + x)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000485 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000486 resp.begin()
487 try:
488 resp.read()
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000489 except client.IncompleteRead as i:
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100490 self.assertEqual(i.partial, expected)
491 expected_message = 'IncompleteRead(%d bytes read)' % len(expected)
492 self.assertEqual(repr(i), expected_message)
493 self.assertEqual(str(i), expected_message)
Christian Heimesa612dc02008-02-24 13:08:18 +0000494 else:
495 self.fail('IncompleteRead expected')
496 finally:
497 resp.close()
498
Antoine Pitrou38d96432011-12-06 22:33:57 +0100499 def test_readinto_chunked(self):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000500
501 expected = chunked_expected
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100502 nexpected = len(expected)
503 b = bytearray(128)
504
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000505 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100506 resp = client.HTTPResponse(sock, method="GET")
507 resp.begin()
Antoine Pitrou38d96432011-12-06 22:33:57 +0100508 n = resp.readinto(b)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100509 self.assertEqual(b[:nexpected], expected)
510 self.assertEqual(n, nexpected)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100511 resp.close()
512
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100513 # Various read sizes
514 for n in range(1, 12):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000515 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100516 resp = client.HTTPResponse(sock, method="GET")
517 resp.begin()
518 m = memoryview(b)
519 i = resp.readinto(m[0:n])
520 i += resp.readinto(m[i:n + i])
521 i += resp.readinto(m[i:])
522 self.assertEqual(b[:nexpected], expected)
523 self.assertEqual(i, nexpected)
524 resp.close()
525
Antoine Pitrou38d96432011-12-06 22:33:57 +0100526 for x in ('', 'foo\r\n'):
527 sock = FakeSocket(chunked_start + x)
528 resp = client.HTTPResponse(sock, method="GET")
529 resp.begin()
530 try:
Antoine Pitrou38d96432011-12-06 22:33:57 +0100531 n = resp.readinto(b)
532 except client.IncompleteRead as i:
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100533 self.assertEqual(i.partial, expected)
534 expected_message = 'IncompleteRead(%d bytes read)' % len(expected)
535 self.assertEqual(repr(i), expected_message)
536 self.assertEqual(str(i), expected_message)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100537 else:
538 self.fail('IncompleteRead expected')
539 finally:
540 resp.close()
541
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000542 def test_chunked_head(self):
543 chunked_start = (
544 'HTTP/1.1 200 OK\r\n'
545 'Transfer-Encoding: chunked\r\n\r\n'
546 'a\r\n'
547 'hello world\r\n'
548 '1\r\n'
549 'd\r\n'
550 )
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000551 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000552 resp = client.HTTPResponse(sock, method="HEAD")
553 resp.begin()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000554 self.assertEqual(resp.read(), b'')
555 self.assertEqual(resp.status, 200)
556 self.assertEqual(resp.reason, 'OK')
Senthil Kumaran0b998832010-06-04 17:27:11 +0000557 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200558 self.assertFalse(resp.closed)
559 resp.close()
560 self.assertTrue(resp.closed)
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000561
Antoine Pitrou38d96432011-12-06 22:33:57 +0100562 def test_readinto_chunked_head(self):
563 chunked_start = (
564 'HTTP/1.1 200 OK\r\n'
565 'Transfer-Encoding: chunked\r\n\r\n'
566 'a\r\n'
567 'hello world\r\n'
568 '1\r\n'
569 'd\r\n'
570 )
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000571 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100572 resp = client.HTTPResponse(sock, method="HEAD")
573 resp.begin()
574 b = bytearray(5)
575 n = resp.readinto(b)
576 self.assertEqual(n, 0)
577 self.assertEqual(bytes(b), b'\x00'*5)
578 self.assertEqual(resp.status, 200)
579 self.assertEqual(resp.reason, 'OK')
580 self.assertTrue(resp.isclosed())
Serhiy Storchakab6c86fd2013-02-06 10:35:40 +0200581 self.assertFalse(resp.closed)
582 resp.close()
583 self.assertTrue(resp.closed)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100584
Christian Heimesa612dc02008-02-24 13:08:18 +0000585 def test_negative_content_length(self):
Jeremy Hylton82066952008-12-15 03:08:30 +0000586 sock = FakeSocket(
587 'HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\nHello\r\n')
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000588 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000589 resp.begin()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000590 self.assertEqual(resp.read(), b'Hello\r\n')
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100591 self.assertTrue(resp.isclosed())
Christian Heimesa612dc02008-02-24 13:08:18 +0000592
Benjamin Peterson6accb982009-03-02 22:50:25 +0000593 def test_incomplete_read(self):
594 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000595 resp = client.HTTPResponse(sock, method="GET")
Benjamin Peterson6accb982009-03-02 22:50:25 +0000596 resp.begin()
597 try:
598 resp.read()
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000599 except client.IncompleteRead as i:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000600 self.assertEqual(i.partial, b'Hello\r\n')
Benjamin Peterson6accb982009-03-02 22:50:25 +0000601 self.assertEqual(repr(i),
602 "IncompleteRead(7 bytes read, 3 more expected)")
603 self.assertEqual(str(i),
604 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100605 self.assertTrue(resp.isclosed())
Benjamin Peterson6accb982009-03-02 22:50:25 +0000606 else:
607 self.fail('IncompleteRead expected')
Benjamin Peterson6accb982009-03-02 22:50:25 +0000608
Jeremy Hylton636950f2009-03-28 04:34:21 +0000609 def test_epipe(self):
610 sock = EPipeSocket(
611 "HTTP/1.0 401 Authorization Required\r\n"
612 "Content-type: text/html\r\n"
613 "WWW-Authenticate: Basic realm=\"example\"\r\n",
614 b"Content-Length")
615 conn = client.HTTPConnection("example.com")
616 conn.sock = sock
Andrew Svetlov0832af62012-12-18 23:10:48 +0200617 self.assertRaises(OSError,
Jeremy Hylton636950f2009-03-28 04:34:21 +0000618 lambda: conn.request("PUT", "/url", "body"))
619 resp = conn.getresponse()
620 self.assertEqual(401, resp.status)
621 self.assertEqual("Basic realm=\"example\"",
622 resp.getheader("www-authenticate"))
Christian Heimesa612dc02008-02-24 13:08:18 +0000623
Senthil Kumaran5466bf12010-12-18 16:55:23 +0000624 # Test lines overflowing the max line size (_MAXLINE in http.client)
625
626 def test_overflowing_status_line(self):
627 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
628 resp = client.HTTPResponse(FakeSocket(body))
629 self.assertRaises((client.LineTooLong, client.BadStatusLine), resp.begin)
630
631 def test_overflowing_header_line(self):
632 body = (
633 'HTTP/1.1 200 OK\r\n'
634 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
635 )
636 resp = client.HTTPResponse(FakeSocket(body))
637 self.assertRaises(client.LineTooLong, resp.begin)
638
639 def test_overflowing_chunked_line(self):
640 body = (
641 'HTTP/1.1 200 OK\r\n'
642 'Transfer-Encoding: chunked\r\n\r\n'
643 + '0' * 65536 + 'a\r\n'
644 'hello world\r\n'
645 '0\r\n'
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000646 '\r\n'
Senthil Kumaran5466bf12010-12-18 16:55:23 +0000647 )
648 resp = client.HTTPResponse(FakeSocket(body))
649 resp.begin()
650 self.assertRaises(client.LineTooLong, resp.read)
651
Senthil Kumaran9c29f862012-04-29 10:20:46 +0800652 def test_early_eof(self):
653 # Test httpresponse with no \r\n termination,
654 body = "HTTP/1.1 200 Ok"
655 sock = FakeSocket(body)
656 resp = client.HTTPResponse(sock)
657 resp.begin()
658 self.assertEqual(resp.read(), b'')
659 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200660 self.assertFalse(resp.closed)
661 resp.close()
662 self.assertTrue(resp.closed)
Senthil Kumaran9c29f862012-04-29 10:20:46 +0800663
Serhiy Storchakab491e052014-12-01 13:07:45 +0200664 def test_error_leak(self):
665 # Test that the socket is not leaked if getresponse() fails
666 conn = client.HTTPConnection('example.com')
667 response = None
668 class Response(client.HTTPResponse):
669 def __init__(self, *pos, **kw):
670 nonlocal response
671 response = self # Avoid garbage collector closing the socket
672 client.HTTPResponse.__init__(self, *pos, **kw)
673 conn.response_class = Response
674 conn.sock = FakeSocket('') # Emulate server dropping connection
675 conn.request('GET', '/')
676 self.assertRaises(client.BadStatusLine, conn.getresponse)
677 self.assertTrue(response.closed)
678 self.assertTrue(conn.sock.file_closed)
679
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000680 def test_chunked_extension(self):
681 extra = '3;foo=bar\r\n' + 'abc\r\n'
682 expected = chunked_expected + b'abc'
683
684 sock = FakeSocket(chunked_start + extra + last_chunk_extended + chunked_end)
685 resp = client.HTTPResponse(sock, method="GET")
686 resp.begin()
687 self.assertEqual(resp.read(), expected)
688 resp.close()
689
690 def test_chunked_missing_end(self):
691 """some servers may serve up a short chunked encoding stream"""
692 expected = chunked_expected
693 sock = FakeSocket(chunked_start + last_chunk) #no terminating crlf
694 resp = client.HTTPResponse(sock, method="GET")
695 resp.begin()
696 self.assertEqual(resp.read(), expected)
697 resp.close()
698
699 def test_chunked_trailers(self):
700 """See that trailers are read and ignored"""
701 expected = chunked_expected
702 sock = FakeSocket(chunked_start + last_chunk + trailers + chunked_end)
703 resp = client.HTTPResponse(sock, method="GET")
704 resp.begin()
705 self.assertEqual(resp.read(), expected)
706 # we should have reached the end of the file
707 self.assertEqual(sock.file.read(100), b"") #we read to the end
708 resp.close()
709
710 def test_chunked_sync(self):
711 """Check that we don't read past the end of the chunked-encoding stream"""
712 expected = chunked_expected
713 extradata = "extradata"
714 sock = FakeSocket(chunked_start + last_chunk + trailers + chunked_end + extradata)
715 resp = client.HTTPResponse(sock, method="GET")
716 resp.begin()
717 self.assertEqual(resp.read(), expected)
718 # the file should now have our extradata ready to be read
719 self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end
720 resp.close()
721
722 def test_content_length_sync(self):
723 """Check that we don't read past the end of the Content-Length stream"""
724 extradata = "extradata"
725 expected = b"Hello123\r\n"
726 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello123\r\n' + extradata)
727 resp = client.HTTPResponse(sock, method="GET")
728 resp.begin()
729 self.assertEqual(resp.read(), expected)
730 # the file should now have our extradata ready to be read
731 self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end
732 resp.close()
733
734class ExtendedReadTest(TestCase):
735 """
736 Test peek(), read1(), readline()
737 """
738 lines = (
739 'HTTP/1.1 200 OK\r\n'
740 '\r\n'
741 'hello world!\n'
742 'and now \n'
743 'for something completely different\n'
744 'foo'
745 )
746 lines_expected = lines[lines.find('hello'):].encode("ascii")
747 lines_chunked = (
748 'HTTP/1.1 200 OK\r\n'
749 'Transfer-Encoding: chunked\r\n\r\n'
750 'a\r\n'
751 'hello worl\r\n'
752 '3\r\n'
753 'd!\n\r\n'
754 '9\r\n'
755 'and now \n\r\n'
756 '23\r\n'
757 'for something completely different\n\r\n'
758 '3\r\n'
759 'foo\r\n'
760 '0\r\n' # terminating chunk
761 '\r\n' # end of trailers
762 )
763
764 def setUp(self):
765 sock = FakeSocket(self.lines)
766 resp = client.HTTPResponse(sock, method="GET")
767 resp.begin()
768 resp.fp = io.BufferedReader(resp.fp)
769 self.resp = resp
770
771
772
773 def test_peek(self):
774 resp = self.resp
775 # patch up the buffered peek so that it returns not too much stuff
776 oldpeek = resp.fp.peek
777 def mypeek(n=-1):
778 p = oldpeek(n)
779 if n >= 0:
780 return p[:n]
781 return p[:10]
782 resp.fp.peek = mypeek
783
784 all = []
785 while True:
786 # try a short peek
787 p = resp.peek(3)
788 if p:
789 self.assertGreater(len(p), 0)
790 # then unbounded peek
791 p2 = resp.peek()
792 self.assertGreaterEqual(len(p2), len(p))
793 self.assertTrue(p2.startswith(p))
794 next = resp.read(len(p2))
795 self.assertEqual(next, p2)
796 else:
797 next = resp.read()
798 self.assertFalse(next)
799 all.append(next)
800 if not next:
801 break
802 self.assertEqual(b"".join(all), self.lines_expected)
803
804 def test_readline(self):
805 resp = self.resp
806 self._verify_readline(self.resp.readline, self.lines_expected)
807
808 def _verify_readline(self, readline, expected):
809 all = []
810 while True:
811 # short readlines
812 line = readline(5)
813 if line and line != b"foo":
814 if len(line) < 5:
815 self.assertTrue(line.endswith(b"\n"))
816 all.append(line)
817 if not line:
818 break
819 self.assertEqual(b"".join(all), expected)
820
821 def test_read1(self):
822 resp = self.resp
823 def r():
824 res = resp.read1(4)
825 self.assertLessEqual(len(res), 4)
826 return res
827 readliner = Readliner(r)
828 self._verify_readline(readliner.readline, self.lines_expected)
829
830 def test_read1_unbounded(self):
831 resp = self.resp
832 all = []
833 while True:
834 data = resp.read1()
835 if not data:
836 break
837 all.append(data)
838 self.assertEqual(b"".join(all), self.lines_expected)
839
840 def test_read1_bounded(self):
841 resp = self.resp
842 all = []
843 while True:
844 data = resp.read1(10)
845 if not data:
846 break
847 self.assertLessEqual(len(data), 10)
848 all.append(data)
849 self.assertEqual(b"".join(all), self.lines_expected)
850
851 def test_read1_0(self):
852 self.assertEqual(self.resp.read1(0), b"")
853
854 def test_peek_0(self):
855 p = self.resp.peek(0)
856 self.assertLessEqual(0, len(p))
857
858class ExtendedReadTestChunked(ExtendedReadTest):
859 """
860 Test peek(), read1(), readline() in chunked mode
861 """
862 lines = (
863 'HTTP/1.1 200 OK\r\n'
864 'Transfer-Encoding: chunked\r\n\r\n'
865 'a\r\n'
866 'hello worl\r\n'
867 '3\r\n'
868 'd!\n\r\n'
869 '9\r\n'
870 'and now \n\r\n'
871 '23\r\n'
872 'for something completely different\n\r\n'
873 '3\r\n'
874 'foo\r\n'
875 '0\r\n' # terminating chunk
876 '\r\n' # end of trailers
877 )
878
879
880class Readliner:
881 """
882 a simple readline class that uses an arbitrary read function and buffering
883 """
884 def __init__(self, readfunc):
885 self.readfunc = readfunc
886 self.remainder = b""
887
888 def readline(self, limit):
889 data = []
890 datalen = 0
891 read = self.remainder
892 try:
893 while True:
894 idx = read.find(b'\n')
895 if idx != -1:
896 break
897 if datalen + len(read) >= limit:
898 idx = limit - datalen - 1
899 # read more data
900 data.append(read)
901 read = self.readfunc()
902 if not read:
903 idx = 0 #eof condition
904 break
905 idx += 1
906 data.append(read[:idx])
907 self.remainder = read[idx:]
908 return b"".join(data)
909 except:
910 self.remainder = b"".join(data)
911 raise
912
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000913class OfflineTest(TestCase):
914 def test_responses(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000915 self.assertEqual(client.responses[client.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000916
Gregory P. Smithb4066372010-01-03 03:28:29 +0000917
918class SourceAddressTest(TestCase):
919 def setUp(self):
920 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
921 self.port = support.bind_port(self.serv)
922 self.source_port = support.find_unused_port()
Charles-François Natali6e204602014-07-23 19:28:13 +0100923 self.serv.listen()
Gregory P. Smithb4066372010-01-03 03:28:29 +0000924 self.conn = None
925
926 def tearDown(self):
927 if self.conn:
928 self.conn.close()
929 self.conn = None
930 self.serv.close()
931 self.serv = None
932
933 def testHTTPConnectionSourceAddress(self):
934 self.conn = client.HTTPConnection(HOST, self.port,
935 source_address=('', self.source_port))
936 self.conn.connect()
937 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
938
939 @unittest.skipIf(not hasattr(client, 'HTTPSConnection'),
940 'http.client.HTTPSConnection not defined')
941 def testHTTPSConnectionSourceAddress(self):
942 self.conn = client.HTTPSConnection(HOST, self.port,
943 source_address=('', self.source_port))
944 # We don't test anything here other the constructor not barfing as
945 # this code doesn't deal with setting up an active running SSL server
946 # for an ssl_wrapped connect() to actually return from.
947
948
Guido van Rossumd8faa362007-04-27 19:54:29 +0000949class TimeoutTest(TestCase):
Christian Heimes5e696852008-04-09 08:37:03 +0000950 PORT = None
Guido van Rossumd8faa362007-04-27 19:54:29 +0000951
952 def setUp(self):
953 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000954 TimeoutTest.PORT = support.bind_port(self.serv)
Charles-François Natali6e204602014-07-23 19:28:13 +0100955 self.serv.listen()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000956
957 def tearDown(self):
958 self.serv.close()
959 self.serv = None
960
961 def testTimeoutAttribute(self):
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000962 # This will prove that the timeout gets through HTTPConnection
963 # and into the socket.
964
Georg Brandlf78e02b2008-06-10 17:40:04 +0000965 # default -- use global socket timeout
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +0200966 self.assertIsNone(socket.getdefaulttimeout())
Georg Brandlf78e02b2008-06-10 17:40:04 +0000967 socket.setdefaulttimeout(30)
968 try:
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000969 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000970 httpConn.connect()
971 finally:
972 socket.setdefaulttimeout(None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000973 self.assertEqual(httpConn.sock.gettimeout(), 30)
974 httpConn.close()
975
Georg Brandlf78e02b2008-06-10 17:40:04 +0000976 # no timeout -- do not use global socket default
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +0200977 self.assertIsNone(socket.getdefaulttimeout())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000978 socket.setdefaulttimeout(30)
979 try:
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000980 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT,
Christian Heimes5e696852008-04-09 08:37:03 +0000981 timeout=None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000982 httpConn.connect()
983 finally:
Georg Brandlf78e02b2008-06-10 17:40:04 +0000984 socket.setdefaulttimeout(None)
985 self.assertEqual(httpConn.sock.gettimeout(), None)
986 httpConn.close()
987
988 # a value
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000989 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000990 httpConn.connect()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000991 self.assertEqual(httpConn.sock.gettimeout(), 30)
992 httpConn.close()
993
Antoine Pitrou803e6d62010-10-13 10:36:15 +0000994
995class HTTPSTest(TestCase):
996
997 def setUp(self):
998 if not hasattr(client, 'HTTPSConnection'):
999 self.skipTest('ssl support required')
1000
1001 def make_server(self, certfile):
1002 from test.ssl_servers import make_https_server
Antoine Pitrouda232592013-02-05 21:20:51 +01001003 return make_https_server(self, certfile=certfile)
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001004
1005 def test_attributes(self):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001006 # simple test to check it's storing the timeout
1007 h = client.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
1008 self.assertEqual(h.timeout, 30)
1009
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001010 def test_networked(self):
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001011 # Default settings: requires a valid cert from a trusted CA
1012 import ssl
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001013 support.requires('network')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001014 with support.transient_internet('self-signed.pythontest.net'):
1015 h = client.HTTPSConnection('self-signed.pythontest.net', 443)
1016 with self.assertRaises(ssl.SSLError) as exc_info:
1017 h.request('GET', '/')
1018 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
1019
1020 def test_networked_noverification(self):
1021 # Switch off cert verification
1022 import ssl
1023 support.requires('network')
1024 with support.transient_internet('self-signed.pythontest.net'):
1025 context = ssl._create_unverified_context()
1026 h = client.HTTPSConnection('self-signed.pythontest.net', 443,
1027 context=context)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001028 h.request('GET', '/')
1029 resp = h.getresponse()
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001030 self.assertIn('nginx', resp.getheader('server'))
1031
Benjamin Peterson2615e9e2014-11-25 15:16:55 -06001032 @support.system_must_validate_cert
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001033 def test_networked_trusted_by_default_cert(self):
1034 # Default settings: requires a valid cert from a trusted CA
1035 support.requires('network')
1036 with support.transient_internet('www.python.org'):
1037 h = client.HTTPSConnection('www.python.org', 443)
1038 h.request('GET', '/')
1039 resp = h.getresponse()
1040 content_type = resp.getheader('content-type')
1041 self.assertIn('text/html', content_type)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001042
1043 def test_networked_good_cert(self):
Georg Brandlfbaf9312014-11-05 20:37:40 +01001044 # We feed the server's cert as a validating cert
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001045 import ssl
1046 support.requires('network')
Georg Brandlfbaf9312014-11-05 20:37:40 +01001047 with support.transient_internet('self-signed.pythontest.net'):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001048 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1049 context.verify_mode = ssl.CERT_REQUIRED
Georg Brandlfbaf9312014-11-05 20:37:40 +01001050 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
1051 h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001052 h.request('GET', '/')
1053 resp = h.getresponse()
Georg Brandlfbaf9312014-11-05 20:37:40 +01001054 server_string = resp.getheader('server')
1055 self.assertIn('nginx', server_string)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001056
1057 def test_networked_bad_cert(self):
1058 # We feed a "CA" cert that is unrelated to the server's cert
1059 import ssl
1060 support.requires('network')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001061 with support.transient_internet('self-signed.pythontest.net'):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001062 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1063 context.verify_mode = ssl.CERT_REQUIRED
1064 context.load_verify_locations(CERT_localhost)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001065 h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
1066 with self.assertRaises(ssl.SSLError) as exc_info:
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001067 h.request('GET', '/')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001068 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
1069
1070 def test_local_unknown_cert(self):
1071 # The custom cert isn't known to the default trust bundle
1072 import ssl
1073 server = self.make_server(CERT_localhost)
1074 h = client.HTTPSConnection('localhost', server.port)
1075 with self.assertRaises(ssl.SSLError) as exc_info:
1076 h.request('GET', '/')
1077 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001078
1079 def test_local_good_hostname(self):
1080 # The (valid) cert validates the HTTP hostname
1081 import ssl
Brett Cannon252365b2011-08-04 22:43:11 -07001082 server = self.make_server(CERT_localhost)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001083 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1084 context.verify_mode = ssl.CERT_REQUIRED
1085 context.load_verify_locations(CERT_localhost)
1086 h = client.HTTPSConnection('localhost', server.port, context=context)
1087 h.request('GET', '/nonexistent')
1088 resp = h.getresponse()
1089 self.assertEqual(resp.status, 404)
1090
1091 def test_local_bad_hostname(self):
1092 # The (valid) cert doesn't validate the HTTP hostname
1093 import ssl
Brett Cannon252365b2011-08-04 22:43:11 -07001094 server = self.make_server(CERT_fakehostname)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001095 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1096 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Petersona090f012014-12-07 13:18:25 -05001097 context.check_hostname = True
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001098 context.load_verify_locations(CERT_fakehostname)
1099 h = client.HTTPSConnection('localhost', server.port, context=context)
1100 with self.assertRaises(ssl.CertificateError):
1101 h.request('GET', '/')
1102 # Same with explicit check_hostname=True
1103 h = client.HTTPSConnection('localhost', server.port, context=context,
1104 check_hostname=True)
1105 with self.assertRaises(ssl.CertificateError):
1106 h.request('GET', '/')
1107 # With check_hostname=False, the mismatching is ignored
Benjamin Petersona090f012014-12-07 13:18:25 -05001108 context.check_hostname = False
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001109 h = client.HTTPSConnection('localhost', server.port, context=context,
1110 check_hostname=False)
1111 h.request('GET', '/nonexistent')
1112 resp = h.getresponse()
1113 self.assertEqual(resp.status, 404)
Benjamin Petersona090f012014-12-07 13:18:25 -05001114 # The context's check_hostname setting is used if one isn't passed to
1115 # HTTPSConnection.
1116 context.check_hostname = False
1117 h = client.HTTPSConnection('localhost', server.port, context=context)
1118 h.request('GET', '/nonexistent')
1119 self.assertEqual(h.getresponse().status, 404)
1120 # Passing check_hostname to HTTPSConnection should override the
1121 # context's setting.
1122 h = client.HTTPSConnection('localhost', server.port, context=context,
1123 check_hostname=True)
1124 with self.assertRaises(ssl.CertificateError):
1125 h.request('GET', '/')
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001126
Petri Lehtinene119c402011-10-26 21:29:15 +03001127 @unittest.skipIf(not hasattr(client, 'HTTPSConnection'),
1128 'http.client.HTTPSConnection not available')
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +02001129 def test_host_port(self):
1130 # Check invalid host_port
1131
1132 for hp in ("www.python.org:abc", "user:password@www.python.org"):
1133 self.assertRaises(client.InvalidURL, client.HTTPSConnection, hp)
1134
1135 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
1136 "fe80::207:e9ff:fe9b", 8000),
1137 ("www.python.org:443", "www.python.org", 443),
1138 ("www.python.org:", "www.python.org", 443),
1139 ("www.python.org", "www.python.org", 443),
1140 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
1141 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
1142 443)):
1143 c = client.HTTPSConnection(hp)
1144 self.assertEqual(h, c.host)
1145 self.assertEqual(p, c.port)
1146
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001147
Jeremy Hylton236654b2009-03-27 20:24:34 +00001148class RequestBodyTest(TestCase):
1149 """Test cases where a request includes a message body."""
1150
1151 def setUp(self):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001152 self.conn = client.HTTPConnection('example.com')
Jeremy Hylton636950f2009-03-28 04:34:21 +00001153 self.conn.sock = self.sock = FakeSocket("")
Jeremy Hylton236654b2009-03-27 20:24:34 +00001154 self.conn.sock = self.sock
1155
1156 def get_headers_and_fp(self):
1157 f = io.BytesIO(self.sock.data)
1158 f.readline() # read the request line
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001159 message = client.parse_headers(f)
Jeremy Hylton236654b2009-03-27 20:24:34 +00001160 return message, f
1161
1162 def test_manual_content_length(self):
1163 # Set an incorrect content-length so that we can verify that
1164 # it will not be over-ridden by the library.
1165 self.conn.request("PUT", "/url", "body",
1166 {"Content-Length": "42"})
1167 message, f = self.get_headers_and_fp()
1168 self.assertEqual("42", message.get("content-length"))
1169 self.assertEqual(4, len(f.read()))
1170
1171 def test_ascii_body(self):
1172 self.conn.request("PUT", "/url", "body")
1173 message, f = self.get_headers_and_fp()
1174 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001175 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001176 self.assertEqual("4", message.get("content-length"))
1177 self.assertEqual(b'body', f.read())
1178
1179 def test_latin1_body(self):
1180 self.conn.request("PUT", "/url", "body\xc1")
1181 message, f = self.get_headers_and_fp()
1182 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001183 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001184 self.assertEqual("5", message.get("content-length"))
1185 self.assertEqual(b'body\xc1', f.read())
1186
1187 def test_bytes_body(self):
1188 self.conn.request("PUT", "/url", b"body\xc1")
1189 message, f = self.get_headers_and_fp()
1190 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001191 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001192 self.assertEqual("5", message.get("content-length"))
1193 self.assertEqual(b'body\xc1', f.read())
1194
1195 def test_file_body(self):
Victor Stinner18d15cb2011-09-21 01:09:04 +02001196 self.addCleanup(support.unlink, support.TESTFN)
Brett Cannon77b7de62010-10-29 23:31:11 +00001197 with open(support.TESTFN, "w") as f:
1198 f.write("body")
1199 with open(support.TESTFN) as f:
1200 self.conn.request("PUT", "/url", f)
1201 message, f = self.get_headers_and_fp()
1202 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001203 self.assertIsNone(message.get_charset())
Brett Cannon77b7de62010-10-29 23:31:11 +00001204 self.assertEqual("4", message.get("content-length"))
1205 self.assertEqual(b'body', f.read())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001206
1207 def test_binary_file_body(self):
Victor Stinner18d15cb2011-09-21 01:09:04 +02001208 self.addCleanup(support.unlink, support.TESTFN)
Brett Cannon77b7de62010-10-29 23:31:11 +00001209 with open(support.TESTFN, "wb") as f:
1210 f.write(b"body\xc1")
1211 with open(support.TESTFN, "rb") as f:
1212 self.conn.request("PUT", "/url", f)
1213 message, f = self.get_headers_and_fp()
1214 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001215 self.assertIsNone(message.get_charset())
Brett Cannon77b7de62010-10-29 23:31:11 +00001216 self.assertEqual("5", message.get("content-length"))
1217 self.assertEqual(b'body\xc1', f.read())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001218
Senthil Kumaran9f8dc442010-08-02 11:04:58 +00001219
1220class HTTPResponseTest(TestCase):
1221
1222 def setUp(self):
1223 body = "HTTP/1.1 200 Ok\r\nMy-Header: first-value\r\nMy-Header: \
1224 second-value\r\n\r\nText"
1225 sock = FakeSocket(body)
1226 self.resp = client.HTTPResponse(sock)
1227 self.resp.begin()
1228
1229 def test_getting_header(self):
1230 header = self.resp.getheader('My-Header')
1231 self.assertEqual(header, 'first-value, second-value')
1232
1233 header = self.resp.getheader('My-Header', 'some default')
1234 self.assertEqual(header, 'first-value, second-value')
1235
1236 def test_getting_nonexistent_header_with_string_default(self):
1237 header = self.resp.getheader('No-Such-Header', 'default-value')
1238 self.assertEqual(header, 'default-value')
1239
1240 def test_getting_nonexistent_header_with_iterable_default(self):
1241 header = self.resp.getheader('No-Such-Header', ['default', 'values'])
1242 self.assertEqual(header, 'default, values')
1243
1244 header = self.resp.getheader('No-Such-Header', ('default', 'values'))
1245 self.assertEqual(header, 'default, values')
1246
1247 def test_getting_nonexistent_header_without_default(self):
1248 header = self.resp.getheader('No-Such-Header')
1249 self.assertEqual(header, None)
1250
1251 def test_getting_header_defaultint(self):
1252 header = self.resp.getheader('No-Such-Header',default=42)
1253 self.assertEqual(header, 42)
1254
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001255class TunnelTests(TestCase):
1256
1257 def test_connect(self):
1258 response_text = (
1259 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
1260 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
1261 'Content-Length: 42\r\n\r\n'
1262 )
1263
1264 def create_connection(address, timeout=None, source_address=None):
1265 return FakeSocket(response_text, host=address[0],
1266 port=address[1])
1267
1268 conn = client.HTTPConnection('proxy.com')
1269 conn._create_connection = create_connection
1270
1271 # Once connected, we shouldn't be able to tunnel anymore
1272 conn.connect()
1273 self.assertRaises(RuntimeError, conn.set_tunnel,
1274 'destination.com')
1275
1276 # But if we close the connection, we're good
1277 conn.close()
1278 conn.set_tunnel('destination.com')
1279 conn.request('HEAD', '/', '')
1280
1281 self.assertEqual(conn.sock.host, 'proxy.com')
1282 self.assertEqual(conn.sock.port, 80)
Serhiy Storchaka4ac7ed92014-12-12 09:29:15 +02001283 self.assertIn(b'CONNECT destination.com', conn.sock.data)
1284 # issue22095
1285 self.assertNotIn(b'Host: destination.com:None', conn.sock.data)
1286 self.assertIn(b'Host: destination.com', conn.sock.data)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001287
1288 # This test should be removed when CONNECT gets the HTTP/1.1 blessing
Serhiy Storchaka4ac7ed92014-12-12 09:29:15 +02001289 self.assertNotIn(b'Host: proxy.com', conn.sock.data)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001290
1291 conn.close()
1292 conn.request('PUT', '/', '')
1293 self.assertEqual(conn.sock.host, 'proxy.com')
1294 self.assertEqual(conn.sock.port, 80)
1295 self.assertTrue(b'CONNECT destination.com' in conn.sock.data)
1296 self.assertTrue(b'Host: destination.com' in conn.sock.data)
1297
Benjamin Peterson9566de12014-12-13 16:13:24 -05001298@support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +00001299def test_main(verbose=None):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001300 support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001301 HTTPSTest, RequestBodyTest, SourceAddressTest,
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +00001302 HTTPResponseTest, ExtendedReadTest,
Senthil Kumaran166214c2014-04-14 13:10:05 -04001303 ExtendedReadTestChunked, TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +00001304
Thomas Wouters89f507f2006-12-13 04:49:30 +00001305if __name__ == '__main__':
1306 test_main()