blob: ccd5419b709e00aafff8230614bac9fb8f96712e [file] [log] [blame]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00003
Christian Heimes05e8be12008-02-23 18:30:17 +00004import os
Guido van Rossum34d19282007-08-09 01:03:29 +00005import io
Georg Brandlf78e02b2008-06-10 17:40:04 +00006import socket
Senthil Kumaran7bc0d872010-12-19 10:49:52 +00007import array
Senthil Kumaran4de00a22011-05-11 21:17:57 +08008import sys
Jeremy Hyltone3e61042001-05-09 15:50:25 +00009
Jeremy Hylton1afc1692008-06-18 20:49:58 +000010import urllib.request
Ronald Oussorene72e1612011-03-14 18:15:25 -040011# The proxy bypass method imported below has logic specific to the OSX
12# proxy config data structure but is testable on all platforms.
13from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
guido@google.coma119df92011-03-29 11:41:02 -070014import urllib.error
Jeremy Hyltone3e61042001-05-09 15:50:25 +000015
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000016# XXX
17# Request
18# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000019# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000020
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000021class TrivialTests(unittest.TestCase):
Senthil Kumaran6c5bd402011-11-01 23:20:31 +080022
23 def test___all__(self):
24 # Verify which names are exposed
25 for module in 'request', 'response', 'parse', 'error', 'robotparser':
26 context = {}
27 exec('from urllib.%s import *' % module, context)
28 del context['__builtins__']
Florent Xicluna3dbb1f12011-11-04 22:15:37 +010029 if module == 'request' and os.name == 'nt':
30 u, p = context.pop('url2pathname'), context.pop('pathname2url')
31 self.assertEqual(u.__module__, 'nturl2path')
32 self.assertEqual(p.__module__, 'nturl2path')
Senthil Kumaran6c5bd402011-11-01 23:20:31 +080033 for k, v in context.items():
34 self.assertEqual(v.__module__, 'urllib.%s' % module,
35 "%r is exposed in 'urllib.%s' but defined in %r" %
36 (k, module, v.__module__))
37
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000038 def test_trivial(self):
39 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000040
Jeremy Hylton1afc1692008-06-18 20:49:58 +000041 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000042
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000043 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000044 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000045
Senthil Kumarand587e302010-01-10 17:45:52 +000046 if os.name == 'nt':
47 file_url = "file:///%s" % fname
48 else:
49 file_url = "file://%s" % fname
50
Jeremy Hylton1afc1692008-06-18 20:49:58 +000051 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000052
53 buf = f.read()
54 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000055
Georg Brandle1b13d22005-08-24 22:20:32 +000056 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000057 tests = [
58 ('a,b,c', ['a', 'b', 'c']),
59 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
60 ('a, b, "c", "d", "e,f", g, h',
61 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
62 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
63 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000064 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000065 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000066
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000067
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000068def test_request_headers_dict():
69 """
70 The Request.headers dictionary is not a documented interface. It should
71 stay that way, because the complete set of headers are only accessible
72 through the .get_header(), .has_header(), .header_items() interface.
73 However, .headers pre-dates those methods, and so real code will be using
74 the dictionary.
75
76 The introduction in 2.4 of those methods was a mistake for the same reason:
77 code that previously saw all (urllib2 user)-provided headers in .headers
78 now sees only a subset (and the function interface is ugly and incomplete).
79 A better change would have been to replace .headers dict with a dict
80 subclass (or UserDict.DictMixin instance?) that preserved the .headers
81 interface and also provided access to the "unredirected" headers. It's
82 probably too late to fix that, though.
83
84
85 Check .capitalize() case normalization:
86
87 >>> url = "http://example.com"
88 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
89 'blah'
90 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
91 'blah'
92
93 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
94 but that could be changed in future.
95
96 """
97
98def test_request_headers_methods():
99 """
100 Note the case normalization of header names here, to .capitalize()-case.
101 This should be preserved for backwards-compatibility. (In the HTTP case,
102 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +0000103 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000104
105 >>> url = "http://example.com"
106 >>> r = Request(url, headers={"Spam-eggs": "blah"})
107 >>> r.has_header("Spam-eggs")
108 True
109 >>> r.header_items()
110 [('Spam-eggs', 'blah')]
111 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000112 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000113 >>> items
114 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
115
116 Note that e.g. r.has_header("spam-EggS") is currently False, and
117 r.get_header("spam-EggS") returns None, but that could be changed in
118 future.
119
120 >>> r.has_header("Not-there")
121 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000122 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000123 None
124 >>> r.get_header("Not-there", "default")
125 'default'
126
127 """
128
129
Thomas Wouters477c8d52006-05-27 19:21:47 +0000130def test_password_manager(self):
131 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000132 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000133 >>> add = mgr.add_password
134 >>> add("Some Realm", "http://example.com/", "joe", "password")
135 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
136 >>> add("c", "http://example.com/foo", "foo", "ni")
137 >>> add("c", "http://example.com/bar", "bar", "nini")
138 >>> add("b", "http://example.com/", "first", "blah")
139 >>> add("b", "http://example.com/", "second", "spam")
140 >>> add("a", "http://example.com", "1", "a")
141 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
142 >>> add("Some Realm", "d.example.com", "4", "d")
143 >>> add("Some Realm", "e.example.com:3128", "5", "e")
144
145 >>> mgr.find_user_password("Some Realm", "example.com")
146 ('joe', 'password')
147 >>> mgr.find_user_password("Some Realm", "http://example.com")
148 ('joe', 'password')
149 >>> mgr.find_user_password("Some Realm", "http://example.com/")
150 ('joe', 'password')
151 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
152 ('joe', 'password')
153 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
154 ('joe', 'password')
155 >>> mgr.find_user_password("c", "http://example.com/foo")
156 ('foo', 'ni')
157 >>> mgr.find_user_password("c", "http://example.com/bar")
158 ('bar', 'nini')
159
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000160 Actually, this is really undefined ATM
161## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000162
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000163## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
164## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000165
166 Use latest add_password() in case of conflict:
167
168 >>> mgr.find_user_password("b", "http://example.com/")
169 ('second', 'spam')
170
171 No special relationship between a.example.com and example.com:
172
173 >>> mgr.find_user_password("a", "http://example.com/")
174 ('1', 'a')
175 >>> mgr.find_user_password("a", "http://a.example.com/")
176 (None, None)
177
178 Ports:
179
180 >>> mgr.find_user_password("Some Realm", "c.example.com")
181 (None, None)
182 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
183 ('3', 'c')
184 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
185 ('3', 'c')
186 >>> mgr.find_user_password("Some Realm", "d.example.com")
187 ('4', 'd')
188 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
189 ('5', 'e')
190
191 """
192 pass
193
194
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000195def test_password_manager_default_port(self):
196 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000197 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000198 >>> add = mgr.add_password
199
200 The point to note here is that we can't guess the default port if there's
201 no scheme. This applies to both add_password and find_user_password.
202
203 >>> add("f", "http://g.example.com:80", "10", "j")
204 >>> add("g", "http://h.example.com", "11", "k")
205 >>> add("h", "i.example.com:80", "12", "l")
206 >>> add("i", "j.example.com", "13", "m")
207 >>> mgr.find_user_password("f", "g.example.com:100")
208 (None, None)
209 >>> mgr.find_user_password("f", "g.example.com:80")
210 ('10', 'j')
211 >>> mgr.find_user_password("f", "g.example.com")
212 (None, None)
213 >>> mgr.find_user_password("f", "http://g.example.com:100")
214 (None, None)
215 >>> mgr.find_user_password("f", "http://g.example.com:80")
216 ('10', 'j')
217 >>> mgr.find_user_password("f", "http://g.example.com")
218 ('10', 'j')
219 >>> mgr.find_user_password("g", "h.example.com")
220 ('11', 'k')
221 >>> mgr.find_user_password("g", "h.example.com:80")
222 ('11', 'k')
223 >>> mgr.find_user_password("g", "http://h.example.com:80")
224 ('11', 'k')
225 >>> mgr.find_user_password("h", "i.example.com")
226 (None, None)
227 >>> mgr.find_user_password("h", "i.example.com:80")
228 ('12', 'l')
229 >>> mgr.find_user_password("h", "http://i.example.com:80")
230 ('12', 'l')
231 >>> mgr.find_user_password("i", "j.example.com")
232 ('13', 'm')
233 >>> mgr.find_user_password("i", "j.example.com:80")
234 (None, None)
235 >>> mgr.find_user_password("i", "http://j.example.com")
236 ('13', 'm')
237 >>> mgr.find_user_password("i", "http://j.example.com:80")
238 (None, None)
239
240 """
241
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000242class MockOpener:
243 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000244 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
245 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000246 def error(self, proto, *args):
247 self.proto, self.args = proto, args
248
249class MockFile:
250 def read(self, count=None): pass
251 def readline(self, count=None): pass
252 def close(self): pass
253
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000254class MockHeaders(dict):
255 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000256 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000257
Guido van Rossum34d19282007-08-09 01:03:29 +0000258class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000259 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000260 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000261 self.code, self.msg, self.headers, self.url = code, msg, headers, url
262 def info(self):
263 return self.headers
264 def geturl(self):
265 return self.url
266
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000267class MockCookieJar:
268 def add_cookie_header(self, request):
269 self.ach_req = request
270 def extract_cookies(self, response, request):
271 self.ec_req, self.ec_r = request, response
272
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000273class FakeMethod:
274 def __init__(self, meth_name, action, handle):
275 self.meth_name = meth_name
276 self.handle = handle
277 self.action = action
278 def __call__(self, *args):
279 return self.handle(self.meth_name, self.action, *args)
280
Senthil Kumaran47fff872009-12-20 07:10:31 +0000281class MockHTTPResponse(io.IOBase):
282 def __init__(self, fp, msg, status, reason):
283 self.fp = fp
284 self.msg = msg
285 self.status = status
286 self.reason = reason
287 self.code = 200
288
289 def read(self):
290 return ''
291
292 def info(self):
293 return {}
294
295 def geturl(self):
296 return self.url
297
298
299class MockHTTPClass:
300 def __init__(self):
301 self.level = 0
302 self.req_headers = []
303 self.data = None
304 self.raise_on_endheaders = False
305 self._tunnel_headers = {}
306
307 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
308 self.host = host
309 self.timeout = timeout
310 return self
311
312 def set_debuglevel(self, level):
313 self.level = level
314
315 def set_tunnel(self, host, port=None, headers=None):
316 self._tunnel_host = host
317 self._tunnel_port = port
318 if headers:
319 self._tunnel_headers = headers
320 else:
321 self._tunnel_headers.clear()
322
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000323 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000324 self.method = method
325 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000326 if headers is not None:
327 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000328 self.req_headers.sort()
329 if body:
330 self.data = body
331 if self.raise_on_endheaders:
332 import socket
333 raise socket.error()
334 def getresponse(self):
335 return MockHTTPResponse(MockFile(), {}, 200, "OK")
336
Victor Stinnera4c45d72011-06-17 14:01:18 +0200337 def close(self):
338 pass
339
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000340class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000341 # useful for testing handler machinery
342 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000343 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000344 def __init__(self, methods):
345 self._define_methods(methods)
346 def _define_methods(self, methods):
347 for spec in methods:
348 if len(spec) == 2: name, action = spec
349 else: name, action = spec, None
350 meth = FakeMethod(name, action, self.handle)
351 setattr(self.__class__, name, meth)
352 def handle(self, fn_name, action, *args, **kwds):
353 self.parent.calls.append((self, fn_name, args, kwds))
354 if action is None:
355 return None
356 elif action == "return self":
357 return self
358 elif action == "return response":
359 res = MockResponse(200, "OK", {}, "")
360 return res
361 elif action == "return request":
362 return Request("http://blah/")
363 elif action.startswith("error"):
364 code = action[action.rfind(" ")+1:]
365 try:
366 code = int(code)
367 except ValueError:
368 pass
369 res = MockResponse(200, "OK", {}, "")
370 return self.parent.error("http", args[0], res, code, "", {})
371 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000372 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000373 assert False
374 def close(self): pass
375 def add_parent(self, parent):
376 self.parent = parent
377 self.parent.calls = []
378 def __lt__(self, other):
379 if not hasattr(other, "handler_order"):
380 # No handler_order, leave in original order. Yuck.
381 return True
382 return self.handler_order < other.handler_order
383
384def add_ordered_mock_handlers(opener, meth_spec):
385 """Create MockHandlers and add them to an OpenerDirector.
386
387 meth_spec: list of lists of tuples and strings defining methods to define
388 on handlers. eg:
389
390 [["http_error", "ftp_open"], ["http_open"]]
391
392 defines methods .http_error() and .ftp_open() on one handler, and
393 .http_open() on another. These methods just record their arguments and
394 return None. Using a tuple instead of a string causes the method to
395 perform some action (see MockHandler.handle()), eg:
396
397 [["http_error"], [("http_open", "return request")]]
398
399 defines .http_error() on one handler (which simply returns None), and
400 .http_open() on another handler, which returns a Request object.
401
402 """
403 handlers = []
404 count = 0
405 for meths in meth_spec:
406 class MockHandlerSubclass(MockHandler): pass
407 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000408 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000409 h.add_parent(opener)
410 count = count + 1
411 handlers.append(h)
412 opener.add_handler(h)
413 return handlers
414
Thomas Wouters477c8d52006-05-27 19:21:47 +0000415def build_test_opener(*handler_instances):
416 opener = OpenerDirector()
417 for h in handler_instances:
418 opener.add_handler(h)
419 return opener
420
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000421class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000422 # useful for testing redirections and auth
423 # sends supplied headers and code as first response
424 # sends 200 OK as second response
425 def __init__(self, code, headers):
426 self.code = code
427 self.headers = headers
428 self.reset()
429 def reset(self):
430 self._count = 0
431 self.requests = []
432 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000433 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000434 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000435 self.requests.append(copy.deepcopy(req))
436 if self._count == 0:
437 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000438 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000439 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000440 return self.parent.error(
441 "http", req, MockFile(), self.code, name, msg)
442 else:
443 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000444 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000445 return MockResponse(200, "OK", msg, "", req.get_full_url())
446
Senthil Kumaran47fff872009-12-20 07:10:31 +0000447class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
448 # Useful for testing the Proxy-Authorization request by verifying the
449 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000450
451 def __init__(self):
452 urllib.request.AbstractHTTPHandler.__init__(self)
453 self.httpconn = MockHTTPClass()
454
Senthil Kumaran47fff872009-12-20 07:10:31 +0000455 def https_open(self, req):
456 return self.do_open(self.httpconn, req)
457
Thomas Wouters477c8d52006-05-27 19:21:47 +0000458class MockPasswordManager:
459 def add_password(self, realm, uri, user, password):
460 self.realm = realm
461 self.url = uri
462 self.user = user
463 self.password = password
464 def find_user_password(self, realm, authuri):
465 self.target_realm = realm
466 self.target_url = authuri
467 return self.user, self.password
468
469
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000470class OpenerDirectorTests(unittest.TestCase):
471
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000472 def test_add_non_handler(self):
473 class NonHandler(object):
474 pass
475 self.assertRaises(TypeError,
476 OpenerDirector().add_handler, NonHandler())
477
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000478 def test_badly_named_methods(self):
479 # test work-around for three methods that accidentally follow the
480 # naming conventions for handler methods
481 # (*_open() / *_request() / *_response())
482
483 # These used to call the accidentally-named methods, causing a
484 # TypeError in real code; here, returning self from these mock
485 # methods would either cause no exception, or AttributeError.
486
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000487 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000488
489 o = OpenerDirector()
490 meth_spec = [
491 [("do_open", "return self"), ("proxy_open", "return self")],
492 [("redirect_request", "return self")],
493 ]
494 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000495 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000496 for scheme in "do", "proxy", "redirect":
497 self.assertRaises(URLError, o.open, scheme+"://example.com/")
498
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000499 def test_handled(self):
500 # handler returning non-None means no more handlers will be called
501 o = OpenerDirector()
502 meth_spec = [
503 ["http_open", "ftp_open", "http_error_302"],
504 ["ftp_open"],
505 [("http_open", "return self")],
506 [("http_open", "return self")],
507 ]
508 handlers = add_ordered_mock_handlers(o, meth_spec)
509
510 req = Request("http://example.com/")
511 r = o.open(req)
512 # Second .http_open() gets called, third doesn't, since second returned
513 # non-None. Handlers without .http_open() never get any methods called
514 # on them.
515 # In fact, second mock handler defining .http_open() returns self
516 # (instead of response), which becomes the OpenerDirector's return
517 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000518 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000519 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
520 for expected, got in zip(calls, o.calls):
521 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000522 self.assertEqual((handler, name), expected)
523 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000524
525 def test_handler_order(self):
526 o = OpenerDirector()
527 handlers = []
528 for meths, handler_order in [
529 ([("http_open", "return self")], 500),
530 (["http_open"], 0),
531 ]:
532 class MockHandlerSubclass(MockHandler): pass
533 h = MockHandlerSubclass(meths)
534 h.handler_order = handler_order
535 handlers.append(h)
536 o.add_handler(h)
537
538 r = o.open("http://example.com/")
539 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000540 self.assertEqual(o.calls[0][0], handlers[1])
541 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000542
543 def test_raise(self):
544 # raising URLError stops processing of request
545 o = OpenerDirector()
546 meth_spec = [
547 [("http_open", "raise")],
548 [("http_open", "return self")],
549 ]
550 handlers = add_ordered_mock_handlers(o, meth_spec)
551
552 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000553 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000554 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000555
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000556 def test_http_error(self):
557 # XXX http_error_default
558 # http errors are a special case
559 o = OpenerDirector()
560 meth_spec = [
561 [("http_open", "error 302")],
562 [("http_error_400", "raise"), "http_open"],
563 [("http_error_302", "return response"), "http_error_303",
564 "http_error"],
565 [("http_error_302")],
566 ]
567 handlers = add_ordered_mock_handlers(o, meth_spec)
568
569 class Unknown:
570 def __eq__(self, other): return True
571
572 req = Request("http://example.com/")
573 r = o.open(req)
574 assert len(o.calls) == 2
575 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000576 (handlers[2], "http_error_302",
577 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000578 for expected, got in zip(calls, o.calls):
579 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000580 self.assertEqual((handler, method_name), got[:2])
581 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000582
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700583
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000584 def test_processors(self):
585 # *_request / *_response methods get called appropriately
586 o = OpenerDirector()
587 meth_spec = [
588 [("http_request", "return request"),
589 ("http_response", "return response")],
590 [("http_request", "return request"),
591 ("http_response", "return response")],
592 ]
593 handlers = add_ordered_mock_handlers(o, meth_spec)
594
595 req = Request("http://example.com/")
596 r = o.open(req)
597 # processor methods are called on *all* handlers that define them,
598 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000599 calls = [
600 (handlers[0], "http_request"), (handlers[1], "http_request"),
601 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000602
603 for i, (handler, name, args, kwds) in enumerate(o.calls):
604 if i < 2:
605 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000606 self.assertEqual((handler, name), calls[i])
607 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000608 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000609 else:
610 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000611 self.assertEqual((handler, name), calls[i])
612 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000613 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000614 # response from opener.open is None, because there's no
615 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000616 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000617 isinstance(args[1], MockResponse))
618
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700619 def test_method_deprecations(self):
620 req = Request("http://www.example.com")
Senthil Kumaran08bd4aa2012-04-11 23:05:49 +0800621
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800622 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700623 req.add_data("data")
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800624 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700625 req.get_data()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800626 with self.assertWarns(DeprecationWarning):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700627 req.has_data()
628 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700629 req.get_host()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800630 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700631 req.get_selector()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800632 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700633 req.is_unverifiable()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800634 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700635 req.get_origin_req_host()
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700636 with self.assertWarns(DeprecationWarning):
637 req.get_type()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000638
Senthil Kumaran08bd4aa2012-04-11 23:05:49 +0800639
Tim Peters58eb11c2004-01-18 20:29:55 +0000640def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000641 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000642 path.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000643 except UnicodeEncodeError:
644 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000645 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000646 if os.name == "nt" and urlpath.startswith("///"):
647 urlpath = urlpath[2:]
648 # XXX don't ask me about the mac...
649 return urlpath
650
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000651class HandlerTests(unittest.TestCase):
652
653 def test_ftp(self):
654 class MockFTPWrapper:
655 def __init__(self, data): self.data = data
656 def retrfile(self, filename, filetype):
657 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000658 return io.StringIO(self.data), len(self.data)
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200659 def close(self): pass
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000660
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000661 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000662 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000663 def connect_ftp(self, user, passwd, host, port, dirs,
664 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000665 self.user, self.passwd = user, passwd
666 self.host, self.port = host, port
667 self.dirs = dirs
668 self.ftpwrapper = MockFTPWrapper(self.data)
669 return self.ftpwrapper
670
Georg Brandlf78e02b2008-06-10 17:40:04 +0000671 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000672 data = "rheum rhaponicum"
673 h = NullFTPHandler(data)
674 o = h.parent = MockOpener()
675
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000676 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000677 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000678 "localhost", ftplib.FTP_PORT, "", "", "I",
679 ["foo", "bar"], "baz.html", "text/html"),
680 ("ftp://parrot@localhost/foo/bar/baz.html",
681 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
682 ["foo", "bar"], "baz.html", "text/html"),
683 ("ftp://%25parrot@localhost/foo/bar/baz.html",
684 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
685 ["foo", "bar"], "baz.html", "text/html"),
686 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
687 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000688 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000689 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000690 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000691 ["foo", "bar"], "", None),
692 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000693 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000694 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000695 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000696 req = Request(url)
697 req.timeout = None
698 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000699 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000700 self.assertEqual(h.user, user)
701 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000702 self.assertEqual(h.host, socket.gethostbyname(host))
703 self.assertEqual(h.port, port)
704 self.assertEqual(h.dirs, dirs)
705 self.assertEqual(h.ftpwrapper.filename, filename)
706 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000707 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000708 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000709 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000710
711 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000712 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000713 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000714 o = h.parent = MockOpener()
715
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000716 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000717 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000718 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000719 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000720 "file://localhost%s" % urlpath,
721 "file://%s" % urlpath,
722 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000723 ]
724 try:
725 localaddr = socket.gethostbyname(socket.gethostname())
726 except socket.gaierror:
727 localaddr = ''
728 if localaddr:
729 urls.append("file://%s%s" % (localaddr, urlpath))
730
731 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000732 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000733 try:
734 try:
735 f.write(towrite)
736 finally:
737 f.close()
738
739 r = h.file_open(Request(url))
740 try:
741 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000742 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000743 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000744 finally:
745 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000746 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000747 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000748 finally:
749 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000750 self.assertEqual(data, towrite)
751 self.assertEqual(headers["Content-type"], "text/plain")
752 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000753 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000754 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000755
756 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000757 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000758 "file:///file_does_not_exist.txt",
759 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
760 os.getcwd(), TESTFN),
761 "file://somerandomhost.ontheinternet.com%s/%s" %
762 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000763 ]:
764 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000765 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766 try:
767 f.write(towrite)
768 finally:
769 f.close()
770
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000771 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000772 h.file_open, Request(url))
773 finally:
774 os.remove(TESTFN)
775
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000776 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000777 o = h.parent = MockOpener()
778 # XXXX why does // mean ftp (and /// mean not ftp!), and where
779 # is file: scheme specified? I think this is really a bug, and
780 # what was intended was to distinguish between URLs like:
781 # file:/blah.txt (a file)
782 # file://localhost/blah.txt (a file)
783 # file:///blah.txt (a file)
784 # file://ftp.example.com/blah.txt (an ftp URL)
785 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000786 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000787 ("file://ftp.example.com///foo.txt", False),
788# XXXX bug: fails with OSError, should be URLError
789 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000790 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000791 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000792 ]:
793 req = Request(url)
794 try:
795 h.file_open(req)
796 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000797 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000798 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000799 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000800 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000801 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000802 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000803
804 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000805
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000806 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000807 o = h.parent = MockOpener()
808
809 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000810 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000811 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000812 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000813 req.add_unredirected_header("Spam", "eggs")
814 http = MockHTTPClass()
815 r = h.do_open(http, req)
816
817 # result attributes
818 r.read; r.readline # wrapped MockFile methods
819 r.info; r.geturl # addinfourl methods
820 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
821 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000822 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000823 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000824
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000825 self.assertEqual(http.host, "example.com")
826 self.assertEqual(http.level, 0)
827 self.assertEqual(http.method, method)
828 self.assertEqual(http.selector, "/")
829 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000830 [("Connection", "close"),
831 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000832 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000833
834 # check socket.error converted to URLError
835 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000836 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000837
Senthil Kumaran29333122011-02-11 11:25:47 +0000838 # Check for TypeError on POST data which is str.
839 req = Request("http://example.com/","badpost")
840 self.assertRaises(TypeError, h.do_request_, req)
841
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000842 # check adding of standard headers
843 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000844 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000845 req = Request("http://example.com/", data)
846 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000847 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000848 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000849 self.assertNotIn("Content-length", req.unredirected_hdrs)
850 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000851 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000852 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
853 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000854 "application/x-www-form-urlencoded")
855 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000856 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
857 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000858
859 # don't clobber existing headers
860 req.add_unredirected_header("Content-length", "foo")
861 req.add_unredirected_header("Content-type", "bar")
862 req.add_unredirected_header("Host", "baz")
863 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000864 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000865 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
866 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000867 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
868 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000869
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000870 # Check iterable body support
871 def iterable_body():
872 yield b"one"
873 yield b"two"
874 yield b"three"
875
876 for headers in {}, {"Content-Length": 11}:
877 req = Request("http://example.com/", iterable_body(), headers)
878 if not headers:
879 # Having an iterable body without a Content-Length should
880 # raise an exception
881 self.assertRaises(ValueError, h.do_request_, req)
882 else:
883 newreq = h.do_request_(req)
884
Senthil Kumaran29333122011-02-11 11:25:47 +0000885 # A file object.
886 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000887
Senthil Kumaran29333122011-02-11 11:25:47 +0000888 file_obj = io.BytesIO()
889 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000890
891 for headers in {}, {"Content-Length": 30}:
892 req = Request("http://example.com/", file_obj, headers)
893 if not headers:
894 # Having an iterable body without a Content-Length should
895 # raise an exception
896 self.assertRaises(ValueError, h.do_request_, req)
897 else:
898 newreq = h.do_request_(req)
899 self.assertEqual(int(newreq.get_header('Content-length')),30)
900
901 file_obj.close()
902
903 # array.array Iterable - Content Length is calculated
904
905 iterable_array = array.array("I",[1,2,3,4])
906
907 for headers in {}, {"Content-Length": 16}:
908 req = Request("http://example.com/", iterable_array, headers)
909 newreq = h.do_request_(req)
910 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000911
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000912 def test_http_doubleslash(self):
913 # Checks the presence of any unnecessary double slash in url does not
914 # break anything. Previously, a double slash directly after the host
Ezio Melottie130a522011-10-19 10:58:56 +0300915 # could cause incorrect parsing.
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000916 h = urllib.request.AbstractHTTPHandler()
917 o = h.parent = MockOpener()
918
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000919 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000920 ds_urls = [
921 "http://example.com/foo/bar/baz.html",
922 "http://example.com//foo/bar/baz.html",
923 "http://example.com/foo//bar/baz.html",
924 "http://example.com/foo/bar//baz.html"
925 ]
926
927 for ds_url in ds_urls:
928 ds_req = Request(ds_url, data)
929
930 # Check whether host is determined correctly if there is no proxy
931 np_ds_req = h.do_request_(ds_req)
932 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
933
934 # Check whether host is determined correctly if there is a proxy
935 ds_req.set_proxy("someproxy:3128",None)
936 p_ds_req = h.do_request_(ds_req)
937 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
938
Senthil Kumaranc2958622010-11-22 04:48:26 +0000939 def test_fixpath_in_weirdurls(self):
940 # Issue4493: urllib2 to supply '/' when to urls where path does not
941 # start with'/'
942
943 h = urllib.request.AbstractHTTPHandler()
944 o = h.parent = MockOpener()
945
946 weird_url = 'http://www.python.org?getspam'
947 req = Request(weird_url)
948 newreq = h.do_request_(req)
949 self.assertEqual(newreq.host,'www.python.org')
950 self.assertEqual(newreq.selector,'/?getspam')
951
952 url_without_path = 'http://www.python.org'
953 req = Request(url_without_path)
954 newreq = h.do_request_(req)
955 self.assertEqual(newreq.host,'www.python.org')
956 self.assertEqual(newreq.selector,'')
957
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000958
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000959 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000960 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000961 o = h.parent = MockOpener()
962
963 url = "http://example.com/"
964 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000965 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000966 r = MockResponse(200, "OK", {}, "", url)
967 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000968 self.assertIs(r, newr)
969 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000970 r = MockResponse(202, "Accepted", {}, "", url)
971 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000972 self.assertIs(r, newr)
973 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000974 r = MockResponse(206, "Partial content", {}, "", url)
975 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000976 self.assertIs(r, newr)
977 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000978 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000979 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000980 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000981 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000982 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000983
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000984 def test_cookies(self):
985 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000986 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000987 o = h.parent = MockOpener()
988
989 req = Request("http://example.com/")
990 r = MockResponse(200, "OK", {}, "")
991 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000992 self.assertIs(cj.ach_req, req)
993 self.assertIs(cj.ach_req, newreq)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700994 self.assertEqual(req.origin_req_host, "example.com")
995 self.assertFalse(req.unverifiable)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000996 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000997 self.assertIs(cj.ec_req, req)
998 self.assertIs(cj.ec_r, r)
999 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001000
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001001 def test_redirect(self):
1002 from_url = "http://example.com/a.html"
1003 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001004 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001005 o = h.parent = MockOpener()
1006
1007 # ordinary redirect behaviour
1008 for code in 301, 302, 303, 307:
1009 for data in None, "blah\nblah\n":
1010 method = getattr(h, "http_error_%s" % code)
1011 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001012 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001013 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +00001014 if data is not None:
1015 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001016 req.add_unredirected_header("Spam", "spam")
1017 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001018 method(req, MockFile(), code, "Blah",
1019 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001020 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001021 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001022 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001023 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001024 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001025 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001026 except AttributeError:
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001027 self.assertFalse(o.req.data)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001028
1029 # now it's a GET, there should not be headers regarding content
1030 # (possibly dragged from before being a POST)
1031 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +00001032 self.assertNotIn("content-length", headers)
1033 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001034
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001035 self.assertEqual(o.req.headers["Nonsense"],
1036 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001037 self.assertNotIn("Spam", o.req.headers)
1038 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001039
1040 # loop detection
1041 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001042 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001043 def redirect(h, req, url=to_url):
1044 h.http_error_302(req, MockFile(), 302, "Blah",
1045 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001046 # Note that the *original* request shares the same record of
1047 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001048
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001049 # detect infinite loop redirect of a URL to itself
1050 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001051 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001052 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001053 try:
1054 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001055 redirect(h, req, "http://example.com/")
1056 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001057 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001058 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001059 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001060
1061 # detect endless non-repeating chain of redirects
1062 req = Request(from_url, origin_req_host="example.com")
1063 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001064 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001065 try:
1066 while 1:
1067 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001068 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001069 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001070 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001071 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001072
guido@google.coma119df92011-03-29 11:41:02 -07001073
1074 def test_invalid_redirect(self):
1075 from_url = "http://example.com/a.html"
1076 valid_schemes = ['http','https','ftp']
1077 invalid_schemes = ['file','imap','ldap']
1078 schemeless_url = "example.com/b.html"
1079 h = urllib.request.HTTPRedirectHandler()
1080 o = h.parent = MockOpener()
1081 req = Request(from_url)
1082 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1083
1084 for scheme in invalid_schemes:
1085 invalid_url = scheme + '://' + schemeless_url
1086 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1087 req, MockFile(), 302, "Security Loophole",
1088 MockHeaders({"location": invalid_url}))
1089
1090 for scheme in valid_schemes:
1091 valid_url = scheme + '://' + schemeless_url
1092 h.http_error_302(req, MockFile(), 302, "That's fine",
1093 MockHeaders({"location": valid_url}))
1094 self.assertEqual(o.req.get_full_url(), valid_url)
1095
Senthil Kumaran6497aa32012-01-04 13:46:59 +08001096 def test_relative_redirect(self):
1097 from_url = "http://example.com/a.html"
1098 relative_url = "/b.html"
1099 h = urllib.request.HTTPRedirectHandler()
1100 o = h.parent = MockOpener()
1101 req = Request(from_url)
1102 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1103
1104 valid_url = urllib.parse.urljoin(from_url,relative_url)
1105 h.http_error_302(req, MockFile(), 302, "That's fine",
1106 MockHeaders({"location": valid_url}))
1107 self.assertEqual(o.req.get_full_url(), valid_url)
1108
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001109 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001110 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001111 from http.cookiejar import CookieJar
1112 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001113
1114 cj = CookieJar()
1115 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001116 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001117 hdeh = urllib.request.HTTPDefaultErrorHandler()
1118 hrh = urllib.request.HTTPRedirectHandler()
1119 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001120 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001121 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001122 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001123
Senthil Kumaran26430412011-04-13 07:01:19 +08001124 def test_redirect_fragment(self):
1125 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1126 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1127 hdeh = urllib.request.HTTPDefaultErrorHandler()
1128 hrh = urllib.request.HTTPRedirectHandler()
1129 o = build_test_opener(hh, hdeh, hrh)
1130 fp = o.open('http://www.example.com')
1131 self.assertEqual(fp.geturl(), redirected_url.strip())
1132
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001133 def test_proxy(self):
1134 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001135 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001136 o.add_handler(ph)
1137 meth_spec = [
1138 [("http_open", "return response")]
1139 ]
1140 handlers = add_ordered_mock_handlers(o, meth_spec)
1141
1142 req = Request("http://acme.example.com/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001143 self.assertEqual(req.host, "acme.example.com")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001144 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001145 self.assertEqual(req.host, "proxy.example.com:3128")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001146
1147 self.assertEqual([(handlers[0], "http_open")],
1148 [tup[0:2] for tup in o.calls])
1149
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001150 def test_proxy_no_proxy(self):
1151 os.environ['no_proxy'] = 'python.org'
1152 o = OpenerDirector()
1153 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1154 o.add_handler(ph)
1155 req = Request("http://www.perl.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001156 self.assertEqual(req.host, "www.perl.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001157 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001158 self.assertEqual(req.host, "proxy.example.com")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001159 req = Request("http://www.python.org")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001160 self.assertEqual(req.host, "www.python.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001161 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001162 self.assertEqual(req.host, "www.python.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001163 del os.environ['no_proxy']
1164
Ronald Oussorene72e1612011-03-14 18:15:25 -04001165 def test_proxy_no_proxy_all(self):
1166 os.environ['no_proxy'] = '*'
1167 o = OpenerDirector()
1168 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1169 o.add_handler(ph)
1170 req = Request("http://www.python.org")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001171 self.assertEqual(req.host, "www.python.org")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001172 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001173 self.assertEqual(req.host, "www.python.org")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001174 del os.environ['no_proxy']
1175
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001176
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001177 def test_proxy_https(self):
1178 o = OpenerDirector()
1179 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1180 o.add_handler(ph)
1181 meth_spec = [
1182 [("https_open", "return response")]
1183 ]
1184 handlers = add_ordered_mock_handlers(o, meth_spec)
1185
1186 req = Request("https://www.example.com/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001187 self.assertEqual(req.host, "www.example.com")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001188 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001189 self.assertEqual(req.host, "proxy.example.com:3128")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001190 self.assertEqual([(handlers[0], "https_open")],
1191 [tup[0:2] for tup in o.calls])
1192
Senthil Kumaran47fff872009-12-20 07:10:31 +00001193 def test_proxy_https_proxy_authorization(self):
1194 o = OpenerDirector()
1195 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1196 o.add_handler(ph)
1197 https_handler = MockHTTPSHandler()
1198 o.add_handler(https_handler)
1199 req = Request("https://www.example.com/")
1200 req.add_header("Proxy-Authorization","FooBar")
1201 req.add_header("User-Agent","Grail")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001202 self.assertEqual(req.host, "www.example.com")
Senthil Kumaran47fff872009-12-20 07:10:31 +00001203 self.assertIsNone(req._tunnel_host)
1204 r = o.open(req)
1205 # Verify Proxy-Authorization gets tunneled to request.
1206 # httpsconn req_headers do not have the Proxy-Authorization header but
1207 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001208 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001209 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001210 self.assertIn(("User-Agent","Grail"),
1211 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001212 self.assertIsNotNone(req._tunnel_host)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001213 self.assertEqual(req.host, "proxy.example.com:3128")
Senthil Kumaran47fff872009-12-20 07:10:31 +00001214 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001215
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001216 # TODO: This should be only for OSX
1217 @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001218 def test_osx_proxy_bypass(self):
1219 bypass = {
1220 'exclude_simple': False,
1221 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1222 '10.0/16']
1223 }
1224 # Check hosts that should trigger the proxy bypass
1225 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1226 '10.0.0.1'):
1227 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1228 'expected bypass of %s to be True' % host)
1229 # Check hosts that should not trigger the proxy bypass
1230 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1231 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1232 'expected bypass of %s to be False' % host)
1233
1234 # Check the exclude_simple flag
1235 bypass = {'exclude_simple': True, 'exceptions': []}
1236 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1237
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001238 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001239 opener = OpenerDirector()
1240 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001241 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001242 realm = "ACME Widget Store"
1243 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001244 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1245 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001246 opener.add_handler(auth_handler)
1247 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001248 self._test_basic_auth(opener, auth_handler, "Authorization",
1249 realm, http_handler, password_manager,
1250 "http://acme.example.com/protected",
1251 "http://acme.example.com/protected",
1252 )
1253
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001254 def test_basic_auth_with_single_quoted_realm(self):
1255 self.test_basic_auth(quote_char="'")
1256
Senthil Kumaran34f3fcc2012-05-15 22:30:25 +08001257 def test_basic_auth_with_unquoted_realm(self):
1258 opener = OpenerDirector()
1259 password_manager = MockPasswordManager()
1260 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
1261 realm = "ACME Widget Store"
1262 http_handler = MockHTTPHandler(
1263 401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
1264 opener.add_handler(auth_handler)
1265 opener.add_handler(http_handler)
Senthil Kumaran0ea91cb2012-05-15 23:59:42 +08001266 with self.assertWarns(UserWarning):
1267 self._test_basic_auth(opener, auth_handler, "Authorization",
1268 realm, http_handler, password_manager,
1269 "http://acme.example.com/protected",
1270 "http://acme.example.com/protected",
1271 )
Senthil Kumaran34f3fcc2012-05-15 22:30:25 +08001272
Thomas Wouters477c8d52006-05-27 19:21:47 +00001273 def test_proxy_basic_auth(self):
1274 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001275 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001276 opener.add_handler(ph)
1277 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001278 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001279 realm = "ACME Networks"
1280 http_handler = MockHTTPHandler(
1281 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001282 opener.add_handler(auth_handler)
1283 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001284 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001285 realm, http_handler, password_manager,
1286 "http://acme.example.com:3128/protected",
1287 "proxy.example.com:3128",
1288 )
1289
1290 def test_basic_and_digest_auth_handlers(self):
Andrew Svetlov7bd61cb2012-12-19 22:49:25 +02001291 # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
Thomas Wouters477c8d52006-05-27 19:21:47 +00001292 # response (http://python.org/sf/1479302), where it should instead
1293 # return None to allow another handler (especially
1294 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001295
1296 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1297 # try digest first (since it's the strongest auth scheme), so we record
1298 # order of calls here to check digest comes first:
1299 class RecordingOpenerDirector(OpenerDirector):
1300 def __init__(self):
1301 OpenerDirector.__init__(self)
1302 self.recorded = []
1303 def record(self, info):
1304 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001305 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001306 def http_error_401(self, *args, **kwds):
1307 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001308 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001309 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001310 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001311 def http_error_401(self, *args, **kwds):
1312 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001313 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001314 *args, **kwds)
1315
1316 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001317 password_manager = MockPasswordManager()
1318 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001319 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001320 realm = "ACME Networks"
1321 http_handler = MockHTTPHandler(
1322 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001323 opener.add_handler(basic_handler)
1324 opener.add_handler(digest_handler)
1325 opener.add_handler(http_handler)
1326
1327 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001328 self._test_basic_auth(opener, basic_handler, "Authorization",
1329 realm, http_handler, password_manager,
1330 "http://acme.example.com/protected",
1331 "http://acme.example.com/protected",
1332 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001333 # check digest was tried before basic (twice, because
1334 # _test_basic_auth called .open() twice)
1335 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001336
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001337 def test_unsupported_auth_digest_handler(self):
1338 opener = OpenerDirector()
1339 # While using DigestAuthHandler
1340 digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
1341 http_handler = MockHTTPHandler(
1342 401, 'WWW-Authenticate: Kerberos\r\n\r\n')
1343 opener.add_handler(digest_auth_handler)
1344 opener.add_handler(http_handler)
1345 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1346
1347 def test_unsupported_auth_basic_handler(self):
1348 # While using BasicAuthHandler
1349 opener = OpenerDirector()
1350 basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
1351 http_handler = MockHTTPHandler(
1352 401, 'WWW-Authenticate: NTLM\r\n\r\n')
1353 opener.add_handler(basic_auth_handler)
1354 opener.add_handler(http_handler)
1355 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1356
Thomas Wouters477c8d52006-05-27 19:21:47 +00001357 def _test_basic_auth(self, opener, auth_handler, auth_header,
1358 realm, http_handler, password_manager,
1359 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001360 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001361 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001362
1363 # .add_password() fed through to password manager
1364 auth_handler.add_password(realm, request_url, user, password)
1365 self.assertEqual(realm, password_manager.realm)
1366 self.assertEqual(request_url, password_manager.url)
1367 self.assertEqual(user, password_manager.user)
1368 self.assertEqual(password, password_manager.password)
1369
1370 r = opener.open(request_url)
1371
1372 # should have asked the password manager for the username/password
1373 self.assertEqual(password_manager.target_realm, realm)
1374 self.assertEqual(password_manager.target_url, protected_url)
1375
1376 # expect one request without authorization, then one with
1377 self.assertEqual(len(http_handler.requests), 2)
1378 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001379 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001380 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001381 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001382 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1383 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001384 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1385 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001386 # if the password manager can't find a password, the handler won't
1387 # handle the HTTP auth error
1388 password_manager.user = password_manager.password = None
1389 http_handler.reset()
1390 r = opener.open(request_url)
1391 self.assertEqual(len(http_handler.requests), 1)
1392 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1393
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001394
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001395class MiscTests(unittest.TestCase):
1396
1397 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001398 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1399 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001400 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001401 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001402 def bar_open(self): pass
1403
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001404 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001405
1406 o = build_opener(FooHandler, BarHandler)
1407 self.opener_has_handler(o, FooHandler)
1408 self.opener_has_handler(o, BarHandler)
1409
1410 # can take a mix of classes and instances
1411 o = build_opener(FooHandler, BarHandler())
1412 self.opener_has_handler(o, FooHandler)
1413 self.opener_has_handler(o, BarHandler)
1414
1415 # subclasses of default handlers override default handlers
1416 o = build_opener(MyHTTPHandler)
1417 self.opener_has_handler(o, MyHTTPHandler)
1418
1419 # a particular case of overriding: default handlers can be passed
1420 # in explicitly
1421 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001422 self.opener_has_handler(o, urllib.request.HTTPHandler)
1423 o = build_opener(urllib.request.HTTPHandler)
1424 self.opener_has_handler(o, urllib.request.HTTPHandler)
1425 o = build_opener(urllib.request.HTTPHandler())
1426 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001427
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001428 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001429 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001430 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1431 self.opener_has_handler(o, MyHTTPHandler)
1432 self.opener_has_handler(o, MyOtherHTTPHandler)
1433
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001434 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001435 self.assertTrue(any(h.__class__ == handler_class
1436 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001437
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001438class RequestTests(unittest.TestCase):
1439
1440 def setUp(self):
1441 self.get = Request("http://www.python.org/~jeremy/")
1442 self.post = Request("http://www.python.org/~jeremy/",
1443 "data",
1444 headers={"X-Test": "test"})
1445
1446 def test_method(self):
1447 self.assertEqual("POST", self.post.get_method())
1448 self.assertEqual("GET", self.get.get_method())
1449
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001450 def test_data(self):
1451 self.assertFalse(self.get.data)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001452 self.assertEqual("GET", self.get.get_method())
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001453 self.get.data = "spam"
1454 self.assertTrue(self.get.data)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001455 self.assertEqual("POST", self.get.get_method())
1456
1457 def test_get_full_url(self):
1458 self.assertEqual("http://www.python.org/~jeremy/",
1459 self.get.get_full_url())
1460
1461 def test_selector(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001462 self.assertEqual("/~jeremy/", self.get.selector)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001463 req = Request("http://www.python.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001464 self.assertEqual("/", req.selector)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001465
1466 def test_get_type(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001467 self.assertEqual("http", self.get.type)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001468
1469 def test_get_host(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001470 self.assertEqual("www.python.org", self.get.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001471
1472 def test_get_host_unquote(self):
1473 req = Request("http://www.%70ython.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001474 self.assertEqual("www.python.org", req.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001475
1476 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001477 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001478 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001479 self.assertTrue(self.get.has_proxy())
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001480 self.assertEqual("www.python.org", self.get.origin_req_host)
1481 self.assertEqual("www.perl.org", self.get.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001482
Senthil Kumarand95cc752010-08-08 11:27:53 +00001483 def test_wrapped_url(self):
1484 req = Request("<URL:http://www.python.org>")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001485 self.assertEqual("www.python.org", req.host)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001486
Senthil Kumaran26430412011-04-13 07:01:19 +08001487 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001488 req = Request("http://www.python.org/?qs=query#fragment=true")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001489 self.assertEqual("/?qs=query", req.selector)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001490 req = Request("http://www.python.org/#fun=true")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001491 self.assertEqual("/", req.selector)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001492
Senthil Kumaran26430412011-04-13 07:01:19 +08001493 # Issue 11703: geturl() omits fragment in the original URL.
1494 url = 'http://docs.python.org/library/urllib2.html#OK'
1495 req = Request(url)
1496 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001497
Senthil Kumaran41e66a22012-12-23 09:04:24 -08001498 def test_HTTPError_interface(self):
1499 """
1500 Issue 13211 reveals that HTTPError didn't implement the URLError
1501 interface even though HTTPError is a subclass of URLError.
Jason R. Coombsaa204db2011-11-07 10:50:32 -05001502
Senthil Kumaran0a6b9ec2012-12-23 09:12:13 -08001503 >>> msg = 'something bad happened'
1504 >>> url = code = hdrs = fp = None
1505 >>> err = urllib.error.HTTPError(url, code, msg, hdrs, fp)
Senthil Kumaran41e66a22012-12-23 09:04:24 -08001506 >>> assert hasattr(err, 'reason')
1507 >>> err.reason
1508 'something bad happened'
1509 """
1510
1511 def test_HTTPError_interface_call(self):
1512 """
1513 Issue 15701 - HTTPError interface has info method available from URLError
1514 """
1515 err = urllib.request.HTTPError(msg="something bad happened", url=None,
1516 code=None, hdrs='Content-Length:42', fp=None)
1517 self.assertTrue(hasattr(err, 'reason'))
1518 assert hasattr(err, 'reason')
1519 assert hasattr(err, 'info')
1520 assert callable(err.info)
1521 try:
1522 err.info()
1523 except AttributeError:
1524 self.fail('err.info call failed.')
1525 self.assertEqual(err.info(), "Content-Length:42")
Jason R. Coombsaa204db2011-11-07 10:50:32 -05001526
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001527def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001528 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001529 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001530 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001531 tests = (TrivialTests,
1532 OpenerDirectorTests,
1533 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001534 MiscTests,
1535 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001536 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001537
1538if __name__ == "__main__":
1539 test_main(verbose=True)