blob: 801f0fd647f4abeafae21ceece2fb11007106ceb [file] [log] [blame]
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001"""Regression tests for what was in Python 2's "urllib" module"""
Brett Cannon74bfd702003-04-25 09:39:47 +00002
Jeremy Hylton1afc1692008-06-18 20:49:58 +00003import urllib.parse
4import urllib.request
guido@google.coma119df92011-03-29 11:41:02 -07005import urllib.error
Georg Brandl24420152008-05-26 16:32:26 +00006import http.client
Barry Warsaw820c1202008-06-12 04:06:45 +00007import email.message
Jeremy Hylton66dc8c52007-08-04 03:42:26 +00008import io
Brett Cannon74bfd702003-04-25 09:39:47 +00009import unittest
Benjamin Peterson3c2dca62014-06-07 15:08:04 -070010from unittest.mock import patch
Benjamin Petersonee8712c2008-05-20 21:35:26 +000011from test import support
Brett Cannon74bfd702003-04-25 09:39:47 +000012import os
Antoine Pitrou07df6552014-11-02 17:23:14 +010013try:
14 import ssl
15except ImportError:
16 ssl = None
Senthil Kumaran2d2ea1b2011-04-14 13:16:30 +080017import sys
Georg Brandl5a650a22005-08-26 08:51:34 +000018import tempfile
Senthil Kumaran277e9092013-04-10 20:51:19 -070019from nturl2path import url2pathname, pathname2url
Jeremy Hylton6102e292000-08-31 15:48:10 +000020
Senthil Kumaranc5c5a142012-01-14 19:09:04 +080021from base64 import b64encode
Georg Brandl2daf6ae2012-02-20 19:54:16 +010022import collections
Senthil Kumaranc5c5a142012-01-14 19:09:04 +080023
Senthil Kumaran8b081b72013-04-10 20:53:12 -070024
Brett Cannon74bfd702003-04-25 09:39:47 +000025def hexescape(char):
26 """Escape char as RFC 2396 specifies"""
27 hex_repr = hex(ord(char))[2:].upper()
28 if len(hex_repr) == 1:
29 hex_repr = "0%s" % hex_repr
30 return "%" + hex_repr
Jeremy Hylton6102e292000-08-31 15:48:10 +000031
Jeremy Hylton1afc1692008-06-18 20:49:58 +000032# Shortcut for testing FancyURLopener
33_urlopener = None
Senthil Kumaran277e9092013-04-10 20:51:19 -070034
35
Jeremy Hylton1afc1692008-06-18 20:49:58 +000036def urlopen(url, data=None, proxies=None):
37 """urlopen(url [, data]) -> open file-like object"""
38 global _urlopener
39 if proxies is not None:
40 opener = urllib.request.FancyURLopener(proxies=proxies)
41 elif not _urlopener:
Martin Pantera0370222016-02-04 06:01:35 +000042 opener = FancyURLopener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +000043 _urlopener = opener
44 else:
45 opener = _urlopener
46 if data is None:
47 return opener.open(url)
48 else:
49 return opener.open(url, data)
50
Senthil Kumarance260142011-11-01 01:35:17 +080051
Martin Pantera0370222016-02-04 06:01:35 +000052def FancyURLopener():
53 with support.check_warnings(
54 ('FancyURLopener style of invoking requests is deprecated.',
55 DeprecationWarning)):
56 return urllib.request.FancyURLopener()
57
58
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -070059def fakehttp(fakedata, mock_close=False):
Serhiy Storchakaf54c3502014-09-06 21:41:39 +030060 class FakeSocket(io.BytesIO):
61 io_refs = 1
62
63 def sendall(self, data):
64 FakeHTTPConnection.buf = data
65
66 def makefile(self, *args, **kwds):
67 self.io_refs += 1
68 return self
69
70 def read(self, amt=None):
71 if self.closed:
72 return b""
73 return io.BytesIO.read(self, amt)
74
75 def readline(self, length=None):
76 if self.closed:
77 return b""
78 return io.BytesIO.readline(self, length)
79
80 def close(self):
81 self.io_refs -= 1
82 if self.io_refs == 0:
83 io.BytesIO.close(self)
84
85 class FakeHTTPConnection(http.client.HTTPConnection):
86
87 # buffer to store data for verification in urlopen tests.
88 buf = None
Serhiy Storchakaf54c3502014-09-06 21:41:39 +030089
90 def connect(self):
Martin Panterce6e0682016-05-16 01:07:13 +000091 self.sock = FakeSocket(self.fakedata)
92 type(self).fakesock = self.sock
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -070093
94 if mock_close:
95 # bpo-36918: HTTPConnection destructor calls close() which calls
96 # flush(). Problem: flush() calls self.fp.flush() which raises
97 # "ValueError: I/O operation on closed file" which is logged as an
98 # "Exception ignored in". Override close() to silence this error.
99 def close(self):
100 pass
Martin Panterce6e0682016-05-16 01:07:13 +0000101 FakeHTTPConnection.fakedata = fakedata
Serhiy Storchakaf54c3502014-09-06 21:41:39 +0300102
103 return FakeHTTPConnection
104
105
Senthil Kumarance260142011-11-01 01:35:17 +0800106class FakeHTTPMixin(object):
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -0700107 def fakehttp(self, fakedata, mock_close=False):
108 fake_http_class = fakehttp(fakedata, mock_close=mock_close)
Senthil Kumarance260142011-11-01 01:35:17 +0800109 self._connection_class = http.client.HTTPConnection
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -0700110 http.client.HTTPConnection = fake_http_class
Senthil Kumarance260142011-11-01 01:35:17 +0800111
112 def unfakehttp(self):
113 http.client.HTTPConnection = self._connection_class
114
115
Benjamin Peterson3c2dca62014-06-07 15:08:04 -0700116class FakeFTPMixin(object):
117 def fakeftp(self):
118 class FakeFtpWrapper(object):
119 def __init__(self, user, passwd, host, port, dirs, timeout=None,
120 persistent=True):
121 pass
122
123 def retrfile(self, file, type):
124 return io.BytesIO(), 0
125
126 def close(self):
127 pass
128
129 self._ftpwrapper_class = urllib.request.ftpwrapper
130 urllib.request.ftpwrapper = FakeFtpWrapper
131
132 def unfakeftp(self):
133 urllib.request.ftpwrapper = self._ftpwrapper_class
134
135
Brett Cannon74bfd702003-04-25 09:39:47 +0000136class urlopen_FileTests(unittest.TestCase):
137 """Test urlopen() opening a temporary file.
Jeremy Hylton6102e292000-08-31 15:48:10 +0000138
Brett Cannon74bfd702003-04-25 09:39:47 +0000139 Try to test as much functionality as possible so as to cut down on reliance
Andrew M. Kuchlingf1a2f9e2004-06-29 13:07:53 +0000140 on connecting to the Net for testing.
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +0000141
Brett Cannon74bfd702003-04-25 09:39:47 +0000142 """
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +0000143
Brett Cannon74bfd702003-04-25 09:39:47 +0000144 def setUp(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000145 # Create a temp file to use for testing
146 self.text = bytes("test_urllib: %s\n" % self.__class__.__name__,
147 "ascii")
148 f = open(support.TESTFN, 'wb')
Brett Cannon74bfd702003-04-25 09:39:47 +0000149 try:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000150 f.write(self.text)
Brett Cannon74bfd702003-04-25 09:39:47 +0000151 finally:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000152 f.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000153 self.pathname = support.TESTFN
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000154 self.returned_obj = urlopen("file:%s" % self.pathname)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +0000155
Brett Cannon74bfd702003-04-25 09:39:47 +0000156 def tearDown(self):
157 """Shut down the open object"""
158 self.returned_obj.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000159 os.remove(support.TESTFN)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +0000160
Brett Cannon74bfd702003-04-25 09:39:47 +0000161 def test_interface(self):
162 # Make sure object returned by urlopen() has the specified methods
163 for attr in ("read", "readline", "readlines", "fileno",
Christian Heimes9bd667a2008-01-20 15:14:11 +0000164 "close", "info", "geturl", "getcode", "__iter__"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000165 self.assertTrue(hasattr(self.returned_obj, attr),
Brett Cannon74bfd702003-04-25 09:39:47 +0000166 "object returned by urlopen() lacks %s attribute" %
167 attr)
Skip Montanaroe78b92a2001-01-20 20:22:30 +0000168
Brett Cannon74bfd702003-04-25 09:39:47 +0000169 def test_read(self):
170 self.assertEqual(self.text, self.returned_obj.read())
Skip Montanaro080c9972001-01-28 21:12:22 +0000171
Brett Cannon74bfd702003-04-25 09:39:47 +0000172 def test_readline(self):
173 self.assertEqual(self.text, self.returned_obj.readline())
Guido van Rossuma0982942007-07-10 08:30:03 +0000174 self.assertEqual(b'', self.returned_obj.readline(),
Brett Cannon74bfd702003-04-25 09:39:47 +0000175 "calling readline() after exhausting the file did not"
176 " return an empty string")
Skip Montanaro080c9972001-01-28 21:12:22 +0000177
Brett Cannon74bfd702003-04-25 09:39:47 +0000178 def test_readlines(self):
179 lines_list = self.returned_obj.readlines()
180 self.assertEqual(len(lines_list), 1,
181 "readlines() returned the wrong number of lines")
182 self.assertEqual(lines_list[0], self.text,
183 "readlines() returned improper text")
Skip Montanaro080c9972001-01-28 21:12:22 +0000184
Brett Cannon74bfd702003-04-25 09:39:47 +0000185 def test_fileno(self):
186 file_num = self.returned_obj.fileno()
Ezio Melottie9615932010-01-24 19:26:24 +0000187 self.assertIsInstance(file_num, int, "fileno() did not return an int")
Brett Cannon74bfd702003-04-25 09:39:47 +0000188 self.assertEqual(os.read(file_num, len(self.text)), self.text,
189 "Reading on the file descriptor returned by fileno() "
190 "did not return the expected text")
Skip Montanaroe78b92a2001-01-20 20:22:30 +0000191
Brett Cannon74bfd702003-04-25 09:39:47 +0000192 def test_close(self):
Senthil Kumarand91ffca2011-03-19 17:25:27 +0800193 # Test close() by calling it here and then having it be called again
Brett Cannon74bfd702003-04-25 09:39:47 +0000194 # by the tearDown() method for the test
195 self.returned_obj.close()
Skip Montanaro080c9972001-01-28 21:12:22 +0000196
Brett Cannon74bfd702003-04-25 09:39:47 +0000197 def test_info(self):
Ezio Melottie9615932010-01-24 19:26:24 +0000198 self.assertIsInstance(self.returned_obj.info(), email.message.Message)
Skip Montanaroe78b92a2001-01-20 20:22:30 +0000199
Brett Cannon74bfd702003-04-25 09:39:47 +0000200 def test_geturl(self):
201 self.assertEqual(self.returned_obj.geturl(), self.pathname)
Skip Montanaro080c9972001-01-28 21:12:22 +0000202
Christian Heimes9bd667a2008-01-20 15:14:11 +0000203 def test_getcode(self):
Florent Xicluna419e3842010-08-08 16:16:07 +0000204 self.assertIsNone(self.returned_obj.getcode())
Christian Heimes9bd667a2008-01-20 15:14:11 +0000205
Brett Cannon74bfd702003-04-25 09:39:47 +0000206 def test_iter(self):
207 # Test iterator
208 # Don't need to count number of iterations since test would fail the
209 # instant it returned anything beyond the first line from the
Raymond Hettinger038018a2011-06-26 14:29:35 +0200210 # comparison.
211 # Use the iterator in the usual implicit way to test for ticket #4608.
212 for line in self.returned_obj:
Brett Cannon74bfd702003-04-25 09:39:47 +0000213 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +0000214
Senthil Kumaran3800ea92012-01-21 11:52:48 +0800215 def test_relativelocalfile(self):
216 self.assertRaises(ValueError,urllib.request.urlopen,'./' + self.pathname)
217
Senthil Kumaranefbd4ea2017-04-01 23:47:35 -0700218
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000219class ProxyTests(unittest.TestCase):
220
221 def setUp(self):
Walter Dörwaldb525e182009-04-26 21:39:21 +0000222 # Records changes to env vars
223 self.env = support.EnvironmentVarGuard()
Benjamin Peterson46a99002010-01-09 18:45:30 +0000224 # Delete all proxy related env vars
Antoine Pitroub3a88b52010-10-14 18:31:39 +0000225 for k in list(os.environ):
Antoine Pitrou8c8f1ac2010-10-14 18:32:54 +0000226 if 'proxy' in k.lower():
Benjamin Peterson46a99002010-01-09 18:45:30 +0000227 self.env.unset(k)
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000228
229 def tearDown(self):
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000230 # Restore all proxy related env vars
Walter Dörwaldb525e182009-04-26 21:39:21 +0000231 self.env.__exit__()
232 del self.env
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000233
234 def test_getproxies_environment_keep_no_proxies(self):
Walter Dörwaldb525e182009-04-26 21:39:21 +0000235 self.env.set('NO_PROXY', 'localhost')
236 proxies = urllib.request.getproxies_environment()
237 # getproxies_environment use lowered case truncated (no '_proxy') keys
Florent Xicluna419e3842010-08-08 16:16:07 +0000238 self.assertEqual('localhost', proxies['no'])
Senthil Kumaran89976f12011-08-06 12:27:40 +0800239 # List of no_proxies with space.
Senthil Kumarana7c0ff22016-04-25 08:16:23 -0700240 self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com:1234')
Senthil Kumaran89976f12011-08-06 12:27:40 +0800241 self.assertTrue(urllib.request.proxy_bypass_environment('anotherdomain.com'))
Senthil Kumarana7c0ff22016-04-25 08:16:23 -0700242 self.assertTrue(urllib.request.proxy_bypass_environment('anotherdomain.com:8888'))
243 self.assertTrue(urllib.request.proxy_bypass_environment('newdomain.com:1234'))
244
Senthil Kumaran4cbb23f2016-07-30 23:24:16 -0700245 def test_proxy_cgi_ignore(self):
246 try:
247 self.env.set('HTTP_PROXY', 'http://somewhere:3128')
248 proxies = urllib.request.getproxies_environment()
249 self.assertEqual('http://somewhere:3128', proxies['http'])
250 self.env.set('REQUEST_METHOD', 'GET')
251 proxies = urllib.request.getproxies_environment()
252 self.assertNotIn('http', proxies)
253 finally:
254 self.env.unset('REQUEST_METHOD')
255 self.env.unset('HTTP_PROXY')
256
Martin Panteraa279822016-04-30 01:03:40 +0000257 def test_proxy_bypass_environment_host_match(self):
258 bypass = urllib.request.proxy_bypass_environment
259 self.env.set('NO_PROXY',
Xiang Zhang959ff7f2017-01-09 11:47:55 +0800260 'localhost, anotherdomain.com, newdomain.com:1234, .d.o.t')
Martin Panteraa279822016-04-30 01:03:40 +0000261 self.assertTrue(bypass('localhost'))
262 self.assertTrue(bypass('LocalHost')) # MixedCase
263 self.assertTrue(bypass('LOCALHOST')) # UPPERCASE
264 self.assertTrue(bypass('newdomain.com:1234'))
Xiang Zhang959ff7f2017-01-09 11:47:55 +0800265 self.assertTrue(bypass('foo.d.o.t')) # issue 29142
Martin Panteraa279822016-04-30 01:03:40 +0000266 self.assertTrue(bypass('anotherdomain.com:8888'))
267 self.assertTrue(bypass('www.newdomain.com:1234'))
268 self.assertFalse(bypass('prelocalhost'))
269 self.assertFalse(bypass('newdomain.com')) # no port
270 self.assertFalse(bypass('newdomain.com:1235')) # wrong port
Senthil Kumarana7c0ff22016-04-25 08:16:23 -0700271
Senthil Kumaranefbd4ea2017-04-01 23:47:35 -0700272
Senthil Kumarana7c0ff22016-04-25 08:16:23 -0700273class ProxyTests_withOrderedEnv(unittest.TestCase):
274
275 def setUp(self):
276 # We need to test conditions, where variable order _is_ significant
277 self._saved_env = os.environ
278 # Monkey patch os.environ, start with empty fake environment
279 os.environ = collections.OrderedDict()
280
281 def tearDown(self):
282 os.environ = self._saved_env
283
284 def test_getproxies_environment_prefer_lowercase(self):
285 # Test lowercase preference with removal
286 os.environ['no_proxy'] = ''
287 os.environ['No_Proxy'] = 'localhost'
288 self.assertFalse(urllib.request.proxy_bypass_environment('localhost'))
289 self.assertFalse(urllib.request.proxy_bypass_environment('arbitrary'))
290 os.environ['http_proxy'] = ''
291 os.environ['HTTP_PROXY'] = 'http://somewhere:3128'
292 proxies = urllib.request.getproxies_environment()
293 self.assertEqual({}, proxies)
294 # Test lowercase preference of proxy bypass and correct matching including ports
295 os.environ['no_proxy'] = 'localhost, noproxy.com, my.proxy:1234'
296 os.environ['No_Proxy'] = 'xyz.com'
297 self.assertTrue(urllib.request.proxy_bypass_environment('localhost'))
298 self.assertTrue(urllib.request.proxy_bypass_environment('noproxy.com:5678'))
299 self.assertTrue(urllib.request.proxy_bypass_environment('my.proxy:1234'))
300 self.assertFalse(urllib.request.proxy_bypass_environment('my.proxy'))
301 self.assertFalse(urllib.request.proxy_bypass_environment('arbitrary'))
302 # Test lowercase preference with replacement
303 os.environ['http_proxy'] = 'http://somewhere:3128'
304 os.environ['Http_Proxy'] = 'http://somewhereelse:3128'
305 proxies = urllib.request.getproxies_environment()
306 self.assertEqual('http://somewhere:3128', proxies['http'])
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000307
Senthil Kumaranefbd4ea2017-04-01 23:47:35 -0700308
Benjamin Peterson3c2dca62014-06-07 15:08:04 -0700309class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin):
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000310 """Test urlopen() opening a fake http connection."""
311
Antoine Pitrou988dbd72010-12-17 17:35:56 +0000312 def check_read(self, ver):
313 self.fakehttp(b"HTTP/" + ver + b" 200 OK\r\n\r\nHello!")
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000314 try:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000315 fp = urlopen("http://python.org/")
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000316 self.assertEqual(fp.readline(), b"Hello!")
317 self.assertEqual(fp.readline(), b"")
Christian Heimes9bd667a2008-01-20 15:14:11 +0000318 self.assertEqual(fp.geturl(), 'http://python.org/')
319 self.assertEqual(fp.getcode(), 200)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000320 finally:
321 self.unfakehttp()
322
Senthil Kumaran26430412011-04-13 07:01:19 +0800323 def test_url_fragment(self):
324 # Issue #11703: geturl() omits fragments in the original URL.
325 url = 'http://docs.python.org/library/urllib.html#OK'
Senthil Kumaranb17abb12011-04-13 07:22:29 +0800326 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!")
Senthil Kumaran26430412011-04-13 07:01:19 +0800327 try:
328 fp = urllib.request.urlopen(url)
329 self.assertEqual(fp.geturl(), url)
330 finally:
331 self.unfakehttp()
332
Senthil Kumarand91ffca2011-03-19 17:25:27 +0800333 def test_willclose(self):
334 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!")
Senthil Kumaranacbaa922011-03-20 05:30:16 +0800335 try:
336 resp = urlopen("http://www.python.org")
337 self.assertTrue(resp.fp.will_close)
338 finally:
339 self.unfakehttp()
Senthil Kumarand91ffca2011-03-19 17:25:27 +0800340
Xtreak2fc936e2019-05-01 17:29:49 +0530341 @unittest.skipUnless(ssl, "ssl module required")
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700342 def test_url_with_control_char_rejected(self):
343 for char_no in list(range(0, 0x21)) + [0x7f]:
344 char = chr(char_no)
345 schemeless_url = f"//localhost:7777/test{char}/"
346 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.")
347 try:
348 # We explicitly test urllib.request.urlopen() instead of the top
349 # level 'def urlopen()' function defined in this... (quite ugly)
350 # test suite. They use different url opening codepaths. Plain
351 # urlopen uses FancyURLOpener which goes via a codepath that
352 # calls urllib.parse.quote() on the URL which makes all of the
353 # above attempts at injection within the url _path_ safe.
354 escaped_char_repr = repr(char).replace('\\', r'\\')
Gregory P. Smithb7378d72019-05-01 16:39:21 -0400355 InvalidURL = http.client.InvalidURL
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700356 with self.assertRaisesRegex(
Gregory P. Smithb7378d72019-05-01 16:39:21 -0400357 InvalidURL, f"contain control.*{escaped_char_repr}"):
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700358 urllib.request.urlopen(f"http:{schemeless_url}")
359 with self.assertRaisesRegex(
Gregory P. Smithb7378d72019-05-01 16:39:21 -0400360 InvalidURL, f"contain control.*{escaped_char_repr}"):
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700361 urllib.request.urlopen(f"https:{schemeless_url}")
362 # This code path quotes the URL so there is no injection.
363 resp = urlopen(f"http:{schemeless_url}")
364 self.assertNotIn(char, resp.geturl())
365 finally:
366 self.unfakehttp()
367
Xtreak2fc936e2019-05-01 17:29:49 +0530368 @unittest.skipUnless(ssl, "ssl module required")
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700369 def test_url_with_newline_header_injection_rejected(self):
370 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.")
371 host = "localhost:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123"
372 schemeless_url = "//" + host + ":8080/test/?test=a"
373 try:
374 # We explicitly test urllib.request.urlopen() instead of the top
375 # level 'def urlopen()' function defined in this... (quite ugly)
376 # test suite. They use different url opening codepaths. Plain
377 # urlopen uses FancyURLOpener which goes via a codepath that
378 # calls urllib.parse.quote() on the URL which makes all of the
379 # above attempts at injection within the url _path_ safe.
Gregory P. Smithb7378d72019-05-01 16:39:21 -0400380 InvalidURL = http.client.InvalidURL
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700381 with self.assertRaisesRegex(
Gregory P. Smithb7378d72019-05-01 16:39:21 -0400382 InvalidURL, r"contain control.*\\r.*(found at least . .)"):
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700383 urllib.request.urlopen(f"http:{schemeless_url}")
Gregory P. Smithb7378d72019-05-01 16:39:21 -0400384 with self.assertRaisesRegex(InvalidURL, r"contain control.*\\n"):
Gregory P. Smithc4e671e2019-04-30 19:12:21 -0700385 urllib.request.urlopen(f"https:{schemeless_url}")
386 # This code path quotes the URL so there is no injection.
387 resp = urlopen(f"http:{schemeless_url}")
388 self.assertNotIn(' ', resp.geturl())
389 self.assertNotIn('\r', resp.geturl())
390 self.assertNotIn('\n', resp.geturl())
391 finally:
392 self.unfakehttp()
393
Antoine Pitrou988dbd72010-12-17 17:35:56 +0000394 def test_read_0_9(self):
395 # "0.9" response accepted (but not "simple responses" without
396 # a status line)
397 self.check_read(b"0.9")
398
399 def test_read_1_0(self):
400 self.check_read(b"1.0")
401
402 def test_read_1_1(self):
403 self.check_read(b"1.1")
404
Christian Heimes57dddfb2008-01-02 18:30:52 +0000405 def test_read_bogus(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200406 # urlopen() should raise OSError for many error codes.
Christian Heimes57dddfb2008-01-02 18:30:52 +0000407 self.fakehttp(b'''HTTP/1.1 401 Authentication Required
408Date: Wed, 02 Jan 2008 03:03:54 GMT
409Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
410Connection: close
411Content-Type: text/html; charset=iso-8859-1
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -0700412''', mock_close=True)
Christian Heimes57dddfb2008-01-02 18:30:52 +0000413 try:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200414 self.assertRaises(OSError, urlopen, "http://python.org/")
Christian Heimes57dddfb2008-01-02 18:30:52 +0000415 finally:
416 self.unfakehttp()
417
guido@google.coma119df92011-03-29 11:41:02 -0700418 def test_invalid_redirect(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200419 # urlopen() should raise OSError for many error codes.
guido@google.coma119df92011-03-29 11:41:02 -0700420 self.fakehttp(b'''HTTP/1.1 302 Found
421Date: Wed, 02 Jan 2008 03:03:54 GMT
422Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
423Location: file://guidocomputer.athome.com:/python/license
424Connection: close
425Content-Type: text/html; charset=iso-8859-1
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -0700426''', mock_close=True)
guido@google.coma119df92011-03-29 11:41:02 -0700427 try:
Martin Pantera0370222016-02-04 06:01:35 +0000428 msg = "Redirection to url 'file:"
429 with self.assertRaisesRegex(urllib.error.HTTPError, msg):
430 urlopen("http://python.org/")
guido@google.coma119df92011-03-29 11:41:02 -0700431 finally:
432 self.unfakehttp()
433
Martin Pantera0370222016-02-04 06:01:35 +0000434 def test_redirect_limit_independent(self):
435 # Ticket #12923: make sure independent requests each use their
436 # own retry limit.
437 for i in range(FancyURLopener().maxtries):
438 self.fakehttp(b'''HTTP/1.1 302 Found
439Location: file://guidocomputer.athome.com:/python/license
440Connection: close
Miss Islington (bot)9d37ae02019-06-11 19:26:02 -0700441''', mock_close=True)
Martin Pantera0370222016-02-04 06:01:35 +0000442 try:
443 self.assertRaises(urllib.error.HTTPError, urlopen,
444 "http://something")
445 finally:
446 self.unfakehttp()
447
Guido van Rossumd8faa362007-04-27 19:54:29 +0000448 def test_empty_socket(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200449 # urlopen() raises OSError if the underlying socket does not send any
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000450 # data. (#1680230)
Christian Heimes57dddfb2008-01-02 18:30:52 +0000451 self.fakehttp(b'')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000452 try:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200453 self.assertRaises(OSError, urlopen, "http://something")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000454 finally:
455 self.unfakehttp()
456
Senthil Kumaranf5776862012-10-21 13:30:02 -0700457 def test_missing_localfile(self):
458 # Test for #10836
Senthil Kumaran3ebef362012-10-21 18:31:25 -0700459 with self.assertRaises(urllib.error.URLError) as e:
Senthil Kumaranf5776862012-10-21 13:30:02 -0700460 urlopen('file://localhost/a/file/which/doesnot/exists.py')
Senthil Kumaran3ebef362012-10-21 18:31:25 -0700461 self.assertTrue(e.exception.filename)
462 self.assertTrue(e.exception.reason)
463
464 def test_file_notexists(self):
465 fd, tmp_file = tempfile.mkstemp()
Senthil Kumaran3194d7c2012-10-23 09:40:53 -0700466 tmp_fileurl = 'file://localhost/' + tmp_file.replace(os.path.sep, '/')
Senthil Kumaranbf644c52012-10-23 11:07:02 -0700467 try:
468 self.assertTrue(os.path.exists(tmp_file))
469 with urlopen(tmp_fileurl) as fobj:
470 self.assertTrue(fobj)
471 finally:
472 os.close(fd)
473 os.unlink(tmp_file)
Senthil Kumaran3ebef362012-10-21 18:31:25 -0700474 self.assertFalse(os.path.exists(tmp_file))
475 with self.assertRaises(urllib.error.URLError):
476 urlopen(tmp_fileurl)
477
478 def test_ftp_nohost(self):
479 test_ftp_url = 'ftp:///path'
480 with self.assertRaises(urllib.error.URLError) as e:
481 urlopen(test_ftp_url)
482 self.assertFalse(e.exception.filename)
483 self.assertTrue(e.exception.reason)
484
485 def test_ftp_nonexisting(self):
486 with self.assertRaises(urllib.error.URLError) as e:
487 urlopen('ftp://localhost/a/file/which/doesnot/exists.py')
488 self.assertFalse(e.exception.filename)
489 self.assertTrue(e.exception.reason)
490
Benjamin Peterson3c2dca62014-06-07 15:08:04 -0700491 @patch.object(urllib.request, 'MAXFTPCACHE', 0)
492 def test_ftp_cache_pruning(self):
493 self.fakeftp()
494 try:
495 urllib.request.ftpcache['test'] = urllib.request.ftpwrapper('user', 'pass', 'localhost', 21, [])
496 urlopen('ftp://localhost')
497 finally:
498 self.unfakeftp()
499
Senthil Kumarande0eb242010-08-01 17:53:37 +0000500 def test_userpass_inurl(self):
Antoine Pitrou988dbd72010-12-17 17:35:56 +0000501 self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!")
Senthil Kumarande0eb242010-08-01 17:53:37 +0000502 try:
503 fp = urlopen("http://user:pass@python.org/")
504 self.assertEqual(fp.readline(), b"Hello!")
505 self.assertEqual(fp.readline(), b"")
506 self.assertEqual(fp.geturl(), 'http://user:pass@python.org/')
507 self.assertEqual(fp.getcode(), 200)
508 finally:
509 self.unfakehttp()
510
Senthil Kumaranc5c5a142012-01-14 19:09:04 +0800511 def test_userpass_inurl_w_spaces(self):
512 self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!")
513 try:
514 userpass = "a b:c d"
515 url = "http://{}@python.org/".format(userpass)
516 fakehttp_wrapper = http.client.HTTPConnection
517 authorization = ("Authorization: Basic %s\r\n" %
518 b64encode(userpass.encode("ASCII")).decode("ASCII"))
519 fp = urlopen(url)
520 # The authorization header must be in place
521 self.assertIn(authorization, fakehttp_wrapper.buf.decode("UTF-8"))
522 self.assertEqual(fp.readline(), b"Hello!")
523 self.assertEqual(fp.readline(), b"")
524 # the spaces are quoted in URL so no match
525 self.assertNotEqual(fp.geturl(), url)
526 self.assertEqual(fp.getcode(), 200)
527 finally:
528 self.unfakehttp()
529
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700530 def test_URLopener_deprecation(self):
531 with support.check_warnings(('',DeprecationWarning)):
Senthil Kumaran3ebef362012-10-21 18:31:25 -0700532 urllib.request.URLopener()
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700533
Antoine Pitrou07df6552014-11-02 17:23:14 +0100534 @unittest.skipUnless(ssl, "ssl module required")
Senthil Kumarana5c85b32014-09-19 15:23:30 +0800535 def test_cafile_and_context(self):
536 context = ssl.create_default_context()
Christian Heimesd0486372016-09-10 23:23:33 +0200537 with support.check_warnings(('', DeprecationWarning)):
538 with self.assertRaises(ValueError):
539 urllib.request.urlopen(
540 "https://localhost", cafile="/nonexistent/path", context=context
541 )
Senthil Kumarana5c85b32014-09-19 15:23:30 +0800542
Senthil Kumaranefbd4ea2017-04-01 23:47:35 -0700543
Antoine Pitroudf204be2012-11-24 17:59:08 +0100544class urlopen_DataTests(unittest.TestCase):
545 """Test urlopen() opening a data URL."""
546
547 def setUp(self):
548 # text containing URL special- and unicode-characters
549 self.text = "test data URLs :;,%=& \u00f6 \u00c4 "
550 # 2x1 pixel RGB PNG image with one black and one white pixel
551 self.image = (
552 b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x02\x00\x00\x00'
553 b'\x01\x08\x02\x00\x00\x00{@\xe8\xdd\x00\x00\x00\x01sRGB\x00\xae'
554 b'\xce\x1c\xe9\x00\x00\x00\x0fIDAT\x08\xd7c```\xf8\xff\xff?\x00'
555 b'\x06\x01\x02\xfe\no/\x1e\x00\x00\x00\x00IEND\xaeB`\x82')
556
557 self.text_url = (
558 "data:text/plain;charset=UTF-8,test%20data%20URLs%20%3A%3B%2C%25%3"
559 "D%26%20%C3%B6%20%C3%84%20")
560 self.text_url_base64 = (
561 "data:text/plain;charset=ISO-8859-1;base64,dGVzdCBkYXRhIFVSTHMgOjs"
562 "sJT0mIPYgxCA%3D")
563 # base64 encoded data URL that contains ignorable spaces,
564 # such as "\n", " ", "%0A", and "%20".
565 self.image_url = (
566 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAIAAAB7\n"
567 "QOjdAAAAAXNSR0IArs4c6QAAAA9JREFUCNdj%0AYGBg%2BP//PwAGAQL%2BCm8 "
568 "vHgAAAABJRU5ErkJggg%3D%3D%0A%20")
569
570 self.text_url_resp = urllib.request.urlopen(self.text_url)
571 self.text_url_base64_resp = urllib.request.urlopen(
572 self.text_url_base64)
573 self.image_url_resp = urllib.request.urlopen(self.image_url)
574
575 def test_interface(self):
576 # Make sure object returned by urlopen() has the specified methods
577 for attr in ("read", "readline", "readlines",
578 "close", "info", "geturl", "getcode", "__iter__"):
579 self.assertTrue(hasattr(self.text_url_resp, attr),
580 "object returned by urlopen() lacks %s attribute" %
581 attr)
582
583 def test_info(self):
584 self.assertIsInstance(self.text_url_resp.info(), email.message.Message)
585 self.assertEqual(self.text_url_base64_resp.info().get_params(),
586 [('text/plain', ''), ('charset', 'ISO-8859-1')])
587 self.assertEqual(self.image_url_resp.info()['content-length'],
588 str(len(self.image)))
589 self.assertEqual(urllib.request.urlopen("data:,").info().get_params(),
590 [('text/plain', ''), ('charset', 'US-ASCII')])
591
592 def test_geturl(self):
593 self.assertEqual(self.text_url_resp.geturl(), self.text_url)
594 self.assertEqual(self.text_url_base64_resp.geturl(),
595 self.text_url_base64)
596 self.assertEqual(self.image_url_resp.geturl(), self.image_url)
597
598 def test_read_text(self):
599 self.assertEqual(self.text_url_resp.read().decode(
600 dict(self.text_url_resp.info().get_params())['charset']), self.text)
601
602 def test_read_text_base64(self):
603 self.assertEqual(self.text_url_base64_resp.read().decode(
604 dict(self.text_url_base64_resp.info().get_params())['charset']),
605 self.text)
606
607 def test_read_image(self):
608 self.assertEqual(self.image_url_resp.read(), self.image)
609
610 def test_missing_comma(self):
611 self.assertRaises(ValueError,urllib.request.urlopen,'data:text/plain')
612
613 def test_invalid_base64_data(self):
614 # missing padding character
615 self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=')
616
Senthil Kumaranefbd4ea2017-04-01 23:47:35 -0700617
Brett Cannon19691362003-04-29 05:08:06 +0000618class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000619 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000620
Brett Cannon19691362003-04-29 05:08:06 +0000621 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000622 # Create a list of temporary files. Each item in the list is a file
623 # name (absolute path or relative to the current working directory).
624 # All files in this list will be deleted in the tearDown method. Note,
625 # this only helps to makes sure temporary files get deleted, but it
626 # does nothing about trying to close files that may still be open. It
627 # is the responsibility of the developer to properly close files even
628 # when exceptional conditions occur.
629 self.tempFiles = []
630
Brett Cannon19691362003-04-29 05:08:06 +0000631 # Create a temporary file.
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000632 self.registerFileForCleanUp(support.TESTFN)
Guido van Rossuma0982942007-07-10 08:30:03 +0000633 self.text = b'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000634 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000635 FILE = open(support.TESTFN, 'wb')
Georg Brandl5a650a22005-08-26 08:51:34 +0000636 FILE.write(self.text)
637 FILE.close()
638 finally:
639 try: FILE.close()
640 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000641
642 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000643 # Delete the temporary files.
644 for each in self.tempFiles:
645 try: os.remove(each)
646 except: pass
647
648 def constructLocalFileUrl(self, filePath):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000649 filePath = os.path.abspath(filePath)
650 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000651 filePath.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000652 except UnicodeEncodeError:
653 raise unittest.SkipTest("filePath is not encodable to utf8")
654 return "file://%s" % urllib.request.pathname2url(filePath)
Georg Brandl5a650a22005-08-26 08:51:34 +0000655
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000656 def createNewTempFile(self, data=b""):
Georg Brandl5a650a22005-08-26 08:51:34 +0000657 """Creates a new temporary file containing the specified data,
658 registers the file for deletion during the test fixture tear down, and
659 returns the absolute path of the file."""
660
661 newFd, newFilePath = tempfile.mkstemp()
662 try:
663 self.registerFileForCleanUp(newFilePath)
664 newFile = os.fdopen(newFd, "wb")
665 newFile.write(data)
666 newFile.close()
667 finally:
668 try: newFile.close()
669 except: pass
670 return newFilePath
671
672 def registerFileForCleanUp(self, fileName):
673 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000674
675 def test_basic(self):
676 # Make sure that a local file just gets its own location returned and
677 # a headers value is returned.
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000678 result = urllib.request.urlretrieve("file:%s" % support.TESTFN)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000679 self.assertEqual(result[0], support.TESTFN)
Ezio Melottie9615932010-01-24 19:26:24 +0000680 self.assertIsInstance(result[1], email.message.Message,
Martin Panter7462b6492015-11-02 03:37:02 +0000681 "did not get an email.message.Message instance "
Ezio Melottie9615932010-01-24 19:26:24 +0000682 "as second returned value")
Brett Cannon19691362003-04-29 05:08:06 +0000683
684 def test_copy(self):
685 # Test that setting the filename argument works.
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000686 second_temp = "%s.2" % support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000687 self.registerFileForCleanUp(second_temp)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000688 result = urllib.request.urlretrieve(self.constructLocalFileUrl(
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000689 support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000690 self.assertEqual(second_temp, result[0])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000691 self.assertTrue(os.path.exists(second_temp), "copy of the file was not "
Brett Cannon19691362003-04-29 05:08:06 +0000692 "made")
Alex Martelli01c77c62006-08-24 02:58:11 +0000693 FILE = open(second_temp, 'rb')
Brett Cannon19691362003-04-29 05:08:06 +0000694 try:
695 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000696 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000697 finally:
698 try: FILE.close()
699 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000700 self.assertEqual(self.text, text)
701
702 def test_reporthook(self):
703 # Make sure that the reporthook works.
Senthil Kumarane24f96a2012-03-13 19:29:33 -0700704 def hooktester(block_count, block_read_size, file_size, count_holder=[0]):
705 self.assertIsInstance(block_count, int)
706 self.assertIsInstance(block_read_size, int)
707 self.assertIsInstance(file_size, int)
708 self.assertEqual(block_count, count_holder[0])
Brett Cannon19691362003-04-29 05:08:06 +0000709 count_holder[0] = count_holder[0] + 1
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000710 second_temp = "%s.2" % support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000711 self.registerFileForCleanUp(second_temp)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000712 urllib.request.urlretrieve(
713 self.constructLocalFileUrl(support.TESTFN),
Georg Brandl5a650a22005-08-26 08:51:34 +0000714 second_temp, hooktester)
715
716 def test_reporthook_0_bytes(self):
717 # Test on zero length file. Should call reporthook only 1 time.
718 report = []
Senthil Kumarane24f96a2012-03-13 19:29:33 -0700719 def hooktester(block_count, block_read_size, file_size, _report=report):
720 _report.append((block_count, block_read_size, file_size))
Georg Brandl5a650a22005-08-26 08:51:34 +0000721 srcFileName = self.createNewTempFile()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000722 urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName),
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000723 support.TESTFN, hooktester)
Georg Brandl5a650a22005-08-26 08:51:34 +0000724 self.assertEqual(len(report), 1)
725 self.assertEqual(report[0][2], 0)
726
727 def test_reporthook_5_bytes(self):
728 # Test on 5 byte file. Should call reporthook only 2 times (once when
729 # the "network connection" is established and once when the block is
Senthil Kumarane24f96a2012-03-13 19:29:33 -0700730 # read).
Georg Brandl5a650a22005-08-26 08:51:34 +0000731 report = []
Senthil Kumarane24f96a2012-03-13 19:29:33 -0700732 def hooktester(block_count, block_read_size, file_size, _report=report):
733 _report.append((block_count, block_read_size, file_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000734 srcFileName = self.createNewTempFile(b"x" * 5)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000735 urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName),
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000736 support.TESTFN, hooktester)
Georg Brandl5a650a22005-08-26 08:51:34 +0000737 self.assertEqual(len(report), 2)
Gregory P. Smith6d9388f2012-11-10 15:12:55 -0800738 self.assertEqual(report[0][2], 5)
739 self.assertEqual(report[1][2], 5)
Georg Brandl5a650a22005-08-26 08:51:34 +0000740
741 def test_reporthook_8193_bytes(self):
742 # Test on 8193 byte file. Should call reporthook only 3 times (once
743 # when the "network connection" is established, once for the next 8192
744 # bytes, and once for the last byte).
745 report = []
Senthil Kumarane24f96a2012-03-13 19:29:33 -0700746 def hooktester(block_count, block_read_size, file_size, _report=report):
747 _report.append((block_count, block_read_size, file_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000748 srcFileName = self.createNewTempFile(b"x" * 8193)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000749 urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName),
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000750 support.TESTFN, hooktester)
Georg Brandl5a650a22005-08-26 08:51:34 +0000751 self.assertEqual(len(report), 3)
Gregory P. Smith6d9388f2012-11-10 15:12:55 -0800752 self.assertEqual(report[0][2], 8193)
753 self.assertEqual(report[0][1], 8192)
Senthil Kumarane24f96a2012-03-13 19:29:33 -0700754 self.assertEqual(report[1][1], 8192)
Gregory P. Smith6d9388f2012-11-10 15:12:55 -0800755 self.assertEqual(report[2][1], 8192)
Skip Montanaro080c9972001-01-28 21:12:22 +0000756
Senthil Kumarance260142011-11-01 01:35:17 +0800757
758class urlretrieve_HttpTests(unittest.TestCase, FakeHTTPMixin):
759 """Test urllib.urlretrieve() using fake http connections"""
760
761 def test_short_content_raises_ContentTooShortError(self):
762 self.fakehttp(b'''HTTP/1.1 200 OK
763Date: Wed, 02 Jan 2008 03:03:54 GMT
764Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
765Connection: close
766Content-Length: 100
767Content-Type: text/html; charset=iso-8859-1
768
769FF
770''')
771
772 def _reporthook(par1, par2, par3):
773 pass
774
775 with self.assertRaises(urllib.error.ContentTooShortError):
776 try:
Stéphane Wirtela40681d2019-02-22 14:45:36 +0100777 urllib.request.urlretrieve(support.TEST_HTTP_URL,
Senthil Kumarance260142011-11-01 01:35:17 +0800778 reporthook=_reporthook)
779 finally:
780 self.unfakehttp()
781
782 def test_short_content_raises_ContentTooShortError_without_reporthook(self):
783 self.fakehttp(b'''HTTP/1.1 200 OK
784Date: Wed, 02 Jan 2008 03:03:54 GMT
785Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
786Connection: close
787Content-Length: 100
788Content-Type: text/html; charset=iso-8859-1
789
790FF
791''')
792 with self.assertRaises(urllib.error.ContentTooShortError):
793 try:
Stéphane Wirtela40681d2019-02-22 14:45:36 +0100794 urllib.request.urlretrieve(support.TEST_HTTP_URL)
Senthil Kumarance260142011-11-01 01:35:17 +0800795 finally:
796 self.unfakehttp()
797
798
Brett Cannon74bfd702003-04-25 09:39:47 +0000799class QuotingTests(unittest.TestCase):
R David Murray44b548d2016-09-08 13:59:53 -0400800 r"""Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000801
Ratnadeep Debnath21024f02017-02-25 14:30:28 +0530802 According to RFC 3986 (Uniform Resource Identifiers), to escape a
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000803 character you write it as '%' + <2 character US-ASCII hex value>.
804 The Python code of ``'%' + hex(ord(<character>))[2:]`` escapes a
805 character properly. Case does not matter on the hex letters.
Brett Cannon74bfd702003-04-25 09:39:47 +0000806
807 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000808
Brett Cannon74bfd702003-04-25 09:39:47 +0000809 Reserved characters : ";/?:@&=+$,"
810 Have special meaning in URIs and must be escaped if not being used for
811 their special meaning
812 Data characters : letters, digits, and "-_.!~*'()"
813 Unreserved and do not need to be escaped; can be, though, if desired
814 Control characters : 0x00 - 0x1F, 0x7F
815 Have no use in URIs so must be escaped
816 space : 0x20
817 Must be escaped
818 Delimiters : '<>#%"'
819 Must be escaped
820 Unwise : "{}|\^[]`"
821 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000822
Brett Cannon74bfd702003-04-25 09:39:47 +0000823 """
824
825 def test_never_quote(self):
826 # Make sure quote() does not quote letters, digits, and "_,.-"
827 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
828 "abcdefghijklmnopqrstuvwxyz",
829 "0123456789",
Ratnadeep Debnath21024f02017-02-25 14:30:28 +0530830 "_.-~"])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000831 result = urllib.parse.quote(do_not_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000832 self.assertEqual(do_not_quote, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000833 "using quote(): %r != %r" % (do_not_quote, result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000834 result = urllib.parse.quote_plus(do_not_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000835 self.assertEqual(do_not_quote, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000836 "using quote_plus(): %r != %r" % (do_not_quote, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000837
838 def test_default_safe(self):
839 # Test '/' is default value for 'safe' parameter
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000840 self.assertEqual(urllib.parse.quote.__defaults__[0], '/')
Brett Cannon74bfd702003-04-25 09:39:47 +0000841
842 def test_safe(self):
843 # Test setting 'safe' parameter does what it should do
844 quote_by_default = "<>"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000845 result = urllib.parse.quote(quote_by_default, safe=quote_by_default)
Brett Cannon74bfd702003-04-25 09:39:47 +0000846 self.assertEqual(quote_by_default, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000847 "using quote(): %r != %r" % (quote_by_default, result))
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +0000848 result = urllib.parse.quote_plus(quote_by_default,
849 safe=quote_by_default)
Brett Cannon74bfd702003-04-25 09:39:47 +0000850 self.assertEqual(quote_by_default, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000851 "using quote_plus(): %r != %r" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000852 (quote_by_default, result))
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000853 # Safe expressed as bytes rather than str
854 result = urllib.parse.quote(quote_by_default, safe=b"<>")
855 self.assertEqual(quote_by_default, result,
856 "using quote(): %r != %r" % (quote_by_default, result))
857 # "Safe" non-ASCII characters should have no effect
858 # (Since URIs are not allowed to have non-ASCII characters)
859 result = urllib.parse.quote("a\xfcb", encoding="latin-1", safe="\xfc")
860 expect = urllib.parse.quote("a\xfcb", encoding="latin-1", safe="")
861 self.assertEqual(expect, result,
862 "using quote(): %r != %r" %
863 (expect, result))
864 # Same as above, but using a bytes rather than str
865 result = urllib.parse.quote("a\xfcb", encoding="latin-1", safe=b"\xfc")
866 expect = urllib.parse.quote("a\xfcb", encoding="latin-1", safe="")
867 self.assertEqual(expect, result,
868 "using quote(): %r != %r" %
869 (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000870
871 def test_default_quoting(self):
872 # Make sure all characters that should be quoted are by default sans
873 # space (separate test for that).
874 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
R David Murray44b548d2016-09-08 13:59:53 -0400875 should_quote.append(r'<>#%"{}|\^[]`')
Brett Cannon74bfd702003-04-25 09:39:47 +0000876 should_quote.append(chr(127)) # For 0x7F
877 should_quote = ''.join(should_quote)
878 for char in should_quote:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000879 result = urllib.parse.quote(char)
Brett Cannon74bfd702003-04-25 09:39:47 +0000880 self.assertEqual(hexescape(char), result,
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +0000881 "using quote(): "
882 "%s should be escaped to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000883 (char, hexescape(char), result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000884 result = urllib.parse.quote_plus(char)
Brett Cannon74bfd702003-04-25 09:39:47 +0000885 self.assertEqual(hexescape(char), result,
886 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000887 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000888 (char, hexescape(char), result))
889 del should_quote
890 partial_quote = "ab[]cd"
891 expected = "ab%5B%5Dcd"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000892 result = urllib.parse.quote(partial_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000893 self.assertEqual(expected, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000894 "using quote(): %r != %r" % (expected, result))
Senthil Kumaran305a68e2011-09-13 06:40:27 +0800895 result = urllib.parse.quote_plus(partial_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000896 self.assertEqual(expected, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000897 "using quote_plus(): %r != %r" % (expected, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000898
899 def test_quoting_space(self):
900 # Make sure quote() and quote_plus() handle spaces as specified in
901 # their unique way
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000902 result = urllib.parse.quote(' ')
Brett Cannon74bfd702003-04-25 09:39:47 +0000903 self.assertEqual(result, hexescape(' '),
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000904 "using quote(): %r != %r" % (result, hexescape(' ')))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000905 result = urllib.parse.quote_plus(' ')
Brett Cannon74bfd702003-04-25 09:39:47 +0000906 self.assertEqual(result, '+',
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000907 "using quote_plus(): %r != +" % result)
Brett Cannon74bfd702003-04-25 09:39:47 +0000908 given = "a b cd e f"
909 expect = given.replace(' ', hexescape(' '))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000910 result = urllib.parse.quote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000911 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000912 "using quote(): %r != %r" % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000913 expect = given.replace(' ', '+')
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000914 result = urllib.parse.quote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000915 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000916 "using quote_plus(): %r != %r" % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000917
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000918 def test_quoting_plus(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000919 self.assertEqual(urllib.parse.quote_plus('alpha+beta gamma'),
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000920 'alpha%2Bbeta+gamma')
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000921 self.assertEqual(urllib.parse.quote_plus('alpha+beta gamma', '+'),
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000922 'alpha+beta+gamma')
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000923 # Test with bytes
924 self.assertEqual(urllib.parse.quote_plus(b'alpha+beta gamma'),
925 'alpha%2Bbeta+gamma')
926 # Test with safe bytes
927 self.assertEqual(urllib.parse.quote_plus('alpha+beta gamma', b'+'),
928 'alpha+beta+gamma')
929
930 def test_quote_bytes(self):
931 # Bytes should quote directly to percent-encoded values
932 given = b"\xa2\xd8ab\xff"
933 expect = "%A2%D8ab%FF"
934 result = urllib.parse.quote(given)
935 self.assertEqual(expect, result,
936 "using quote(): %r != %r" % (expect, result))
937 # Encoding argument should raise type error on bytes input
938 self.assertRaises(TypeError, urllib.parse.quote, given,
939 encoding="latin-1")
940 # quote_from_bytes should work the same
941 result = urllib.parse.quote_from_bytes(given)
942 self.assertEqual(expect, result,
943 "using quote_from_bytes(): %r != %r"
944 % (expect, result))
945
946 def test_quote_with_unicode(self):
947 # Characters in Latin-1 range, encoded by default in UTF-8
948 given = "\xa2\xd8ab\xff"
949 expect = "%C2%A2%C3%98ab%C3%BF"
950 result = urllib.parse.quote(given)
951 self.assertEqual(expect, result,
952 "using quote(): %r != %r" % (expect, result))
953 # Characters in Latin-1 range, encoded by with None (default)
954 result = urllib.parse.quote(given, encoding=None, errors=None)
955 self.assertEqual(expect, result,
956 "using quote(): %r != %r" % (expect, result))
957 # Characters in Latin-1 range, encoded with Latin-1
958 given = "\xa2\xd8ab\xff"
959 expect = "%A2%D8ab%FF"
960 result = urllib.parse.quote(given, encoding="latin-1")
961 self.assertEqual(expect, result,
962 "using quote(): %r != %r" % (expect, result))
963 # Characters in BMP, encoded by default in UTF-8
964 given = "\u6f22\u5b57" # "Kanji"
965 expect = "%E6%BC%A2%E5%AD%97"
966 result = urllib.parse.quote(given)
967 self.assertEqual(expect, result,
968 "using quote(): %r != %r" % (expect, result))
969 # Characters in BMP, encoded with Latin-1
970 given = "\u6f22\u5b57"
971 self.assertRaises(UnicodeEncodeError, urllib.parse.quote, given,
972 encoding="latin-1")
973 # Characters in BMP, encoded with Latin-1, with replace error handling
974 given = "\u6f22\u5b57"
975 expect = "%3F%3F" # "??"
976 result = urllib.parse.quote(given, encoding="latin-1",
977 errors="replace")
978 self.assertEqual(expect, result,
979 "using quote(): %r != %r" % (expect, result))
980 # Characters in BMP, Latin-1, with xmlcharref error handling
981 given = "\u6f22\u5b57"
982 expect = "%26%2328450%3B%26%2323383%3B" # "&#28450;&#23383;"
983 result = urllib.parse.quote(given, encoding="latin-1",
984 errors="xmlcharrefreplace")
985 self.assertEqual(expect, result,
986 "using quote(): %r != %r" % (expect, result))
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000987
Georg Brandlfaf41492009-05-26 18:31:11 +0000988 def test_quote_plus_with_unicode(self):
989 # Encoding (latin-1) test for quote_plus
990 given = "\xa2\xd8 \xff"
991 expect = "%A2%D8+%FF"
992 result = urllib.parse.quote_plus(given, encoding="latin-1")
993 self.assertEqual(expect, result,
994 "using quote_plus(): %r != %r" % (expect, result))
995 # Errors test for quote_plus
996 given = "ab\u6f22\u5b57 cd"
997 expect = "ab%3F%3F+cd"
998 result = urllib.parse.quote_plus(given, encoding="latin-1",
999 errors="replace")
1000 self.assertEqual(expect, result,
1001 "using quote_plus(): %r != %r" % (expect, result))
1002
Senthil Kumarand496c4c2010-07-30 19:34:36 +00001003
Brett Cannon74bfd702003-04-25 09:39:47 +00001004class UnquotingTests(unittest.TestCase):
1005 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +00001006
Brett Cannon74bfd702003-04-25 09:39:47 +00001007 See the doc string for quoting_Tests for details on quoting and such.
1008
1009 """
1010
1011 def test_unquoting(self):
1012 # Make sure unquoting of all ASCII values works
1013 escape_list = []
1014 for num in range(128):
1015 given = hexescape(chr(num))
1016 expect = chr(num)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001017 result = urllib.parse.unquote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001018 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001019 "using unquote(): %r != %r" % (expect, result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001020 result = urllib.parse.unquote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001021 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001022 "using unquote_plus(): %r != %r" %
Brett Cannon74bfd702003-04-25 09:39:47 +00001023 (expect, result))
1024 escape_list.append(given)
1025 escape_string = ''.join(escape_list)
1026 del escape_list
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001027 result = urllib.parse.unquote(escape_string)
Brett Cannon74bfd702003-04-25 09:39:47 +00001028 self.assertEqual(result.count('%'), 1,
Brett Cannon74bfd702003-04-25 09:39:47 +00001029 "using unquote(): not all characters escaped: "
1030 "%s" % result)
Georg Brandl604ef372010-07-31 08:20:02 +00001031 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote, None)
1032 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote, ())
Florent Xicluna62829dc2010-08-14 20:51:58 +00001033 with support.check_warnings(('', BytesWarning), quiet=True):
1034 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote, b'')
Brett Cannon74bfd702003-04-25 09:39:47 +00001035
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001036 def test_unquoting_badpercent(self):
1037 # Test unquoting on bad percent-escapes
1038 given = '%xab'
1039 expect = given
1040 result = urllib.parse.unquote(given)
1041 self.assertEqual(expect, result, "using unquote(): %r != %r"
1042 % (expect, result))
1043 given = '%x'
1044 expect = given
1045 result = urllib.parse.unquote(given)
1046 self.assertEqual(expect, result, "using unquote(): %r != %r"
1047 % (expect, result))
1048 given = '%'
1049 expect = given
1050 result = urllib.parse.unquote(given)
1051 self.assertEqual(expect, result, "using unquote(): %r != %r"
1052 % (expect, result))
1053 # unquote_to_bytes
1054 given = '%xab'
1055 expect = bytes(given, 'ascii')
1056 result = urllib.parse.unquote_to_bytes(given)
1057 self.assertEqual(expect, result, "using unquote_to_bytes(): %r != %r"
1058 % (expect, result))
1059 given = '%x'
1060 expect = bytes(given, 'ascii')
1061 result = urllib.parse.unquote_to_bytes(given)
1062 self.assertEqual(expect, result, "using unquote_to_bytes(): %r != %r"
1063 % (expect, result))
1064 given = '%'
1065 expect = bytes(given, 'ascii')
1066 result = urllib.parse.unquote_to_bytes(given)
1067 self.assertEqual(expect, result, "using unquote_to_bytes(): %r != %r"
1068 % (expect, result))
Georg Brandl604ef372010-07-31 08:20:02 +00001069 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote_to_bytes, None)
1070 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote_to_bytes, ())
Senthil Kumaran79e17f62010-07-19 18:17:19 +00001071
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001072 def test_unquoting_mixed_case(self):
1073 # Test unquoting on mixed-case hex digits in the percent-escapes
1074 given = '%Ab%eA'
1075 expect = b'\xab\xea'
1076 result = urllib.parse.unquote_to_bytes(given)
1077 self.assertEqual(expect, result,
1078 "using unquote_to_bytes(): %r != %r"
1079 % (expect, result))
1080
Brett Cannon74bfd702003-04-25 09:39:47 +00001081 def test_unquoting_parts(self):
1082 # Make sure unquoting works when have non-quoted characters
1083 # interspersed
1084 given = 'ab%sd' % hexescape('c')
1085 expect = "abcd"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001086 result = urllib.parse.unquote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001087 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001088 "using quote(): %r != %r" % (expect, result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001089 result = urllib.parse.unquote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001090 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001091 "using unquote_plus(): %r != %r" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +00001092
Brett Cannon74bfd702003-04-25 09:39:47 +00001093 def test_unquoting_plus(self):
1094 # Test difference between unquote() and unquote_plus()
1095 given = "are+there+spaces..."
1096 expect = given
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001097 result = urllib.parse.unquote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001098 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001099 "using unquote(): %r != %r" % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +00001100 expect = given.replace('+', ' ')
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001101 result = urllib.parse.unquote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001102 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001103 "using unquote_plus(): %r != %r" % (expect, result))
1104
1105 def test_unquote_to_bytes(self):
1106 given = 'br%C3%BCckner_sapporo_20050930.doc'
1107 expect = b'br\xc3\xbcckner_sapporo_20050930.doc'
1108 result = urllib.parse.unquote_to_bytes(given)
1109 self.assertEqual(expect, result,
1110 "using unquote_to_bytes(): %r != %r"
1111 % (expect, result))
1112 # Test on a string with unescaped non-ASCII characters
1113 # (Technically an invalid URI; expect those characters to be UTF-8
1114 # encoded).
1115 result = urllib.parse.unquote_to_bytes("\u6f22%C3%BC")
1116 expect = b'\xe6\xbc\xa2\xc3\xbc' # UTF-8 for "\u6f22\u00fc"
1117 self.assertEqual(expect, result,
1118 "using unquote_to_bytes(): %r != %r"
1119 % (expect, result))
1120 # Test with a bytes as input
1121 given = b'%A2%D8ab%FF'
1122 expect = b'\xa2\xd8ab\xff'
1123 result = urllib.parse.unquote_to_bytes(given)
1124 self.assertEqual(expect, result,
1125 "using unquote_to_bytes(): %r != %r"
1126 % (expect, result))
1127 # Test with a bytes as input, with unescaped non-ASCII bytes
1128 # (Technically an invalid URI; expect those bytes to be preserved)
1129 given = b'%A2\xd8ab%FF'
1130 expect = b'\xa2\xd8ab\xff'
1131 result = urllib.parse.unquote_to_bytes(given)
1132 self.assertEqual(expect, result,
1133 "using unquote_to_bytes(): %r != %r"
1134 % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +00001135
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +00001136 def test_unquote_with_unicode(self):
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001137 # Characters in the Latin-1 range, encoded with UTF-8
1138 given = 'br%C3%BCckner_sapporo_20050930.doc'
1139 expect = 'br\u00fcckner_sapporo_20050930.doc'
1140 result = urllib.parse.unquote(given)
1141 self.assertEqual(expect, result,
1142 "using unquote(): %r != %r" % (expect, result))
1143 # Characters in the Latin-1 range, encoded with None (default)
1144 result = urllib.parse.unquote(given, encoding=None, errors=None)
1145 self.assertEqual(expect, result,
1146 "using unquote(): %r != %r" % (expect, result))
1147
1148 # Characters in the Latin-1 range, encoded with Latin-1
1149 result = urllib.parse.unquote('br%FCckner_sapporo_20050930.doc',
1150 encoding="latin-1")
1151 expect = 'br\u00fcckner_sapporo_20050930.doc'
1152 self.assertEqual(expect, result,
1153 "using unquote(): %r != %r" % (expect, result))
1154
1155 # Characters in BMP, encoded with UTF-8
1156 given = "%E6%BC%A2%E5%AD%97"
1157 expect = "\u6f22\u5b57" # "Kanji"
1158 result = urllib.parse.unquote(given)
1159 self.assertEqual(expect, result,
1160 "using unquote(): %r != %r" % (expect, result))
1161
1162 # Decode with UTF-8, invalid sequence
1163 given = "%F3%B1"
1164 expect = "\ufffd" # Replacement character
1165 result = urllib.parse.unquote(given)
1166 self.assertEqual(expect, result,
1167 "using unquote(): %r != %r" % (expect, result))
1168
1169 # Decode with UTF-8, invalid sequence, replace errors
1170 result = urllib.parse.unquote(given, errors="replace")
1171 self.assertEqual(expect, result,
1172 "using unquote(): %r != %r" % (expect, result))
1173
1174 # Decode with UTF-8, invalid sequence, ignoring errors
1175 given = "%F3%B1"
1176 expect = ""
1177 result = urllib.parse.unquote(given, errors="ignore")
1178 self.assertEqual(expect, result,
1179 "using unquote(): %r != %r" % (expect, result))
1180
1181 # A mix of non-ASCII and percent-encoded characters, UTF-8
1182 result = urllib.parse.unquote("\u6f22%C3%BC")
1183 expect = '\u6f22\u00fc'
1184 self.assertEqual(expect, result,
1185 "using unquote(): %r != %r" % (expect, result))
1186
1187 # A mix of non-ASCII and percent-encoded characters, Latin-1
1188 # (Note, the string contains non-Latin-1-representable characters)
1189 result = urllib.parse.unquote("\u6f22%FC", encoding="latin-1")
1190 expect = '\u6f22\u00fc'
1191 self.assertEqual(expect, result,
1192 "using unquote(): %r != %r" % (expect, result))
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +00001193
Brett Cannon74bfd702003-04-25 09:39:47 +00001194class urlencode_Tests(unittest.TestCase):
1195 """Tests for urlencode()"""
1196
1197 def help_inputtype(self, given, test_type):
1198 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +00001199
Brett Cannon74bfd702003-04-25 09:39:47 +00001200 'given' must lead to only the pairs:
1201 * 1st, 1
1202 * 2nd, 2
1203 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +00001204
Brett Cannon74bfd702003-04-25 09:39:47 +00001205 Test cannot assume anything about order. Docs make no guarantee and
1206 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +00001207
Brett Cannon74bfd702003-04-25 09:39:47 +00001208 """
1209 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001210 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001211 for expected in expect_somewhere:
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001212 self.assertIn(expected, result,
Brett Cannon74bfd702003-04-25 09:39:47 +00001213 "testing %s: %s not found in %s" %
1214 (test_type, expected, result))
1215 self.assertEqual(result.count('&'), 2,
1216 "testing %s: expected 2 '&'s; got %s" %
1217 (test_type, result.count('&')))
1218 amp_location = result.index('&')
1219 on_amp_left = result[amp_location - 1]
1220 on_amp_right = result[amp_location + 1]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001221 self.assertTrue(on_amp_left.isdigit() and on_amp_right.isdigit(),
Brett Cannon74bfd702003-04-25 09:39:47 +00001222 "testing %s: '&' not located in proper place in %s" %
1223 (test_type, result))
1224 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
1225 "testing %s: "
1226 "unexpected number of characters: %s != %s" %
1227 (test_type, len(result), (5 * 3) + 2))
1228
1229 def test_using_mapping(self):
1230 # Test passing in a mapping object as an argument.
1231 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
1232 "using dict as input type")
1233
1234 def test_using_sequence(self):
1235 # Test passing in a sequence of two-item sequences as an argument.
1236 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
1237 "using sequence of two-item tuples as input")
1238
1239 def test_quoting(self):
1240 # Make sure keys and values are quoted using quote_plus()
1241 given = {"&":"="}
1242 expect = "%s=%s" % (hexescape('&'), hexescape('='))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001243 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001244 self.assertEqual(expect, result)
1245 given = {"key name":"A bunch of pluses"}
1246 expect = "key+name=A+bunch+of+pluses"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001247 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001248 self.assertEqual(expect, result)
1249
1250 def test_doseq(self):
1251 # Test that passing True for 'doseq' parameter works correctly
1252 given = {'sequence':['1', '2', '3']}
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001253 expect = "sequence=%s" % urllib.parse.quote_plus(str(['1', '2', '3']))
1254 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001255 self.assertEqual(expect, result)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001256 result = urllib.parse.urlencode(given, True)
Brett Cannon74bfd702003-04-25 09:39:47 +00001257 for value in given["sequence"]:
1258 expect = "sequence=%s" % value
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001259 self.assertIn(expect, result)
Brett Cannon74bfd702003-04-25 09:39:47 +00001260 self.assertEqual(result.count('&'), 2,
1261 "Expected 2 '&'s, got %s" % result.count('&'))
1262
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +00001263 def test_empty_sequence(self):
1264 self.assertEqual("", urllib.parse.urlencode({}))
1265 self.assertEqual("", urllib.parse.urlencode([]))
1266
1267 def test_nonstring_values(self):
1268 self.assertEqual("a=1", urllib.parse.urlencode({"a": 1}))
1269 self.assertEqual("a=None", urllib.parse.urlencode({"a": None}))
1270
1271 def test_nonstring_seq_values(self):
1272 self.assertEqual("a=1&a=2", urllib.parse.urlencode({"a": [1, 2]}, True))
1273 self.assertEqual("a=None&a=a",
1274 urllib.parse.urlencode({"a": [None, "a"]}, True))
Georg Brandl2daf6ae2012-02-20 19:54:16 +01001275 data = collections.OrderedDict([("a", 1), ("b", 1)])
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +00001276 self.assertEqual("a=a&a=b",
Georg Brandl2daf6ae2012-02-20 19:54:16 +01001277 urllib.parse.urlencode({"a": data}, True))
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +00001278
Senthil Kumarandf022da2010-07-03 17:48:22 +00001279 def test_urlencode_encoding(self):
1280 # ASCII encoding. Expect %3F with errors="replace'
1281 given = (('\u00a0', '\u00c1'),)
1282 expect = '%3F=%3F'
1283 result = urllib.parse.urlencode(given, encoding="ASCII", errors="replace")
1284 self.assertEqual(expect, result)
1285
1286 # Default is UTF-8 encoding.
1287 given = (('\u00a0', '\u00c1'),)
1288 expect = '%C2%A0=%C3%81'
1289 result = urllib.parse.urlencode(given)
1290 self.assertEqual(expect, result)
1291
1292 # Latin-1 encoding.
1293 given = (('\u00a0', '\u00c1'),)
1294 expect = '%A0=%C1'
1295 result = urllib.parse.urlencode(given, encoding="latin-1")
1296 self.assertEqual(expect, result)
1297
1298 def test_urlencode_encoding_doseq(self):
1299 # ASCII Encoding. Expect %3F with errors="replace'
1300 given = (('\u00a0', '\u00c1'),)
1301 expect = '%3F=%3F'
1302 result = urllib.parse.urlencode(given, doseq=True,
1303 encoding="ASCII", errors="replace")
1304 self.assertEqual(expect, result)
1305
1306 # ASCII Encoding. On a sequence of values.
1307 given = (("\u00a0", (1, "\u00c1")),)
1308 expect = '%3F=1&%3F=%3F'
1309 result = urllib.parse.urlencode(given, True,
1310 encoding="ASCII", errors="replace")
1311 self.assertEqual(expect, result)
1312
1313 # Utf-8
1314 given = (("\u00a0", "\u00c1"),)
1315 expect = '%C2%A0=%C3%81'
1316 result = urllib.parse.urlencode(given, True)
1317 self.assertEqual(expect, result)
1318
1319 given = (("\u00a0", (42, "\u00c1")),)
1320 expect = '%C2%A0=42&%C2%A0=%C3%81'
1321 result = urllib.parse.urlencode(given, True)
1322 self.assertEqual(expect, result)
1323
1324 # latin-1
1325 given = (("\u00a0", "\u00c1"),)
1326 expect = '%A0=%C1'
1327 result = urllib.parse.urlencode(given, True, encoding="latin-1")
1328 self.assertEqual(expect, result)
1329
1330 given = (("\u00a0", (42, "\u00c1")),)
1331 expect = '%A0=42&%A0=%C1'
1332 result = urllib.parse.urlencode(given, True, encoding="latin-1")
1333 self.assertEqual(expect, result)
1334
1335 def test_urlencode_bytes(self):
1336 given = ((b'\xa0\x24', b'\xc1\x24'),)
1337 expect = '%A0%24=%C1%24'
1338 result = urllib.parse.urlencode(given)
1339 self.assertEqual(expect, result)
1340 result = urllib.parse.urlencode(given, True)
1341 self.assertEqual(expect, result)
1342
1343 # Sequence of values
1344 given = ((b'\xa0\x24', (42, b'\xc1\x24')),)
1345 expect = '%A0%24=42&%A0%24=%C1%24'
1346 result = urllib.parse.urlencode(given, True)
1347 self.assertEqual(expect, result)
1348
1349 def test_urlencode_encoding_safe_parameter(self):
1350
1351 # Send '$' (\x24) as safe character
1352 # Default utf-8 encoding
1353
1354 given = ((b'\xa0\x24', b'\xc1\x24'),)
1355 result = urllib.parse.urlencode(given, safe=":$")
1356 expect = '%A0$=%C1$'
1357 self.assertEqual(expect, result)
1358
1359 given = ((b'\xa0\x24', b'\xc1\x24'),)
1360 result = urllib.parse.urlencode(given, doseq=True, safe=":$")
1361 expect = '%A0$=%C1$'
1362 self.assertEqual(expect, result)
1363
1364 # Safe parameter in sequence
1365 given = ((b'\xa0\x24', (b'\xc1\x24', 0xd, 42)),)
1366 expect = '%A0$=%C1$&%A0$=13&%A0$=42'
1367 result = urllib.parse.urlencode(given, True, safe=":$")
1368 self.assertEqual(expect, result)
1369
1370 # Test all above in latin-1 encoding
1371
1372 given = ((b'\xa0\x24', b'\xc1\x24'),)
1373 result = urllib.parse.urlencode(given, safe=":$",
1374 encoding="latin-1")
1375 expect = '%A0$=%C1$'
1376 self.assertEqual(expect, result)
1377
1378 given = ((b'\xa0\x24', b'\xc1\x24'),)
1379 expect = '%A0$=%C1$'
1380 result = urllib.parse.urlencode(given, doseq=True, safe=":$",
1381 encoding="latin-1")
1382
1383 given = ((b'\xa0\x24', (b'\xc1\x24', 0xd, 42)),)
1384 expect = '%A0$=%C1$&%A0$=13&%A0$=42'
1385 result = urllib.parse.urlencode(given, True, safe=":$",
1386 encoding="latin-1")
1387 self.assertEqual(expect, result)
1388
Brett Cannon74bfd702003-04-25 09:39:47 +00001389class Pathname_Tests(unittest.TestCase):
1390 """Test pathname2url() and url2pathname()"""
1391
1392 def test_basic(self):
1393 # Make sure simple tests pass
1394 expected_path = os.path.join("parts", "of", "a", "path")
1395 expected_url = "parts/of/a/path"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001396 result = urllib.request.pathname2url(expected_path)
Brett Cannon74bfd702003-04-25 09:39:47 +00001397 self.assertEqual(expected_url, result,
1398 "pathname2url() failed; %s != %s" %
1399 (result, expected_url))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001400 result = urllib.request.url2pathname(expected_url)
Brett Cannon74bfd702003-04-25 09:39:47 +00001401 self.assertEqual(expected_path, result,
1402 "url2pathame() failed; %s != %s" %
1403 (result, expected_path))
1404
1405 def test_quoting(self):
1406 # Test automatic quoting and unquoting works for pathnam2url() and
1407 # url2pathname() respectively
1408 given = os.path.join("needs", "quot=ing", "here")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001409 expect = "needs/%s/here" % urllib.parse.quote("quot=ing")
1410 result = urllib.request.pathname2url(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001411 self.assertEqual(expect, result,
1412 "pathname2url() failed; %s != %s" %
1413 (expect, result))
1414 expect = given
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001415 result = urllib.request.url2pathname(result)
Brett Cannon74bfd702003-04-25 09:39:47 +00001416 self.assertEqual(expect, result,
1417 "url2pathname() failed; %s != %s" %
1418 (expect, result))
1419 given = os.path.join("make sure", "using_quote")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001420 expect = "%s/using_quote" % urllib.parse.quote("make sure")
1421 result = urllib.request.pathname2url(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001422 self.assertEqual(expect, result,
1423 "pathname2url() failed; %s != %s" %
1424 (expect, result))
1425 given = "make+sure/using_unquote"
1426 expect = os.path.join("make+sure", "using_unquote")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001427 result = urllib.request.url2pathname(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001428 self.assertEqual(expect, result,
1429 "url2pathname() failed; %s != %s" %
1430 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +00001431
Senthil Kumaran2d2ea1b2011-04-14 13:16:30 +08001432 @unittest.skipUnless(sys.platform == 'win32',
1433 'test specific to the urllib.url2path function.')
1434 def test_ntpath(self):
1435 given = ('/C:/', '///C:/', '/C|//')
1436 expect = 'C:\\'
1437 for url in given:
1438 result = urllib.request.url2pathname(url)
1439 self.assertEqual(expect, result,
1440 'urllib.request..url2pathname() failed; %s != %s' %
1441 (expect, result))
1442 given = '///C|/path'
1443 expect = 'C:\\path'
1444 result = urllib.request.url2pathname(given)
1445 self.assertEqual(expect, result,
1446 'urllib.request.url2pathname() failed; %s != %s' %
1447 (expect, result))
1448
Senthil Kumaraneaaec272009-03-30 21:54:41 +00001449class Utility_Tests(unittest.TestCase):
1450 """Testcase to test the various utility functions in the urllib."""
1451
Senthil Kumaran1b7da512011-10-06 00:32:02 +08001452 def test_thishost(self):
1453 """Test the urllib.request.thishost utility function returns a tuple"""
1454 self.assertIsInstance(urllib.request.thishost(), tuple)
1455
Senthil Kumaran690ce9b2009-05-05 18:41:13 +00001456
Xtreakc661b302019-05-19 19:10:06 +05301457class URLopener_Tests(FakeHTTPMixin, unittest.TestCase):
Senthil Kumaran690ce9b2009-05-05 18:41:13 +00001458 """Testcase to test the open method of URLopener class."""
1459
1460 def test_quoted_open(self):
1461 class DummyURLopener(urllib.request.URLopener):
1462 def open_spam(self, url):
1463 return url
Ezio Melotti79b99db2013-02-21 02:41:42 +02001464 with support.check_warnings(
1465 ('DummyURLopener style of invoking requests is deprecated.',
1466 DeprecationWarning)):
1467 self.assertEqual(DummyURLopener().open(
1468 'spam://example/ /'),'//example/%20/')
Senthil Kumaran690ce9b2009-05-05 18:41:13 +00001469
Ezio Melotti79b99db2013-02-21 02:41:42 +02001470 # test the safe characters are not quoted by urlopen
1471 self.assertEqual(DummyURLopener().open(
1472 "spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"),
1473 "//c:|windows%/:=&?~#+!$,;'@()*[]|/path/")
Senthil Kumaran734f0592010-02-20 22:19:04 +00001474
Xtreakc661b302019-05-19 19:10:06 +05301475 @support.ignore_warnings(category=DeprecationWarning)
1476 def test_urlopener_retrieve_file(self):
1477 with support.temp_dir() as tmpdir:
1478 fd, tmpfile = tempfile.mkstemp(dir=tmpdir)
1479 os.close(fd)
1480 fileurl = "file:" + urllib.request.pathname2url(tmpfile)
1481 filename, _ = urllib.request.URLopener().retrieve(fileurl)
Berker Peksag2725cb02019-05-22 02:00:35 +03001482 # Some buildbots have TEMP folder that uses a lowercase drive letter.
1483 self.assertEqual(os.path.normcase(filename), os.path.normcase(tmpfile))
Xtreakc661b302019-05-19 19:10:06 +05301484
1485 @support.ignore_warnings(category=DeprecationWarning)
1486 def test_urlopener_retrieve_remote(self):
1487 url = "http://www.python.org/file.txt"
1488 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!")
1489 self.addCleanup(self.unfakehttp)
1490 filename, _ = urllib.request.URLopener().retrieve(url)
1491 self.assertEqual(os.path.splitext(filename)[1], ".txt")
1492
Victor Stinner0c2b6a32019-05-22 22:15:01 +02001493 @support.ignore_warnings(category=DeprecationWarning)
1494 def test_local_file_open(self):
1495 # bpo-35907, CVE-2019-9948: urllib must reject local_file:// scheme
1496 class DummyURLopener(urllib.request.URLopener):
1497 def open_local_file(self, url):
1498 return url
1499 for url in ('local_file://example', 'local-file://example'):
1500 self.assertRaises(OSError, urllib.request.urlopen, url)
1501 self.assertRaises(OSError, urllib.request.URLopener().open, url)
1502 self.assertRaises(OSError, urllib.request.URLopener().retrieve, url)
1503 self.assertRaises(OSError, DummyURLopener().open, url)
1504 self.assertRaises(OSError, DummyURLopener().retrieve, url)
1505
Xtreakc661b302019-05-19 19:10:06 +05301506
Guido van Rossume7ba4952007-06-06 23:52:48 +00001507# Just commented them out.
1508# Can't really tell why keep failing in windows and sparc.
Ezio Melotti13925002011-03-16 11:05:33 +02001509# Everywhere else they work ok, but on those machines, sometimes
Guido van Rossume7ba4952007-06-06 23:52:48 +00001510# fail in one of the tests, sometimes in other. I have a linux, and
1511# the tests go ok.
Ezio Melotti85a86292013-08-17 16:57:41 +03001512# If anybody has one of the problematic environments, please help!
Guido van Rossume7ba4952007-06-06 23:52:48 +00001513# . Facundo
1514#
1515# def server(evt):
Georg Brandlf78e02b2008-06-10 17:40:04 +00001516# import socket, time
Guido van Rossume7ba4952007-06-06 23:52:48 +00001517# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1518# serv.settimeout(3)
1519# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1520# serv.bind(("", 9093))
Charles-François Natali6e204602014-07-23 19:28:13 +01001521# serv.listen()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001522# try:
1523# conn, addr = serv.accept()
1524# conn.send("1 Hola mundo\n")
1525# cantdata = 0
1526# while cantdata < 13:
1527# data = conn.recv(13-cantdata)
1528# cantdata += len(data)
1529# time.sleep(.3)
1530# conn.send("2 No more lines\n")
1531# conn.close()
1532# except socket.timeout:
1533# pass
1534# finally:
1535# serv.close()
1536# evt.set()
1537#
1538# class FTPWrapperTests(unittest.TestCase):
1539#
1540# def setUp(self):
Georg Brandlf78e02b2008-06-10 17:40:04 +00001541# import ftplib, time, threading
Guido van Rossume7ba4952007-06-06 23:52:48 +00001542# ftplib.FTP.port = 9093
1543# self.evt = threading.Event()
1544# threading.Thread(target=server, args=(self.evt,)).start()
1545# time.sleep(.1)
1546#
1547# def tearDown(self):
1548# self.evt.wait()
1549#
1550# def testBasic(self):
1551# # connects
1552# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
Georg Brandlf78e02b2008-06-10 17:40:04 +00001553# ftp.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001554#
1555# def testTimeoutNone(self):
Georg Brandlf78e02b2008-06-10 17:40:04 +00001556# # global default timeout is ignored
1557# import socket
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +02001558# self.assertIsNone(socket.getdefaulttimeout())
Guido van Rossume7ba4952007-06-06 23:52:48 +00001559# socket.setdefaulttimeout(30)
1560# try:
1561# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
1562# finally:
Georg Brandlf78e02b2008-06-10 17:40:04 +00001563# socket.setdefaulttimeout(None)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001564# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
Georg Brandlf78e02b2008-06-10 17:40:04 +00001565# ftp.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001566#
Georg Brandlf78e02b2008-06-10 17:40:04 +00001567# def testTimeoutDefault(self):
1568# # global default timeout is used
1569# import socket
Serhiy Storchaka25d8aea2014-02-08 14:50:08 +02001570# self.assertIsNone(socket.getdefaulttimeout())
Georg Brandlf78e02b2008-06-10 17:40:04 +00001571# socket.setdefaulttimeout(30)
1572# try:
1573# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
1574# finally:
1575# socket.setdefaulttimeout(None)
1576# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
1577# ftp.close()
1578#
1579# def testTimeoutValue(self):
1580# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [],
1581# timeout=30)
1582# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
1583# ftp.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001584
Senthil Kumaran8b081b72013-04-10 20:53:12 -07001585
Senthil Kumarande49d642011-10-16 23:54:44 +08001586class RequestTests(unittest.TestCase):
1587 """Unit tests for urllib.request.Request."""
1588
1589 def test_default_values(self):
1590 Request = urllib.request.Request
1591 request = Request("http://www.python.org")
1592 self.assertEqual(request.get_method(), 'GET')
1593 request = Request("http://www.python.org", {})
1594 self.assertEqual(request.get_method(), 'POST')
1595
1596 def test_with_method_arg(self):
1597 Request = urllib.request.Request
1598 request = Request("http://www.python.org", method='HEAD')
1599 self.assertEqual(request.method, 'HEAD')
1600 self.assertEqual(request.get_method(), 'HEAD')
1601 request = Request("http://www.python.org", {}, method='HEAD')
1602 self.assertEqual(request.method, 'HEAD')
1603 self.assertEqual(request.get_method(), 'HEAD')
1604 request = Request("http://www.python.org", method='GET')
1605 self.assertEqual(request.get_method(), 'GET')
1606 request.method = 'HEAD'
1607 self.assertEqual(request.get_method(), 'HEAD')
Skip Montanaro080c9972001-01-28 21:12:22 +00001608
1609
Senthil Kumaran277e9092013-04-10 20:51:19 -07001610class URL2PathNameTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +00001611
Senthil Kumaran277e9092013-04-10 20:51:19 -07001612 def test_converting_drive_letter(self):
1613 self.assertEqual(url2pathname("///C|"), 'C:')
1614 self.assertEqual(url2pathname("///C:"), 'C:')
1615 self.assertEqual(url2pathname("///C|/"), 'C:\\')
Brett Cannon74bfd702003-04-25 09:39:47 +00001616
Senthil Kumaran277e9092013-04-10 20:51:19 -07001617 def test_converting_when_no_drive_letter(self):
1618 # cannot end a raw string in \
1619 self.assertEqual(url2pathname("///C/test/"), r'\\\C\test' '\\')
1620 self.assertEqual(url2pathname("////C/test/"), r'\\C\test' '\\')
1621
1622 def test_simple_compare(self):
1623 self.assertEqual(url2pathname("///C|/foo/bar/spam.foo"),
1624 r'C:\foo\bar\spam.foo')
1625
1626 def test_non_ascii_drive_letter(self):
1627 self.assertRaises(IOError, url2pathname, "///\u00e8|/")
1628
1629 def test_roundtrip_url2pathname(self):
1630 list_of_paths = ['C:',
1631 r'\\\C\test\\',
1632 r'C:\foo\bar\spam.foo'
1633 ]
1634 for path in list_of_paths:
Senthil Kumaranc7e09802013-04-10 20:54:23 -07001635 self.assertEqual(url2pathname(pathname2url(path)), path)
Senthil Kumaran277e9092013-04-10 20:51:19 -07001636
1637class PathName2URLTests(unittest.TestCase):
1638
1639 def test_converting_drive_letter(self):
1640 self.assertEqual(pathname2url("C:"), '///C:')
1641 self.assertEqual(pathname2url("C:\\"), '///C:')
1642
1643 def test_converting_when_no_drive_letter(self):
1644 self.assertEqual(pathname2url(r"\\\folder\test" "\\"),
1645 '/////folder/test/')
1646 self.assertEqual(pathname2url(r"\\folder\test" "\\"),
1647 '////folder/test/')
1648 self.assertEqual(pathname2url(r"\folder\test" "\\"),
1649 '/folder/test/')
1650
1651 def test_simple_compare(self):
1652 self.assertEqual(pathname2url(r'C:\foo\bar\spam.foo'),
1653 "///C:/foo/bar/spam.foo" )
1654
1655 def test_long_drive_letter(self):
1656 self.assertRaises(IOError, pathname2url, "XX:\\")
1657
1658 def test_roundtrip_pathname2url(self):
1659 list_of_paths = ['///C:',
1660 '/////folder/test/',
1661 '///C:/foo/bar/spam.foo']
1662 for path in list_of_paths:
Senthil Kumaranc7e09802013-04-10 20:54:23 -07001663 self.assertEqual(pathname2url(url2pathname(path)), path)
Brett Cannon74bfd702003-04-25 09:39:47 +00001664
1665if __name__ == '__main__':
Senthil Kumaran277e9092013-04-10 20:51:19 -07001666 unittest.main()