blob: ca6bda583b08e253dd1c67f7b6e2d92b6735a2df [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
Serhiy Storchakaa112a8a2015-03-12 11:13:36 +0200174 conn.putheader('Foo', ' bar ')
175 self.assertIn(b'Foo: bar ', conn._buffer)
176 conn.putheader('Bar', '\tbaz\t')
177 self.assertIn(b'Bar: \tbaz\t', conn._buffer)
178 conn.putheader('Authorization', 'Bearer mytoken')
179 self.assertIn(b'Authorization: Bearer mytoken', conn._buffer)
180 conn.putheader('IterHeader', 'IterA', 'IterB')
181 self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer)
182 conn.putheader('LatinHeader', b'\xFF')
183 self.assertIn(b'LatinHeader: \xFF', conn._buffer)
184 conn.putheader('Utf8Header', b'\xc3\x80')
185 self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer)
186 conn.putheader('C1-Control', b'next\x85line')
187 self.assertIn(b'C1-Control: next\x85line', conn._buffer)
188 conn.putheader('Embedded-Fold-Space', 'is\r\n allowed')
189 self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer)
190 conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed')
191 self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer)
192 conn.putheader('Key Space', 'value')
193 self.assertIn(b'Key Space: value', conn._buffer)
194 conn.putheader('KeySpace ', 'value')
195 self.assertIn(b'KeySpace : value', conn._buffer)
196 conn.putheader(b'Nonbreak\xa0Space', 'value')
197 self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer)
198 conn.putheader(b'\xa0NonbreakSpace', 'value')
199 self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer)
200
Senthil Kumaran74ebd9e2010-11-13 12:27:49 +0000201 def test_ipv6host_header(self):
202 # Default host header on IPv6 transaction should wrapped by [] if
203 # its actual IPv6 address
204 expected = b'GET /foo HTTP/1.1\r\nHost: [2001::]:81\r\n' \
205 b'Accept-Encoding: identity\r\n\r\n'
206 conn = client.HTTPConnection('[2001::]:81')
207 sock = FakeSocket('')
208 conn.sock = sock
209 conn.request('GET', '/foo')
210 self.assertTrue(sock.data.startswith(expected))
211
212 expected = b'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
213 b'Accept-Encoding: identity\r\n\r\n'
214 conn = client.HTTPConnection('[2001:102A::]')
215 sock = FakeSocket('')
216 conn.sock = sock
217 conn.request('GET', '/foo')
218 self.assertTrue(sock.data.startswith(expected))
219
Benjamin Peterson155ceaa2015-01-25 23:30:30 -0500220 def test_malformed_headers_coped_with(self):
221 # Issue 19996
222 body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n"
223 sock = FakeSocket(body)
224 resp = client.HTTPResponse(sock)
225 resp.begin()
226
227 self.assertEqual(resp.getheader('First'), 'val')
228 self.assertEqual(resp.getheader('Second'), 'val')
229
Serhiy Storchakaa112a8a2015-03-12 11:13:36 +0200230 def test_invalid_headers(self):
231 conn = client.HTTPConnection('example.com')
232 conn.sock = FakeSocket('')
233 conn.putrequest('GET', '/')
234
235 # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no
236 # longer allowed in header names
237 cases = (
238 (b'Invalid\r\nName', b'ValidValue'),
239 (b'Invalid\rName', b'ValidValue'),
240 (b'Invalid\nName', b'ValidValue'),
241 (b'\r\nInvalidName', b'ValidValue'),
242 (b'\rInvalidName', b'ValidValue'),
243 (b'\nInvalidName', b'ValidValue'),
244 (b' InvalidName', b'ValidValue'),
245 (b'\tInvalidName', b'ValidValue'),
246 (b'Invalid:Name', b'ValidValue'),
247 (b':InvalidName', b'ValidValue'),
248 (b'ValidName', b'Invalid\r\nValue'),
249 (b'ValidName', b'Invalid\rValue'),
250 (b'ValidName', b'Invalid\nValue'),
251 (b'ValidName', b'InvalidValue\r\n'),
252 (b'ValidName', b'InvalidValue\r'),
253 (b'ValidName', b'InvalidValue\n'),
254 )
255 for name, value in cases:
256 with self.subTest((name, value)):
257 with self.assertRaisesRegex(ValueError, 'Invalid header'):
258 conn.putheader(name, value)
259
Senthil Kumaran58d5dbf2010-10-03 18:22:42 +0000260
Thomas Wouters89f507f2006-12-13 04:49:30 +0000261class BasicTest(TestCase):
262 def test_status_lines(self):
263 # Test HTTP status lines
Jeremy Hylton79fa2b62001-04-13 14:57:44 +0000264
Thomas Wouters89f507f2006-12-13 04:49:30 +0000265 body = "HTTP/1.1 200 Ok\r\n\r\nText"
266 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000267 resp = client.HTTPResponse(sock)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000268 resp.begin()
Serhiy Storchaka1c84ac12013-12-17 21:50:02 +0200269 self.assertEqual(resp.read(0), b'') # Issue #20007
270 self.assertFalse(resp.isclosed())
271 self.assertFalse(resp.closed)
Jeremy Hylton8fff7922007-08-03 20:56:14 +0000272 self.assertEqual(resp.read(), b"Text")
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000273 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200274 self.assertFalse(resp.closed)
275 resp.close()
276 self.assertTrue(resp.closed)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000277
Thomas Wouters89f507f2006-12-13 04:49:30 +0000278 body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
279 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000280 resp = client.HTTPResponse(sock)
281 self.assertRaises(client.BadStatusLine, resp.begin)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000282
Benjamin Peterson11dbfd42010-03-21 22:50:04 +0000283 def test_bad_status_repr(self):
284 exc = client.BadStatusLine('')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000285 self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
Benjamin Peterson11dbfd42010-03-21 22:50:04 +0000286
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000287 def test_partial_reads(self):
Antoine Pitrou084daa22012-12-15 19:11:54 +0100288 # if we have a length, the system knows when to close itself
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000289 # same behaviour than when we read the whole thing with read()
290 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
291 sock = FakeSocket(body)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000292 resp = client.HTTPResponse(sock)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000293 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.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200298 self.assertFalse(resp.closed)
299 resp.close()
300 self.assertTrue(resp.closed)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000301
Antoine Pitrou38d96432011-12-06 22:33:57 +0100302 def test_partial_readintos(self):
Antoine Pitroud20e7742012-12-15 19:22:30 +0100303 # if we have a length, the system knows when to close itself
Antoine Pitrou38d96432011-12-06 22:33:57 +0100304 # same behaviour than when we read the whole thing with read()
305 body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
306 sock = FakeSocket(body)
307 resp = client.HTTPResponse(sock)
308 resp.begin()
309 b = bytearray(2)
310 n = resp.readinto(b)
311 self.assertEqual(n, 2)
312 self.assertEqual(bytes(b), b'Te')
313 self.assertFalse(resp.isclosed())
314 n = resp.readinto(b)
315 self.assertEqual(n, 2)
316 self.assertEqual(bytes(b), b'xt')
317 self.assertTrue(resp.isclosed())
Serhiy Storchakab6c86fd2013-02-06 10:35:40 +0200318 self.assertFalse(resp.closed)
319 resp.close()
320 self.assertTrue(resp.closed)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100321
Antoine Pitrou084daa22012-12-15 19:11:54 +0100322 def test_partial_reads_no_content_length(self):
323 # when no length is present, the socket should be gracefully closed when
324 # all data was read
325 body = "HTTP/1.1 200 Ok\r\n\r\nText"
326 sock = FakeSocket(body)
327 resp = client.HTTPResponse(sock)
328 resp.begin()
329 self.assertEqual(resp.read(2), b'Te')
330 self.assertFalse(resp.isclosed())
331 self.assertEqual(resp.read(2), b'xt')
332 self.assertEqual(resp.read(1), b'')
333 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200334 self.assertFalse(resp.closed)
335 resp.close()
336 self.assertTrue(resp.closed)
Antoine Pitrou084daa22012-12-15 19:11:54 +0100337
Antoine Pitroud20e7742012-12-15 19:22:30 +0100338 def test_partial_readintos_no_content_length(self):
339 # when no length is present, the socket should be gracefully closed when
340 # all data was read
341 body = "HTTP/1.1 200 Ok\r\n\r\nText"
342 sock = FakeSocket(body)
343 resp = client.HTTPResponse(sock)
344 resp.begin()
345 b = bytearray(2)
346 n = resp.readinto(b)
347 self.assertEqual(n, 2)
348 self.assertEqual(bytes(b), b'Te')
349 self.assertFalse(resp.isclosed())
350 n = resp.readinto(b)
351 self.assertEqual(n, 2)
352 self.assertEqual(bytes(b), b'xt')
353 n = resp.readinto(b)
354 self.assertEqual(n, 0)
355 self.assertTrue(resp.isclosed())
356
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100357 def test_partial_reads_incomplete_body(self):
358 # if the server shuts down the connection before the whole
359 # content-length is delivered, the socket is gracefully closed
360 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
361 sock = FakeSocket(body)
362 resp = client.HTTPResponse(sock)
363 resp.begin()
364 self.assertEqual(resp.read(2), b'Te')
365 self.assertFalse(resp.isclosed())
366 self.assertEqual(resp.read(2), b'xt')
367 self.assertEqual(resp.read(1), b'')
368 self.assertTrue(resp.isclosed())
369
Antoine Pitrou6a35e182013-02-02 23:04:56 +0100370 def test_partial_readintos_incomplete_body(self):
371 # if the server shuts down the connection before the whole
372 # content-length is delivered, the socket is gracefully closed
373 body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
374 sock = FakeSocket(body)
375 resp = client.HTTPResponse(sock)
376 resp.begin()
377 b = bytearray(2)
378 n = resp.readinto(b)
379 self.assertEqual(n, 2)
380 self.assertEqual(bytes(b), b'Te')
381 self.assertFalse(resp.isclosed())
382 n = resp.readinto(b)
383 self.assertEqual(n, 2)
384 self.assertEqual(bytes(b), b'xt')
385 n = resp.readinto(b)
386 self.assertEqual(n, 0)
387 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200388 self.assertFalse(resp.closed)
389 resp.close()
390 self.assertTrue(resp.closed)
Antoine Pitrou6a35e182013-02-02 23:04:56 +0100391
Thomas Wouters89f507f2006-12-13 04:49:30 +0000392 def test_host_port(self):
393 # Check invalid host_port
Jeremy Hyltonba603192003-01-23 18:02:20 +0000394
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200395 for hp in ("www.python.org:abc", "user:password@www.python.org"):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000396 self.assertRaises(client.InvalidURL, client.HTTPConnection, hp)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000397
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000398 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
399 "fe80::207:e9ff:fe9b", 8000),
Thomas Wouters89f507f2006-12-13 04:49:30 +0000400 ("www.python.org:80", "www.python.org", 80),
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200401 ("www.python.org:", "www.python.org", 80),
Thomas Wouters89f507f2006-12-13 04:49:30 +0000402 ("www.python.org", "www.python.org", 80),
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +0200403 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 80),
404 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", 80)):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000405 c = client.HTTPConnection(hp)
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000406 self.assertEqual(h, c.host)
407 self.assertEqual(p, c.port)
Skip Montanaro10e6e0e2004-09-14 16:32:02 +0000408
Thomas Wouters89f507f2006-12-13 04:49:30 +0000409 def test_response_headers(self):
410 # test response with multiple message headers with the same field name.
411 text = ('HTTP/1.1 200 OK\r\n'
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000412 'Set-Cookie: Customer="WILE_E_COYOTE"; '
413 'Version="1"; Path="/acme"\r\n'
Thomas Wouters89f507f2006-12-13 04:49:30 +0000414 'Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";'
415 ' Path="/acme"\r\n'
416 '\r\n'
417 'No body\r\n')
418 hdr = ('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
419 ', '
420 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"')
421 s = FakeSocket(text)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000422 r = client.HTTPResponse(s)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000423 r.begin()
424 cookies = r.getheader("Set-Cookie")
Jeremy Hylton3a38c912007-08-14 17:08:07 +0000425 self.assertEqual(cookies, hdr)
Jeremy Hyltonba603192003-01-23 18:02:20 +0000426
Thomas Wouters89f507f2006-12-13 04:49:30 +0000427 def test_read_head(self):
428 # Test that the library doesn't attempt to read any data
429 # from a HEAD request. (Tickles SF bug #622042.)
430 sock = FakeSocket(
431 'HTTP/1.1 200 OK\r\n'
432 'Content-Length: 14432\r\n'
433 '\r\n',
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300434 NoEOFBytesIO)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000435 resp = client.HTTPResponse(sock, method="HEAD")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000436 resp.begin()
Guido van Rossuma00f1232007-09-12 19:43:09 +0000437 if resp.read():
Thomas Wouters89f507f2006-12-13 04:49:30 +0000438 self.fail("Did not expect response from HEAD request")
Jeremy Hyltonc1b2cb92003-05-05 16:13:58 +0000439
Antoine Pitrou38d96432011-12-06 22:33:57 +0100440 def test_readinto_head(self):
441 # Test that the library doesn't attempt to read any data
442 # from a HEAD request. (Tickles SF bug #622042.)
443 sock = FakeSocket(
444 'HTTP/1.1 200 OK\r\n'
445 'Content-Length: 14432\r\n'
446 '\r\n',
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300447 NoEOFBytesIO)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100448 resp = client.HTTPResponse(sock, method="HEAD")
449 resp.begin()
450 b = bytearray(5)
451 if resp.readinto(b) != 0:
452 self.fail("Did not expect response from HEAD request")
453 self.assertEqual(bytes(b), b'\x00'*5)
454
Georg Brandlbf3f8eb2013-10-27 07:34:48 +0100455 def test_too_many_headers(self):
456 headers = '\r\n'.join('Header%d: foo' % i
457 for i in range(client._MAXHEADERS + 1)) + '\r\n'
458 text = ('HTTP/1.1 200 OK\r\n' + headers)
459 s = FakeSocket(text)
460 r = client.HTTPResponse(s)
461 self.assertRaisesRegex(client.HTTPException,
462 r"got more than \d+ headers", r.begin)
463
Thomas Wouters89f507f2006-12-13 04:49:30 +0000464 def test_send_file(self):
Guido van Rossum022c4742007-08-29 02:00:20 +0000465 expected = (b'GET /foo HTTP/1.1\r\nHost: example.com\r\n'
466 b'Accept-Encoding: identity\r\nContent-Length:')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000467
Brett Cannon77b7de62010-10-29 23:31:11 +0000468 with open(__file__, 'rb') as body:
469 conn = client.HTTPConnection('example.com')
470 sock = FakeSocket(body)
471 conn.sock = sock
472 conn.request('GET', '/foo', body)
473 self.assertTrue(sock.data.startswith(expected), '%r != %r' %
474 (sock.data[:len(expected)], expected))
Jeremy Hylton2c178252004-08-07 16:28:14 +0000475
Antoine Pitrouead1d622009-09-29 18:44:53 +0000476 def test_send(self):
477 expected = b'this is a test this is only a test'
478 conn = client.HTTPConnection('example.com')
479 sock = FakeSocket(None)
480 conn.sock = sock
481 conn.send(expected)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000482 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000483 sock.data = b''
484 conn.send(array.array('b', expected))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000485 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000486 sock.data = b''
487 conn.send(io.BytesIO(expected))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000488 self.assertEqual(expected, sock.data)
Antoine Pitrouead1d622009-09-29 18:44:53 +0000489
Andrew Svetlov7b2c8bb2013-04-12 22:49:19 +0300490 def test_send_updating_file(self):
491 def data():
492 yield 'data'
493 yield None
494 yield 'data_two'
495
496 class UpdatingFile():
497 mode = 'r'
498 d = data()
499 def read(self, blocksize=-1):
500 return self.d.__next__()
501
502 expected = b'data'
503
504 conn = client.HTTPConnection('example.com')
505 sock = FakeSocket("")
506 conn.sock = sock
507 conn.send(UpdatingFile())
508 self.assertEqual(sock.data, expected)
509
510
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000511 def test_send_iter(self):
512 expected = b'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
513 b'Accept-Encoding: identity\r\nContent-Length: 11\r\n' \
514 b'\r\nonetwothree'
515
516 def body():
517 yield b"one"
518 yield b"two"
519 yield b"three"
520
521 conn = client.HTTPConnection('example.com')
522 sock = FakeSocket("")
523 conn.sock = sock
524 conn.request('GET', '/foo', body(), {'Content-Length': '11'})
Victor Stinner04ba9662011-01-04 00:04:46 +0000525 self.assertEqual(sock.data, expected)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000526
Senthil Kumaraneb71ad42011-08-02 18:33:41 +0800527 def test_send_type_error(self):
528 # See: Issue #12676
529 conn = client.HTTPConnection('example.com')
530 conn.sock = FakeSocket('')
531 with self.assertRaises(TypeError):
532 conn.request('POST', 'test', conn)
533
Christian Heimesa612dc02008-02-24 13:08:18 +0000534 def test_chunked(self):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000535 expected = chunked_expected
536 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000537 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000538 resp.begin()
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100539 self.assertEqual(resp.read(), expected)
Christian Heimesa612dc02008-02-24 13:08:18 +0000540 resp.close()
541
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100542 # Various read sizes
543 for n in range(1, 12):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000544 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100545 resp = client.HTTPResponse(sock, method="GET")
546 resp.begin()
547 self.assertEqual(resp.read(n) + resp.read(n) + resp.read(), expected)
548 resp.close()
549
Christian Heimesa612dc02008-02-24 13:08:18 +0000550 for x in ('', 'foo\r\n'):
551 sock = FakeSocket(chunked_start + x)
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000552 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000553 resp.begin()
554 try:
555 resp.read()
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000556 except client.IncompleteRead as i:
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100557 self.assertEqual(i.partial, expected)
558 expected_message = 'IncompleteRead(%d bytes read)' % len(expected)
559 self.assertEqual(repr(i), expected_message)
560 self.assertEqual(str(i), expected_message)
Christian Heimesa612dc02008-02-24 13:08:18 +0000561 else:
562 self.fail('IncompleteRead expected')
563 finally:
564 resp.close()
565
Antoine Pitrou38d96432011-12-06 22:33:57 +0100566 def test_readinto_chunked(self):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000567
568 expected = chunked_expected
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100569 nexpected = len(expected)
570 b = bytearray(128)
571
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000572 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100573 resp = client.HTTPResponse(sock, method="GET")
574 resp.begin()
Antoine Pitrou38d96432011-12-06 22:33:57 +0100575 n = resp.readinto(b)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100576 self.assertEqual(b[:nexpected], expected)
577 self.assertEqual(n, nexpected)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100578 resp.close()
579
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100580 # Various read sizes
581 for n in range(1, 12):
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000582 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100583 resp = client.HTTPResponse(sock, method="GET")
584 resp.begin()
585 m = memoryview(b)
586 i = resp.readinto(m[0:n])
587 i += resp.readinto(m[i:n + i])
588 i += resp.readinto(m[i:])
589 self.assertEqual(b[:nexpected], expected)
590 self.assertEqual(i, nexpected)
591 resp.close()
592
Antoine Pitrou38d96432011-12-06 22:33:57 +0100593 for x in ('', 'foo\r\n'):
594 sock = FakeSocket(chunked_start + x)
595 resp = client.HTTPResponse(sock, method="GET")
596 resp.begin()
597 try:
Antoine Pitrou38d96432011-12-06 22:33:57 +0100598 n = resp.readinto(b)
599 except client.IncompleteRead as i:
Antoine Pitrouf7e78182012-01-04 18:57:22 +0100600 self.assertEqual(i.partial, expected)
601 expected_message = 'IncompleteRead(%d bytes read)' % len(expected)
602 self.assertEqual(repr(i), expected_message)
603 self.assertEqual(str(i), expected_message)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100604 else:
605 self.fail('IncompleteRead expected')
606 finally:
607 resp.close()
608
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000609 def test_chunked_head(self):
610 chunked_start = (
611 'HTTP/1.1 200 OK\r\n'
612 'Transfer-Encoding: chunked\r\n\r\n'
613 'a\r\n'
614 'hello world\r\n'
615 '1\r\n'
616 'd\r\n'
617 )
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000618 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000619 resp = client.HTTPResponse(sock, method="HEAD")
620 resp.begin()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000621 self.assertEqual(resp.read(), b'')
622 self.assertEqual(resp.status, 200)
623 self.assertEqual(resp.reason, 'OK')
Senthil Kumaran0b998832010-06-04 17:27:11 +0000624 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200625 self.assertFalse(resp.closed)
626 resp.close()
627 self.assertTrue(resp.closed)
Senthil Kumaran71fb6c82010-04-28 17:39:48 +0000628
Antoine Pitrou38d96432011-12-06 22:33:57 +0100629 def test_readinto_chunked_head(self):
630 chunked_start = (
631 'HTTP/1.1 200 OK\r\n'
632 'Transfer-Encoding: chunked\r\n\r\n'
633 'a\r\n'
634 'hello world\r\n'
635 '1\r\n'
636 'd\r\n'
637 )
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000638 sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100639 resp = client.HTTPResponse(sock, method="HEAD")
640 resp.begin()
641 b = bytearray(5)
642 n = resp.readinto(b)
643 self.assertEqual(n, 0)
644 self.assertEqual(bytes(b), b'\x00'*5)
645 self.assertEqual(resp.status, 200)
646 self.assertEqual(resp.reason, 'OK')
647 self.assertTrue(resp.isclosed())
Serhiy Storchakab6c86fd2013-02-06 10:35:40 +0200648 self.assertFalse(resp.closed)
649 resp.close()
650 self.assertTrue(resp.closed)
Antoine Pitrou38d96432011-12-06 22:33:57 +0100651
Christian Heimesa612dc02008-02-24 13:08:18 +0000652 def test_negative_content_length(self):
Jeremy Hylton82066952008-12-15 03:08:30 +0000653 sock = FakeSocket(
654 'HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\nHello\r\n')
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000655 resp = client.HTTPResponse(sock, method="GET")
Christian Heimesa612dc02008-02-24 13:08:18 +0000656 resp.begin()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000657 self.assertEqual(resp.read(), b'Hello\r\n')
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100658 self.assertTrue(resp.isclosed())
Christian Heimesa612dc02008-02-24 13:08:18 +0000659
Benjamin Peterson6accb982009-03-02 22:50:25 +0000660 def test_incomplete_read(self):
661 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000662 resp = client.HTTPResponse(sock, method="GET")
Benjamin Peterson6accb982009-03-02 22:50:25 +0000663 resp.begin()
664 try:
665 resp.read()
Jeremy Hylton7c1692d2009-03-27 21:31:03 +0000666 except client.IncompleteRead as i:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000667 self.assertEqual(i.partial, b'Hello\r\n')
Benjamin Peterson6accb982009-03-02 22:50:25 +0000668 self.assertEqual(repr(i),
669 "IncompleteRead(7 bytes read, 3 more expected)")
670 self.assertEqual(str(i),
671 "IncompleteRead(7 bytes read, 3 more expected)")
Antoine Pitroubeec61a2013-02-02 22:49:34 +0100672 self.assertTrue(resp.isclosed())
Benjamin Peterson6accb982009-03-02 22:50:25 +0000673 else:
674 self.fail('IncompleteRead expected')
Benjamin Peterson6accb982009-03-02 22:50:25 +0000675
Jeremy Hylton636950f2009-03-28 04:34:21 +0000676 def test_epipe(self):
677 sock = EPipeSocket(
678 "HTTP/1.0 401 Authorization Required\r\n"
679 "Content-type: text/html\r\n"
680 "WWW-Authenticate: Basic realm=\"example\"\r\n",
681 b"Content-Length")
682 conn = client.HTTPConnection("example.com")
683 conn.sock = sock
Andrew Svetlov0832af62012-12-18 23:10:48 +0200684 self.assertRaises(OSError,
Jeremy Hylton636950f2009-03-28 04:34:21 +0000685 lambda: conn.request("PUT", "/url", "body"))
686 resp = conn.getresponse()
687 self.assertEqual(401, resp.status)
688 self.assertEqual("Basic realm=\"example\"",
689 resp.getheader("www-authenticate"))
Christian Heimesa612dc02008-02-24 13:08:18 +0000690
Senthil Kumaran5466bf12010-12-18 16:55:23 +0000691 # Test lines overflowing the max line size (_MAXLINE in http.client)
692
693 def test_overflowing_status_line(self):
694 body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"
695 resp = client.HTTPResponse(FakeSocket(body))
696 self.assertRaises((client.LineTooLong, client.BadStatusLine), resp.begin)
697
698 def test_overflowing_header_line(self):
699 body = (
700 'HTTP/1.1 200 OK\r\n'
701 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'
702 )
703 resp = client.HTTPResponse(FakeSocket(body))
704 self.assertRaises(client.LineTooLong, resp.begin)
705
706 def test_overflowing_chunked_line(self):
707 body = (
708 'HTTP/1.1 200 OK\r\n'
709 'Transfer-Encoding: chunked\r\n\r\n'
710 + '0' * 65536 + 'a\r\n'
711 'hello world\r\n'
712 '0\r\n'
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000713 '\r\n'
Senthil Kumaran5466bf12010-12-18 16:55:23 +0000714 )
715 resp = client.HTTPResponse(FakeSocket(body))
716 resp.begin()
717 self.assertRaises(client.LineTooLong, resp.read)
718
Senthil Kumaran9c29f862012-04-29 10:20:46 +0800719 def test_early_eof(self):
720 # Test httpresponse with no \r\n termination,
721 body = "HTTP/1.1 200 Ok"
722 sock = FakeSocket(body)
723 resp = client.HTTPResponse(sock)
724 resp.begin()
725 self.assertEqual(resp.read(), b'')
726 self.assertTrue(resp.isclosed())
Serhiy Storchakab5b9c8c2013-02-06 10:31:57 +0200727 self.assertFalse(resp.closed)
728 resp.close()
729 self.assertTrue(resp.closed)
Senthil Kumaran9c29f862012-04-29 10:20:46 +0800730
Serhiy Storchakab491e052014-12-01 13:07:45 +0200731 def test_error_leak(self):
732 # Test that the socket is not leaked if getresponse() fails
733 conn = client.HTTPConnection('example.com')
734 response = None
735 class Response(client.HTTPResponse):
736 def __init__(self, *pos, **kw):
737 nonlocal response
738 response = self # Avoid garbage collector closing the socket
739 client.HTTPResponse.__init__(self, *pos, **kw)
740 conn.response_class = Response
741 conn.sock = FakeSocket('') # Emulate server dropping connection
742 conn.request('GET', '/')
743 self.assertRaises(client.BadStatusLine, conn.getresponse)
744 self.assertTrue(response.closed)
745 self.assertTrue(conn.sock.file_closed)
746
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +0000747 def test_chunked_extension(self):
748 extra = '3;foo=bar\r\n' + 'abc\r\n'
749 expected = chunked_expected + b'abc'
750
751 sock = FakeSocket(chunked_start + extra + last_chunk_extended + chunked_end)
752 resp = client.HTTPResponse(sock, method="GET")
753 resp.begin()
754 self.assertEqual(resp.read(), expected)
755 resp.close()
756
757 def test_chunked_missing_end(self):
758 """some servers may serve up a short chunked encoding stream"""
759 expected = chunked_expected
760 sock = FakeSocket(chunked_start + last_chunk) #no terminating crlf
761 resp = client.HTTPResponse(sock, method="GET")
762 resp.begin()
763 self.assertEqual(resp.read(), expected)
764 resp.close()
765
766 def test_chunked_trailers(self):
767 """See that trailers are read and ignored"""
768 expected = chunked_expected
769 sock = FakeSocket(chunked_start + last_chunk + trailers + chunked_end)
770 resp = client.HTTPResponse(sock, method="GET")
771 resp.begin()
772 self.assertEqual(resp.read(), expected)
773 # we should have reached the end of the file
774 self.assertEqual(sock.file.read(100), b"") #we read to the end
775 resp.close()
776
777 def test_chunked_sync(self):
778 """Check that we don't read past the end of the chunked-encoding stream"""
779 expected = chunked_expected
780 extradata = "extradata"
781 sock = FakeSocket(chunked_start + last_chunk + trailers + chunked_end + extradata)
782 resp = client.HTTPResponse(sock, method="GET")
783 resp.begin()
784 self.assertEqual(resp.read(), expected)
785 # the file should now have our extradata ready to be read
786 self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end
787 resp.close()
788
789 def test_content_length_sync(self):
790 """Check that we don't read past the end of the Content-Length stream"""
791 extradata = "extradata"
792 expected = b"Hello123\r\n"
793 sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello123\r\n' + extradata)
794 resp = client.HTTPResponse(sock, method="GET")
795 resp.begin()
796 self.assertEqual(resp.read(), expected)
797 # the file should now have our extradata ready to be read
798 self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end
799 resp.close()
800
801class ExtendedReadTest(TestCase):
802 """
803 Test peek(), read1(), readline()
804 """
805 lines = (
806 'HTTP/1.1 200 OK\r\n'
807 '\r\n'
808 'hello world!\n'
809 'and now \n'
810 'for something completely different\n'
811 'foo'
812 )
813 lines_expected = lines[lines.find('hello'):].encode("ascii")
814 lines_chunked = (
815 'HTTP/1.1 200 OK\r\n'
816 'Transfer-Encoding: chunked\r\n\r\n'
817 'a\r\n'
818 'hello worl\r\n'
819 '3\r\n'
820 'd!\n\r\n'
821 '9\r\n'
822 'and now \n\r\n'
823 '23\r\n'
824 'for something completely different\n\r\n'
825 '3\r\n'
826 'foo\r\n'
827 '0\r\n' # terminating chunk
828 '\r\n' # end of trailers
829 )
830
831 def setUp(self):
832 sock = FakeSocket(self.lines)
833 resp = client.HTTPResponse(sock, method="GET")
834 resp.begin()
835 resp.fp = io.BufferedReader(resp.fp)
836 self.resp = resp
837
838
839
840 def test_peek(self):
841 resp = self.resp
842 # patch up the buffered peek so that it returns not too much stuff
843 oldpeek = resp.fp.peek
844 def mypeek(n=-1):
845 p = oldpeek(n)
846 if n >= 0:
847 return p[:n]
848 return p[:10]
849 resp.fp.peek = mypeek
850
851 all = []
852 while True:
853 # try a short peek
854 p = resp.peek(3)
855 if p:
856 self.assertGreater(len(p), 0)
857 # then unbounded peek
858 p2 = resp.peek()
859 self.assertGreaterEqual(len(p2), len(p))
860 self.assertTrue(p2.startswith(p))
861 next = resp.read(len(p2))
862 self.assertEqual(next, p2)
863 else:
864 next = resp.read()
865 self.assertFalse(next)
866 all.append(next)
867 if not next:
868 break
869 self.assertEqual(b"".join(all), self.lines_expected)
870
871 def test_readline(self):
872 resp = self.resp
873 self._verify_readline(self.resp.readline, self.lines_expected)
874
875 def _verify_readline(self, readline, expected):
876 all = []
877 while True:
878 # short readlines
879 line = readline(5)
880 if line and line != b"foo":
881 if len(line) < 5:
882 self.assertTrue(line.endswith(b"\n"))
883 all.append(line)
884 if not line:
885 break
886 self.assertEqual(b"".join(all), expected)
887
888 def test_read1(self):
889 resp = self.resp
890 def r():
891 res = resp.read1(4)
892 self.assertLessEqual(len(res), 4)
893 return res
894 readliner = Readliner(r)
895 self._verify_readline(readliner.readline, self.lines_expected)
896
897 def test_read1_unbounded(self):
898 resp = self.resp
899 all = []
900 while True:
901 data = resp.read1()
902 if not data:
903 break
904 all.append(data)
905 self.assertEqual(b"".join(all), self.lines_expected)
906
907 def test_read1_bounded(self):
908 resp = self.resp
909 all = []
910 while True:
911 data = resp.read1(10)
912 if not data:
913 break
914 self.assertLessEqual(len(data), 10)
915 all.append(data)
916 self.assertEqual(b"".join(all), self.lines_expected)
917
918 def test_read1_0(self):
919 self.assertEqual(self.resp.read1(0), b"")
920
921 def test_peek_0(self):
922 p = self.resp.peek(0)
923 self.assertLessEqual(0, len(p))
924
925class ExtendedReadTestChunked(ExtendedReadTest):
926 """
927 Test peek(), read1(), readline() in chunked mode
928 """
929 lines = (
930 'HTTP/1.1 200 OK\r\n'
931 'Transfer-Encoding: chunked\r\n\r\n'
932 'a\r\n'
933 'hello worl\r\n'
934 '3\r\n'
935 'd!\n\r\n'
936 '9\r\n'
937 'and now \n\r\n'
938 '23\r\n'
939 'for something completely different\n\r\n'
940 '3\r\n'
941 'foo\r\n'
942 '0\r\n' # terminating chunk
943 '\r\n' # end of trailers
944 )
945
946
947class Readliner:
948 """
949 a simple readline class that uses an arbitrary read function and buffering
950 """
951 def __init__(self, readfunc):
952 self.readfunc = readfunc
953 self.remainder = b""
954
955 def readline(self, limit):
956 data = []
957 datalen = 0
958 read = self.remainder
959 try:
960 while True:
961 idx = read.find(b'\n')
962 if idx != -1:
963 break
964 if datalen + len(read) >= limit:
965 idx = limit - datalen - 1
966 # read more data
967 data.append(read)
968 read = self.readfunc()
969 if not read:
970 idx = 0 #eof condition
971 break
972 idx += 1
973 data.append(read[:idx])
974 self.remainder = read[idx:]
975 return b"".join(data)
976 except:
977 self.remainder = b"".join(data)
978 raise
979
Berker Peksagbabc6882015-02-20 09:39:38 +0200980
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000981class OfflineTest(TestCase):
Berker Peksagbabc6882015-02-20 09:39:38 +0200982 def test_all(self):
983 # Documented objects defined in the module should be in __all__
984 expected = {"responses"} # White-list documented dict() object
985 # HTTPMessage, parse_headers(), and the HTTP status code constants are
986 # intentionally omitted for simplicity
987 blacklist = {"HTTPMessage", "parse_headers"}
988 for name in dir(client):
989 if name in blacklist:
990 continue
991 module_object = getattr(client, name)
992 if getattr(module_object, "__module__", None) == "http.client":
993 expected.add(name)
994 self.assertCountEqual(client.__all__, expected)
995
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000996 def test_responses(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000997 self.assertEqual(client.responses[client.NOT_FOUND], "Not Found")
Georg Brandl4cbd1e32006-02-17 22:01:08 +0000998
Berker Peksagabbf0f42015-02-20 14:57:31 +0200999 def test_client_constants(self):
1000 # Make sure we don't break backward compatibility with 3.4
1001 expected = [
1002 'CONTINUE',
1003 'SWITCHING_PROTOCOLS',
1004 'PROCESSING',
1005 'OK',
1006 'CREATED',
1007 'ACCEPTED',
1008 'NON_AUTHORITATIVE_INFORMATION',
1009 'NO_CONTENT',
1010 'RESET_CONTENT',
1011 'PARTIAL_CONTENT',
1012 'MULTI_STATUS',
1013 'IM_USED',
1014 'MULTIPLE_CHOICES',
1015 'MOVED_PERMANENTLY',
1016 'FOUND',
1017 'SEE_OTHER',
1018 'NOT_MODIFIED',
1019 'USE_PROXY',
1020 'TEMPORARY_REDIRECT',
1021 'BAD_REQUEST',
1022 'UNAUTHORIZED',
1023 'PAYMENT_REQUIRED',
1024 'FORBIDDEN',
1025 'NOT_FOUND',
1026 'METHOD_NOT_ALLOWED',
1027 'NOT_ACCEPTABLE',
1028 'PROXY_AUTHENTICATION_REQUIRED',
1029 'REQUEST_TIMEOUT',
1030 'CONFLICT',
1031 'GONE',
1032 'LENGTH_REQUIRED',
1033 'PRECONDITION_FAILED',
1034 'REQUEST_ENTITY_TOO_LARGE',
1035 'REQUEST_URI_TOO_LONG',
1036 'UNSUPPORTED_MEDIA_TYPE',
1037 'REQUESTED_RANGE_NOT_SATISFIABLE',
1038 'EXPECTATION_FAILED',
1039 'UNPROCESSABLE_ENTITY',
1040 'LOCKED',
1041 'FAILED_DEPENDENCY',
1042 'UPGRADE_REQUIRED',
1043 'PRECONDITION_REQUIRED',
1044 'TOO_MANY_REQUESTS',
1045 'REQUEST_HEADER_FIELDS_TOO_LARGE',
1046 'INTERNAL_SERVER_ERROR',
1047 'NOT_IMPLEMENTED',
1048 'BAD_GATEWAY',
1049 'SERVICE_UNAVAILABLE',
1050 'GATEWAY_TIMEOUT',
1051 'HTTP_VERSION_NOT_SUPPORTED',
1052 'INSUFFICIENT_STORAGE',
1053 'NOT_EXTENDED',
1054 'NETWORK_AUTHENTICATION_REQUIRED',
1055 ]
1056 for const in expected:
1057 with self.subTest(constant=const):
1058 self.assertTrue(hasattr(client, const))
1059
Gregory P. Smithb4066372010-01-03 03:28:29 +00001060
1061class SourceAddressTest(TestCase):
1062 def setUp(self):
1063 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1064 self.port = support.bind_port(self.serv)
1065 self.source_port = support.find_unused_port()
Charles-François Natali6e204602014-07-23 19:28:13 +01001066 self.serv.listen()
Gregory P. Smithb4066372010-01-03 03:28:29 +00001067 self.conn = None
1068
1069 def tearDown(self):
1070 if self.conn:
1071 self.conn.close()
1072 self.conn = None
1073 self.serv.close()
1074 self.serv = None
1075
1076 def testHTTPConnectionSourceAddress(self):
1077 self.conn = client.HTTPConnection(HOST, self.port,
1078 source_address=('', self.source_port))
1079 self.conn.connect()
1080 self.assertEqual(self.conn.sock.getsockname()[1], self.source_port)
1081
1082 @unittest.skipIf(not hasattr(client, 'HTTPSConnection'),
1083 'http.client.HTTPSConnection not defined')
1084 def testHTTPSConnectionSourceAddress(self):
1085 self.conn = client.HTTPSConnection(HOST, self.port,
1086 source_address=('', self.source_port))
1087 # We don't test anything here other the constructor not barfing as
1088 # this code doesn't deal with setting up an active running SSL server
1089 # for an ssl_wrapped connect() to actually return from.
1090
1091
Guido van Rossumd8faa362007-04-27 19:54:29 +00001092class TimeoutTest(TestCase):
Christian Heimes5e696852008-04-09 08:37:03 +00001093 PORT = None
Guido van Rossumd8faa362007-04-27 19:54:29 +00001094
1095 def setUp(self):
1096 self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001097 TimeoutTest.PORT = support.bind_port(self.serv)
Charles-François Natali6e204602014-07-23 19:28:13 +01001098 self.serv.listen()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001099
1100 def tearDown(self):
1101 self.serv.close()
1102 self.serv = None
1103
1104 def testTimeoutAttribute(self):
Jeremy Hylton3a38c912007-08-14 17:08:07 +00001105 # This will prove that the timeout gets through HTTPConnection
1106 # and into the socket.
1107
Georg Brandlf78e02b2008-06-10 17:40:04 +00001108 # default -- use global socket timeout
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +02001109 self.assertIsNone(socket.getdefaulttimeout())
Georg Brandlf78e02b2008-06-10 17:40:04 +00001110 socket.setdefaulttimeout(30)
1111 try:
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001112 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT)
Georg Brandlf78e02b2008-06-10 17:40:04 +00001113 httpConn.connect()
1114 finally:
1115 socket.setdefaulttimeout(None)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001116 self.assertEqual(httpConn.sock.gettimeout(), 30)
1117 httpConn.close()
1118
Georg Brandlf78e02b2008-06-10 17:40:04 +00001119 # no timeout -- do not use global socket default
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +02001120 self.assertIsNone(socket.getdefaulttimeout())
Guido van Rossumd8faa362007-04-27 19:54:29 +00001121 socket.setdefaulttimeout(30)
1122 try:
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001123 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT,
Christian Heimes5e696852008-04-09 08:37:03 +00001124 timeout=None)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001125 httpConn.connect()
1126 finally:
Georg Brandlf78e02b2008-06-10 17:40:04 +00001127 socket.setdefaulttimeout(None)
1128 self.assertEqual(httpConn.sock.gettimeout(), None)
1129 httpConn.close()
1130
1131 # a value
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001132 httpConn = client.HTTPConnection(HOST, TimeoutTest.PORT, timeout=30)
Georg Brandlf78e02b2008-06-10 17:40:04 +00001133 httpConn.connect()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001134 self.assertEqual(httpConn.sock.gettimeout(), 30)
1135 httpConn.close()
1136
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001137
1138class HTTPSTest(TestCase):
1139
1140 def setUp(self):
1141 if not hasattr(client, 'HTTPSConnection'):
1142 self.skipTest('ssl support required')
1143
1144 def make_server(self, certfile):
1145 from test.ssl_servers import make_https_server
Antoine Pitrouda232592013-02-05 21:20:51 +01001146 return make_https_server(self, certfile=certfile)
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001147
1148 def test_attributes(self):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001149 # simple test to check it's storing the timeout
1150 h = client.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
1151 self.assertEqual(h.timeout, 30)
1152
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001153 def test_networked(self):
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001154 # Default settings: requires a valid cert from a trusted CA
1155 import ssl
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001156 support.requires('network')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001157 with support.transient_internet('self-signed.pythontest.net'):
1158 h = client.HTTPSConnection('self-signed.pythontest.net', 443)
1159 with self.assertRaises(ssl.SSLError) as exc_info:
1160 h.request('GET', '/')
1161 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
1162
1163 def test_networked_noverification(self):
1164 # Switch off cert verification
1165 import ssl
1166 support.requires('network')
1167 with support.transient_internet('self-signed.pythontest.net'):
1168 context = ssl._create_unverified_context()
1169 h = client.HTTPSConnection('self-signed.pythontest.net', 443,
1170 context=context)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001171 h.request('GET', '/')
1172 resp = h.getresponse()
Victor Stinnerb389b482015-02-27 17:47:23 +01001173 h.close()
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001174 self.assertIn('nginx', resp.getheader('server'))
1175
Benjamin Peterson2615e9e2014-11-25 15:16:55 -06001176 @support.system_must_validate_cert
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001177 def test_networked_trusted_by_default_cert(self):
1178 # Default settings: requires a valid cert from a trusted CA
1179 support.requires('network')
1180 with support.transient_internet('www.python.org'):
1181 h = client.HTTPSConnection('www.python.org', 443)
1182 h.request('GET', '/')
1183 resp = h.getresponse()
1184 content_type = resp.getheader('content-type')
Victor Stinnerb389b482015-02-27 17:47:23 +01001185 h.close()
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001186 self.assertIn('text/html', content_type)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001187
1188 def test_networked_good_cert(self):
Georg Brandlfbaf9312014-11-05 20:37:40 +01001189 # We feed the server's cert as a validating cert
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001190 import ssl
1191 support.requires('network')
Georg Brandlfbaf9312014-11-05 20:37:40 +01001192 with support.transient_internet('self-signed.pythontest.net'):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001193 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1194 context.verify_mode = ssl.CERT_REQUIRED
Georg Brandlfbaf9312014-11-05 20:37:40 +01001195 context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
1196 h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001197 h.request('GET', '/')
1198 resp = h.getresponse()
Georg Brandlfbaf9312014-11-05 20:37:40 +01001199 server_string = resp.getheader('server')
Victor Stinnerb389b482015-02-27 17:47:23 +01001200 h.close()
Georg Brandlfbaf9312014-11-05 20:37:40 +01001201 self.assertIn('nginx', server_string)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001202
1203 def test_networked_bad_cert(self):
1204 # We feed a "CA" cert that is unrelated to the server's cert
1205 import ssl
1206 support.requires('network')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001207 with support.transient_internet('self-signed.pythontest.net'):
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001208 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1209 context.verify_mode = ssl.CERT_REQUIRED
1210 context.load_verify_locations(CERT_localhost)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001211 h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
1212 with self.assertRaises(ssl.SSLError) as exc_info:
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001213 h.request('GET', '/')
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001214 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
1215
1216 def test_local_unknown_cert(self):
1217 # The custom cert isn't known to the default trust bundle
1218 import ssl
1219 server = self.make_server(CERT_localhost)
1220 h = client.HTTPSConnection('localhost', server.port)
1221 with self.assertRaises(ssl.SSLError) as exc_info:
1222 h.request('GET', '/')
1223 self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001224
1225 def test_local_good_hostname(self):
1226 # The (valid) cert validates the HTTP hostname
1227 import ssl
Brett Cannon252365b2011-08-04 22:43:11 -07001228 server = self.make_server(CERT_localhost)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001229 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1230 context.verify_mode = ssl.CERT_REQUIRED
1231 context.load_verify_locations(CERT_localhost)
1232 h = client.HTTPSConnection('localhost', server.port, context=context)
1233 h.request('GET', '/nonexistent')
1234 resp = h.getresponse()
1235 self.assertEqual(resp.status, 404)
1236
1237 def test_local_bad_hostname(self):
1238 # The (valid) cert doesn't validate the HTTP hostname
1239 import ssl
Brett Cannon252365b2011-08-04 22:43:11 -07001240 server = self.make_server(CERT_fakehostname)
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001241 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1242 context.verify_mode = ssl.CERT_REQUIRED
Benjamin Petersona090f012014-12-07 13:18:25 -05001243 context.check_hostname = True
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001244 context.load_verify_locations(CERT_fakehostname)
1245 h = client.HTTPSConnection('localhost', server.port, context=context)
1246 with self.assertRaises(ssl.CertificateError):
1247 h.request('GET', '/')
1248 # Same with explicit check_hostname=True
1249 h = client.HTTPSConnection('localhost', server.port, context=context,
1250 check_hostname=True)
1251 with self.assertRaises(ssl.CertificateError):
1252 h.request('GET', '/')
1253 # With check_hostname=False, the mismatching is ignored
Benjamin Petersona090f012014-12-07 13:18:25 -05001254 context.check_hostname = False
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001255 h = client.HTTPSConnection('localhost', server.port, context=context,
1256 check_hostname=False)
1257 h.request('GET', '/nonexistent')
1258 resp = h.getresponse()
1259 self.assertEqual(resp.status, 404)
Benjamin Petersona090f012014-12-07 13:18:25 -05001260 # The context's check_hostname setting is used if one isn't passed to
1261 # HTTPSConnection.
1262 context.check_hostname = False
1263 h = client.HTTPSConnection('localhost', server.port, context=context)
1264 h.request('GET', '/nonexistent')
1265 self.assertEqual(h.getresponse().status, 404)
1266 # Passing check_hostname to HTTPSConnection should override the
1267 # context's setting.
1268 h = client.HTTPSConnection('localhost', server.port, context=context,
1269 check_hostname=True)
1270 with self.assertRaises(ssl.CertificateError):
1271 h.request('GET', '/')
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001272
Petri Lehtinene119c402011-10-26 21:29:15 +03001273 @unittest.skipIf(not hasattr(client, 'HTTPSConnection'),
1274 'http.client.HTTPSConnection not available')
Łukasz Langaa5a9a9c2011-10-18 21:17:39 +02001275 def test_host_port(self):
1276 # Check invalid host_port
1277
1278 for hp in ("www.python.org:abc", "user:password@www.python.org"):
1279 self.assertRaises(client.InvalidURL, client.HTTPSConnection, hp)
1280
1281 for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
1282 "fe80::207:e9ff:fe9b", 8000),
1283 ("www.python.org:443", "www.python.org", 443),
1284 ("www.python.org:", "www.python.org", 443),
1285 ("www.python.org", "www.python.org", 443),
1286 ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
1287 ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
1288 443)):
1289 c = client.HTTPSConnection(hp)
1290 self.assertEqual(h, c.host)
1291 self.assertEqual(p, c.port)
1292
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001293
Jeremy Hylton236654b2009-03-27 20:24:34 +00001294class RequestBodyTest(TestCase):
1295 """Test cases where a request includes a message body."""
1296
1297 def setUp(self):
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001298 self.conn = client.HTTPConnection('example.com')
Jeremy Hylton636950f2009-03-28 04:34:21 +00001299 self.conn.sock = self.sock = FakeSocket("")
Jeremy Hylton236654b2009-03-27 20:24:34 +00001300 self.conn.sock = self.sock
1301
1302 def get_headers_and_fp(self):
1303 f = io.BytesIO(self.sock.data)
1304 f.readline() # read the request line
Jeremy Hylton7c1692d2009-03-27 21:31:03 +00001305 message = client.parse_headers(f)
Jeremy Hylton236654b2009-03-27 20:24:34 +00001306 return message, f
1307
1308 def test_manual_content_length(self):
1309 # Set an incorrect content-length so that we can verify that
1310 # it will not be over-ridden by the library.
1311 self.conn.request("PUT", "/url", "body",
1312 {"Content-Length": "42"})
1313 message, f = self.get_headers_and_fp()
1314 self.assertEqual("42", message.get("content-length"))
1315 self.assertEqual(4, len(f.read()))
1316
1317 def test_ascii_body(self):
1318 self.conn.request("PUT", "/url", "body")
1319 message, f = self.get_headers_and_fp()
1320 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001321 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001322 self.assertEqual("4", message.get("content-length"))
1323 self.assertEqual(b'body', f.read())
1324
1325 def test_latin1_body(self):
1326 self.conn.request("PUT", "/url", "body\xc1")
1327 message, f = self.get_headers_and_fp()
1328 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001329 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001330 self.assertEqual("5", message.get("content-length"))
1331 self.assertEqual(b'body\xc1', f.read())
1332
1333 def test_bytes_body(self):
1334 self.conn.request("PUT", "/url", b"body\xc1")
1335 message, f = self.get_headers_and_fp()
1336 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001337 self.assertIsNone(message.get_charset())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001338 self.assertEqual("5", message.get("content-length"))
1339 self.assertEqual(b'body\xc1', f.read())
1340
1341 def test_file_body(self):
Victor Stinner18d15cb2011-09-21 01:09:04 +02001342 self.addCleanup(support.unlink, support.TESTFN)
Brett Cannon77b7de62010-10-29 23:31:11 +00001343 with open(support.TESTFN, "w") as f:
1344 f.write("body")
1345 with open(support.TESTFN) as f:
1346 self.conn.request("PUT", "/url", f)
1347 message, f = self.get_headers_and_fp()
1348 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001349 self.assertIsNone(message.get_charset())
Brett Cannon77b7de62010-10-29 23:31:11 +00001350 self.assertEqual("4", message.get("content-length"))
1351 self.assertEqual(b'body', f.read())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001352
1353 def test_binary_file_body(self):
Victor Stinner18d15cb2011-09-21 01:09:04 +02001354 self.addCleanup(support.unlink, support.TESTFN)
Brett Cannon77b7de62010-10-29 23:31:11 +00001355 with open(support.TESTFN, "wb") as f:
1356 f.write(b"body\xc1")
1357 with open(support.TESTFN, "rb") as f:
1358 self.conn.request("PUT", "/url", f)
1359 message, f = self.get_headers_and_fp()
1360 self.assertEqual("text/plain", message.get_content_type())
Raymond Hettinger7beae8a2011-01-06 05:34:17 +00001361 self.assertIsNone(message.get_charset())
Brett Cannon77b7de62010-10-29 23:31:11 +00001362 self.assertEqual("5", message.get("content-length"))
1363 self.assertEqual(b'body\xc1', f.read())
Jeremy Hylton236654b2009-03-27 20:24:34 +00001364
Senthil Kumaran9f8dc442010-08-02 11:04:58 +00001365
1366class HTTPResponseTest(TestCase):
1367
1368 def setUp(self):
1369 body = "HTTP/1.1 200 Ok\r\nMy-Header: first-value\r\nMy-Header: \
1370 second-value\r\n\r\nText"
1371 sock = FakeSocket(body)
1372 self.resp = client.HTTPResponse(sock)
1373 self.resp.begin()
1374
1375 def test_getting_header(self):
1376 header = self.resp.getheader('My-Header')
1377 self.assertEqual(header, 'first-value, second-value')
1378
1379 header = self.resp.getheader('My-Header', 'some default')
1380 self.assertEqual(header, 'first-value, second-value')
1381
1382 def test_getting_nonexistent_header_with_string_default(self):
1383 header = self.resp.getheader('No-Such-Header', 'default-value')
1384 self.assertEqual(header, 'default-value')
1385
1386 def test_getting_nonexistent_header_with_iterable_default(self):
1387 header = self.resp.getheader('No-Such-Header', ['default', 'values'])
1388 self.assertEqual(header, 'default, values')
1389
1390 header = self.resp.getheader('No-Such-Header', ('default', 'values'))
1391 self.assertEqual(header, 'default, values')
1392
1393 def test_getting_nonexistent_header_without_default(self):
1394 header = self.resp.getheader('No-Such-Header')
1395 self.assertEqual(header, None)
1396
1397 def test_getting_header_defaultint(self):
1398 header = self.resp.getheader('No-Such-Header',default=42)
1399 self.assertEqual(header, 42)
1400
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001401class TunnelTests(TestCase):
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001402 def setUp(self):
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001403 response_text = (
1404 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
1405 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
1406 'Content-Length: 42\r\n\r\n'
1407 )
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001408 self.host = 'proxy.com'
1409 self.conn = client.HTTPConnection(self.host)
Berker Peksagab53ab02015-02-03 12:22:11 +02001410 self.conn._create_connection = self._create_connection(response_text)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001411
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001412 def tearDown(self):
1413 self.conn.close()
1414
Berker Peksagab53ab02015-02-03 12:22:11 +02001415 def _create_connection(self, response_text):
1416 def create_connection(address, timeout=None, source_address=None):
1417 return FakeSocket(response_text, host=address[0], port=address[1])
1418 return create_connection
1419
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001420 def test_set_tunnel_host_port_headers(self):
1421 tunnel_host = 'destination.com'
1422 tunnel_port = 8888
1423 tunnel_headers = {'User-Agent': 'Mozilla/5.0 (compatible, MSIE 11)'}
1424 self.conn.set_tunnel(tunnel_host, port=tunnel_port,
1425 headers=tunnel_headers)
1426 self.conn.request('HEAD', '/', '')
1427 self.assertEqual(self.conn.sock.host, self.host)
1428 self.assertEqual(self.conn.sock.port, client.HTTP_PORT)
1429 self.assertEqual(self.conn._tunnel_host, tunnel_host)
1430 self.assertEqual(self.conn._tunnel_port, tunnel_port)
1431 self.assertEqual(self.conn._tunnel_headers, tunnel_headers)
1432
1433 def test_disallow_set_tunnel_after_connect(self):
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001434 # Once connected, we shouldn't be able to tunnel anymore
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001435 self.conn.connect()
1436 self.assertRaises(RuntimeError, self.conn.set_tunnel,
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001437 'destination.com')
1438
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001439 def test_connect_with_tunnel(self):
1440 self.conn.set_tunnel('destination.com')
1441 self.conn.request('HEAD', '/', '')
1442 self.assertEqual(self.conn.sock.host, self.host)
1443 self.assertEqual(self.conn.sock.port, client.HTTP_PORT)
1444 self.assertIn(b'CONNECT destination.com', self.conn.sock.data)
Serhiy Storchaka4ac7ed92014-12-12 09:29:15 +02001445 # issue22095
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001446 self.assertNotIn(b'Host: destination.com:None', self.conn.sock.data)
1447 self.assertIn(b'Host: destination.com', self.conn.sock.data)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001448
1449 # This test should be removed when CONNECT gets the HTTP/1.1 blessing
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001450 self.assertNotIn(b'Host: proxy.com', self.conn.sock.data)
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001451
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001452 def test_connect_put_request(self):
1453 self.conn.set_tunnel('destination.com')
1454 self.conn.request('PUT', '/', '')
1455 self.assertEqual(self.conn.sock.host, self.host)
1456 self.assertEqual(self.conn.sock.port, client.HTTP_PORT)
1457 self.assertIn(b'CONNECT destination.com', self.conn.sock.data)
1458 self.assertIn(b'Host: destination.com', self.conn.sock.data)
1459
Berker Peksagab53ab02015-02-03 12:22:11 +02001460 def test_tunnel_debuglog(self):
1461 expected_header = 'X-Dummy: 1'
1462 response_text = 'HTTP/1.0 200 OK\r\n{}\r\n\r\n'.format(expected_header)
1463
1464 self.conn.set_debuglevel(1)
1465 self.conn._create_connection = self._create_connection(response_text)
1466 self.conn.set_tunnel('destination.com')
1467
1468 with support.captured_stdout() as output:
1469 self.conn.request('PUT', '/', '')
1470 lines = output.getvalue().splitlines()
1471 self.assertIn('header: {}'.format(expected_header), lines)
Senthil Kumarane6cc7012015-01-24 19:24:59 -08001472
Senthil Kumaran9da047b2014-04-14 13:07:56 -04001473
Benjamin Peterson9566de12014-12-13 16:13:24 -05001474@support.reap_threads
Jeremy Hylton2c178252004-08-07 16:28:14 +00001475def test_main(verbose=None):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001476 support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
Antoine Pitrou803e6d62010-10-13 10:36:15 +00001477 HTTPSTest, RequestBodyTest, SourceAddressTest,
Kristján Valur Jónsson8e5d0ca2014-03-19 10:07:26 +00001478 HTTPResponseTest, ExtendedReadTest,
Senthil Kumaran166214c2014-04-14 13:10:05 -04001479 ExtendedReadTestChunked, TunnelTests)
Jeremy Hylton2c178252004-08-07 16:28:14 +00001480
Thomas Wouters89f507f2006-12-13 04:49:30 +00001481if __name__ == '__main__':
1482 test_main()