blob: d19e11689791e5b6df843d0620860f0ec22b3ffb [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):
22 def test_trivial(self):
23 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000024
Jeremy Hylton1afc1692008-06-18 20:49:58 +000025 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000026
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000027 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000028 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000029
Senthil Kumarand587e302010-01-10 17:45:52 +000030 if os.name == 'nt':
31 file_url = "file:///%s" % fname
32 else:
33 file_url = "file://%s" % fname
34
Jeremy Hylton1afc1692008-06-18 20:49:58 +000035 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000036
37 buf = f.read()
38 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000039
Georg Brandle1b13d22005-08-24 22:20:32 +000040 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000041 tests = [
42 ('a,b,c', ['a', 'b', 'c']),
43 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
44 ('a, b, "c", "d", "e,f", g, h',
45 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
46 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
47 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000048 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000049 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000050
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000051
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000052def test_request_headers_dict():
53 """
54 The Request.headers dictionary is not a documented interface. It should
55 stay that way, because the complete set of headers are only accessible
56 through the .get_header(), .has_header(), .header_items() interface.
57 However, .headers pre-dates those methods, and so real code will be using
58 the dictionary.
59
60 The introduction in 2.4 of those methods was a mistake for the same reason:
61 code that previously saw all (urllib2 user)-provided headers in .headers
62 now sees only a subset (and the function interface is ugly and incomplete).
63 A better change would have been to replace .headers dict with a dict
64 subclass (or UserDict.DictMixin instance?) that preserved the .headers
65 interface and also provided access to the "unredirected" headers. It's
66 probably too late to fix that, though.
67
68
69 Check .capitalize() case normalization:
70
71 >>> url = "http://example.com"
72 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
73 'blah'
74 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
75 'blah'
76
77 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
78 but that could be changed in future.
79
80 """
81
82def test_request_headers_methods():
83 """
84 Note the case normalization of header names here, to .capitalize()-case.
85 This should be preserved for backwards-compatibility. (In the HTTP case,
86 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000087 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000088
89 >>> url = "http://example.com"
90 >>> r = Request(url, headers={"Spam-eggs": "blah"})
91 >>> r.has_header("Spam-eggs")
92 True
93 >>> r.header_items()
94 [('Spam-eggs', 'blah')]
95 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000096 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000097 >>> items
98 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
99
100 Note that e.g. r.has_header("spam-EggS") is currently False, and
101 r.get_header("spam-EggS") returns None, but that could be changed in
102 future.
103
104 >>> r.has_header("Not-there")
105 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000106 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000107 None
108 >>> r.get_header("Not-there", "default")
109 'default'
110
111 """
112
113
Thomas Wouters477c8d52006-05-27 19:21:47 +0000114def test_password_manager(self):
115 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000116 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000117 >>> add = mgr.add_password
118 >>> add("Some Realm", "http://example.com/", "joe", "password")
119 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
120 >>> add("c", "http://example.com/foo", "foo", "ni")
121 >>> add("c", "http://example.com/bar", "bar", "nini")
122 >>> add("b", "http://example.com/", "first", "blah")
123 >>> add("b", "http://example.com/", "second", "spam")
124 >>> add("a", "http://example.com", "1", "a")
125 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
126 >>> add("Some Realm", "d.example.com", "4", "d")
127 >>> add("Some Realm", "e.example.com:3128", "5", "e")
128
129 >>> mgr.find_user_password("Some Realm", "example.com")
130 ('joe', 'password')
131 >>> mgr.find_user_password("Some Realm", "http://example.com")
132 ('joe', 'password')
133 >>> mgr.find_user_password("Some Realm", "http://example.com/")
134 ('joe', 'password')
135 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
136 ('joe', 'password')
137 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
138 ('joe', 'password')
139 >>> mgr.find_user_password("c", "http://example.com/foo")
140 ('foo', 'ni')
141 >>> mgr.find_user_password("c", "http://example.com/bar")
142 ('bar', 'nini')
143
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000144 Actually, this is really undefined ATM
145## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000146
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000147## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
148## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000149
150 Use latest add_password() in case of conflict:
151
152 >>> mgr.find_user_password("b", "http://example.com/")
153 ('second', 'spam')
154
155 No special relationship between a.example.com and example.com:
156
157 >>> mgr.find_user_password("a", "http://example.com/")
158 ('1', 'a')
159 >>> mgr.find_user_password("a", "http://a.example.com/")
160 (None, None)
161
162 Ports:
163
164 >>> mgr.find_user_password("Some Realm", "c.example.com")
165 (None, None)
166 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
167 ('3', 'c')
168 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
169 ('3', 'c')
170 >>> mgr.find_user_password("Some Realm", "d.example.com")
171 ('4', 'd')
172 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
173 ('5', 'e')
174
175 """
176 pass
177
178
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000179def test_password_manager_default_port(self):
180 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000181 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000182 >>> add = mgr.add_password
183
184 The point to note here is that we can't guess the default port if there's
185 no scheme. This applies to both add_password and find_user_password.
186
187 >>> add("f", "http://g.example.com:80", "10", "j")
188 >>> add("g", "http://h.example.com", "11", "k")
189 >>> add("h", "i.example.com:80", "12", "l")
190 >>> add("i", "j.example.com", "13", "m")
191 >>> mgr.find_user_password("f", "g.example.com:100")
192 (None, None)
193 >>> mgr.find_user_password("f", "g.example.com:80")
194 ('10', 'j')
195 >>> mgr.find_user_password("f", "g.example.com")
196 (None, None)
197 >>> mgr.find_user_password("f", "http://g.example.com:100")
198 (None, None)
199 >>> mgr.find_user_password("f", "http://g.example.com:80")
200 ('10', 'j')
201 >>> mgr.find_user_password("f", "http://g.example.com")
202 ('10', 'j')
203 >>> mgr.find_user_password("g", "h.example.com")
204 ('11', 'k')
205 >>> mgr.find_user_password("g", "h.example.com:80")
206 ('11', 'k')
207 >>> mgr.find_user_password("g", "http://h.example.com:80")
208 ('11', 'k')
209 >>> mgr.find_user_password("h", "i.example.com")
210 (None, None)
211 >>> mgr.find_user_password("h", "i.example.com:80")
212 ('12', 'l')
213 >>> mgr.find_user_password("h", "http://i.example.com:80")
214 ('12', 'l')
215 >>> mgr.find_user_password("i", "j.example.com")
216 ('13', 'm')
217 >>> mgr.find_user_password("i", "j.example.com:80")
218 (None, None)
219 >>> mgr.find_user_password("i", "http://j.example.com")
220 ('13', 'm')
221 >>> mgr.find_user_password("i", "http://j.example.com:80")
222 (None, None)
223
224 """
225
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000226class MockOpener:
227 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000228 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
229 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000230 def error(self, proto, *args):
231 self.proto, self.args = proto, args
232
233class MockFile:
234 def read(self, count=None): pass
235 def readline(self, count=None): pass
236 def close(self): pass
237
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000238class MockHeaders(dict):
239 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000240 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000241
Guido van Rossum34d19282007-08-09 01:03:29 +0000242class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000243 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000244 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000245 self.code, self.msg, self.headers, self.url = code, msg, headers, url
246 def info(self):
247 return self.headers
248 def geturl(self):
249 return self.url
250
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000251class MockCookieJar:
252 def add_cookie_header(self, request):
253 self.ach_req = request
254 def extract_cookies(self, response, request):
255 self.ec_req, self.ec_r = request, response
256
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000257class FakeMethod:
258 def __init__(self, meth_name, action, handle):
259 self.meth_name = meth_name
260 self.handle = handle
261 self.action = action
262 def __call__(self, *args):
263 return self.handle(self.meth_name, self.action, *args)
264
Senthil Kumaran47fff872009-12-20 07:10:31 +0000265class MockHTTPResponse(io.IOBase):
266 def __init__(self, fp, msg, status, reason):
267 self.fp = fp
268 self.msg = msg
269 self.status = status
270 self.reason = reason
271 self.code = 200
272
273 def read(self):
274 return ''
275
276 def info(self):
277 return {}
278
279 def geturl(self):
280 return self.url
281
282
283class MockHTTPClass:
284 def __init__(self):
285 self.level = 0
286 self.req_headers = []
287 self.data = None
288 self.raise_on_endheaders = False
289 self._tunnel_headers = {}
290
291 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
292 self.host = host
293 self.timeout = timeout
294 return self
295
296 def set_debuglevel(self, level):
297 self.level = level
298
299 def set_tunnel(self, host, port=None, headers=None):
300 self._tunnel_host = host
301 self._tunnel_port = port
302 if headers:
303 self._tunnel_headers = headers
304 else:
305 self._tunnel_headers.clear()
306
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000307 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000308 self.method = method
309 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000310 if headers is not None:
311 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000312 self.req_headers.sort()
313 if body:
314 self.data = body
315 if self.raise_on_endheaders:
316 import socket
317 raise socket.error()
318 def getresponse(self):
319 return MockHTTPResponse(MockFile(), {}, 200, "OK")
320
Victor Stinnera4c45d72011-06-17 14:01:18 +0200321 def close(self):
322 pass
323
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000324class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000325 # useful for testing handler machinery
326 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000327 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000328 def __init__(self, methods):
329 self._define_methods(methods)
330 def _define_methods(self, methods):
331 for spec in methods:
332 if len(spec) == 2: name, action = spec
333 else: name, action = spec, None
334 meth = FakeMethod(name, action, self.handle)
335 setattr(self.__class__, name, meth)
336 def handle(self, fn_name, action, *args, **kwds):
337 self.parent.calls.append((self, fn_name, args, kwds))
338 if action is None:
339 return None
340 elif action == "return self":
341 return self
342 elif action == "return response":
343 res = MockResponse(200, "OK", {}, "")
344 return res
345 elif action == "return request":
346 return Request("http://blah/")
347 elif action.startswith("error"):
348 code = action[action.rfind(" ")+1:]
349 try:
350 code = int(code)
351 except ValueError:
352 pass
353 res = MockResponse(200, "OK", {}, "")
354 return self.parent.error("http", args[0], res, code, "", {})
355 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000356 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000357 assert False
358 def close(self): pass
359 def add_parent(self, parent):
360 self.parent = parent
361 self.parent.calls = []
362 def __lt__(self, other):
363 if not hasattr(other, "handler_order"):
364 # No handler_order, leave in original order. Yuck.
365 return True
366 return self.handler_order < other.handler_order
367
368def add_ordered_mock_handlers(opener, meth_spec):
369 """Create MockHandlers and add them to an OpenerDirector.
370
371 meth_spec: list of lists of tuples and strings defining methods to define
372 on handlers. eg:
373
374 [["http_error", "ftp_open"], ["http_open"]]
375
376 defines methods .http_error() and .ftp_open() on one handler, and
377 .http_open() on another. These methods just record their arguments and
378 return None. Using a tuple instead of a string causes the method to
379 perform some action (see MockHandler.handle()), eg:
380
381 [["http_error"], [("http_open", "return request")]]
382
383 defines .http_error() on one handler (which simply returns None), and
384 .http_open() on another handler, which returns a Request object.
385
386 """
387 handlers = []
388 count = 0
389 for meths in meth_spec:
390 class MockHandlerSubclass(MockHandler): pass
391 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000392 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000393 h.add_parent(opener)
394 count = count + 1
395 handlers.append(h)
396 opener.add_handler(h)
397 return handlers
398
Thomas Wouters477c8d52006-05-27 19:21:47 +0000399def build_test_opener(*handler_instances):
400 opener = OpenerDirector()
401 for h in handler_instances:
402 opener.add_handler(h)
403 return opener
404
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000405class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000406 # useful for testing redirections and auth
407 # sends supplied headers and code as first response
408 # sends 200 OK as second response
409 def __init__(self, code, headers):
410 self.code = code
411 self.headers = headers
412 self.reset()
413 def reset(self):
414 self._count = 0
415 self.requests = []
416 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000417 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000418 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000419 self.requests.append(copy.deepcopy(req))
420 if self._count == 0:
421 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000422 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000423 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000424 return self.parent.error(
425 "http", req, MockFile(), self.code, name, msg)
426 else:
427 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000428 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000429 return MockResponse(200, "OK", msg, "", req.get_full_url())
430
Senthil Kumaran47fff872009-12-20 07:10:31 +0000431class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
432 # Useful for testing the Proxy-Authorization request by verifying the
433 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000434
435 def __init__(self):
436 urllib.request.AbstractHTTPHandler.__init__(self)
437 self.httpconn = MockHTTPClass()
438
Senthil Kumaran47fff872009-12-20 07:10:31 +0000439 def https_open(self, req):
440 return self.do_open(self.httpconn, req)
441
Thomas Wouters477c8d52006-05-27 19:21:47 +0000442class MockPasswordManager:
443 def add_password(self, realm, uri, user, password):
444 self.realm = realm
445 self.url = uri
446 self.user = user
447 self.password = password
448 def find_user_password(self, realm, authuri):
449 self.target_realm = realm
450 self.target_url = authuri
451 return self.user, self.password
452
453
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000454class OpenerDirectorTests(unittest.TestCase):
455
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000456 def test_add_non_handler(self):
457 class NonHandler(object):
458 pass
459 self.assertRaises(TypeError,
460 OpenerDirector().add_handler, NonHandler())
461
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000462 def test_badly_named_methods(self):
463 # test work-around for three methods that accidentally follow the
464 # naming conventions for handler methods
465 # (*_open() / *_request() / *_response())
466
467 # These used to call the accidentally-named methods, causing a
468 # TypeError in real code; here, returning self from these mock
469 # methods would either cause no exception, or AttributeError.
470
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000471 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000472
473 o = OpenerDirector()
474 meth_spec = [
475 [("do_open", "return self"), ("proxy_open", "return self")],
476 [("redirect_request", "return self")],
477 ]
478 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000479 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000480 for scheme in "do", "proxy", "redirect":
481 self.assertRaises(URLError, o.open, scheme+"://example.com/")
482
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000483 def test_handled(self):
484 # handler returning non-None means no more handlers will be called
485 o = OpenerDirector()
486 meth_spec = [
487 ["http_open", "ftp_open", "http_error_302"],
488 ["ftp_open"],
489 [("http_open", "return self")],
490 [("http_open", "return self")],
491 ]
492 handlers = add_ordered_mock_handlers(o, meth_spec)
493
494 req = Request("http://example.com/")
495 r = o.open(req)
496 # Second .http_open() gets called, third doesn't, since second returned
497 # non-None. Handlers without .http_open() never get any methods called
498 # on them.
499 # In fact, second mock handler defining .http_open() returns self
500 # (instead of response), which becomes the OpenerDirector's return
501 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000502 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000503 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
504 for expected, got in zip(calls, o.calls):
505 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000506 self.assertEqual((handler, name), expected)
507 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000508
509 def test_handler_order(self):
510 o = OpenerDirector()
511 handlers = []
512 for meths, handler_order in [
513 ([("http_open", "return self")], 500),
514 (["http_open"], 0),
515 ]:
516 class MockHandlerSubclass(MockHandler): pass
517 h = MockHandlerSubclass(meths)
518 h.handler_order = handler_order
519 handlers.append(h)
520 o.add_handler(h)
521
522 r = o.open("http://example.com/")
523 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000524 self.assertEqual(o.calls[0][0], handlers[1])
525 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000526
527 def test_raise(self):
528 # raising URLError stops processing of request
529 o = OpenerDirector()
530 meth_spec = [
531 [("http_open", "raise")],
532 [("http_open", "return self")],
533 ]
534 handlers = add_ordered_mock_handlers(o, meth_spec)
535
536 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000537 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000538 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000539
540## def test_error(self):
541## # XXX this doesn't actually seem to be used in standard library,
542## # but should really be tested anyway...
543
544 def test_http_error(self):
545 # XXX http_error_default
546 # http errors are a special case
547 o = OpenerDirector()
548 meth_spec = [
549 [("http_open", "error 302")],
550 [("http_error_400", "raise"), "http_open"],
551 [("http_error_302", "return response"), "http_error_303",
552 "http_error"],
553 [("http_error_302")],
554 ]
555 handlers = add_ordered_mock_handlers(o, meth_spec)
556
557 class Unknown:
558 def __eq__(self, other): return True
559
560 req = Request("http://example.com/")
561 r = o.open(req)
562 assert len(o.calls) == 2
563 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000564 (handlers[2], "http_error_302",
565 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000566 for expected, got in zip(calls, o.calls):
567 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000568 self.assertEqual((handler, method_name), got[:2])
569 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000570
571 def test_processors(self):
572 # *_request / *_response methods get called appropriately
573 o = OpenerDirector()
574 meth_spec = [
575 [("http_request", "return request"),
576 ("http_response", "return response")],
577 [("http_request", "return request"),
578 ("http_response", "return response")],
579 ]
580 handlers = add_ordered_mock_handlers(o, meth_spec)
581
582 req = Request("http://example.com/")
583 r = o.open(req)
584 # processor methods are called on *all* handlers that define them,
585 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000586 calls = [
587 (handlers[0], "http_request"), (handlers[1], "http_request"),
588 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000589
590 for i, (handler, name, args, kwds) in enumerate(o.calls):
591 if i < 2:
592 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000593 self.assertEqual((handler, name), calls[i])
594 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000595 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000596 else:
597 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000598 self.assertEqual((handler, name), calls[i])
599 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000600 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000601 # response from opener.open is None, because there's no
602 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000603 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000604 isinstance(args[1], MockResponse))
605
606
Tim Peters58eb11c2004-01-18 20:29:55 +0000607def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000608 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000609 path.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000610 except UnicodeEncodeError:
611 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000612 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000613 if os.name == "nt" and urlpath.startswith("///"):
614 urlpath = urlpath[2:]
615 # XXX don't ask me about the mac...
616 return urlpath
617
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000618class HandlerTests(unittest.TestCase):
619
620 def test_ftp(self):
621 class MockFTPWrapper:
622 def __init__(self, data): self.data = data
623 def retrfile(self, filename, filetype):
624 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000625 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000626
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000627 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000628 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000629 def connect_ftp(self, user, passwd, host, port, dirs,
630 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000631 self.user, self.passwd = user, passwd
632 self.host, self.port = host, port
633 self.dirs = dirs
634 self.ftpwrapper = MockFTPWrapper(self.data)
635 return self.ftpwrapper
636
Georg Brandlf78e02b2008-06-10 17:40:04 +0000637 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000638 data = "rheum rhaponicum"
639 h = NullFTPHandler(data)
640 o = h.parent = MockOpener()
641
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000642 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000643 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000644 "localhost", ftplib.FTP_PORT, "", "", "I",
645 ["foo", "bar"], "baz.html", "text/html"),
646 ("ftp://parrot@localhost/foo/bar/baz.html",
647 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
648 ["foo", "bar"], "baz.html", "text/html"),
649 ("ftp://%25parrot@localhost/foo/bar/baz.html",
650 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
651 ["foo", "bar"], "baz.html", "text/html"),
652 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
653 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000654 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000655 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000656 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000657 ["foo", "bar"], "", None),
658 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000659 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000660 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000661 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000662 req = Request(url)
663 req.timeout = None
664 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000665 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000666 self.assertEqual(h.user, user)
667 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000668 self.assertEqual(h.host, socket.gethostbyname(host))
669 self.assertEqual(h.port, port)
670 self.assertEqual(h.dirs, dirs)
671 self.assertEqual(h.ftpwrapper.filename, filename)
672 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000673 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000674 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000675 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000676
677 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000678 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000679 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000680 o = h.parent = MockOpener()
681
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000682 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000683 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000684 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000685 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000686 "file://localhost%s" % urlpath,
687 "file://%s" % urlpath,
688 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000689 ]
690 try:
691 localaddr = socket.gethostbyname(socket.gethostname())
692 except socket.gaierror:
693 localaddr = ''
694 if localaddr:
695 urls.append("file://%s%s" % (localaddr, urlpath))
696
697 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000698 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000699 try:
700 try:
701 f.write(towrite)
702 finally:
703 f.close()
704
705 r = h.file_open(Request(url))
706 try:
707 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000708 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000709 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000710 finally:
711 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000712 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000713 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000714 finally:
715 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000716 self.assertEqual(data, towrite)
717 self.assertEqual(headers["Content-type"], "text/plain")
718 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000719 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000720 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000721
722 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000723 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000724 "file:///file_does_not_exist.txt",
725 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
726 os.getcwd(), TESTFN),
727 "file://somerandomhost.ontheinternet.com%s/%s" %
728 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000729 ]:
730 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000731 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000732 try:
733 f.write(towrite)
734 finally:
735 f.close()
736
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000737 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000738 h.file_open, Request(url))
739 finally:
740 os.remove(TESTFN)
741
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000742 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000743 o = h.parent = MockOpener()
744 # XXXX why does // mean ftp (and /// mean not ftp!), and where
745 # is file: scheme specified? I think this is really a bug, and
746 # what was intended was to distinguish between URLs like:
747 # file:/blah.txt (a file)
748 # file://localhost/blah.txt (a file)
749 # file:///blah.txt (a file)
750 # file://ftp.example.com/blah.txt (an ftp URL)
751 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000752 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000753 ("file://ftp.example.com///foo.txt", False),
754# XXXX bug: fails with OSError, should be URLError
755 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000756 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000757 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000758 ]:
759 req = Request(url)
760 try:
761 h.file_open(req)
762 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000763 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000764 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000765 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000766 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000767 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000768 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000769
770 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000771
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000772 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000773 o = h.parent = MockOpener()
774
775 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000776 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000777 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000778 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000779 req.add_unredirected_header("Spam", "eggs")
780 http = MockHTTPClass()
781 r = h.do_open(http, req)
782
783 # result attributes
784 r.read; r.readline # wrapped MockFile methods
785 r.info; r.geturl # addinfourl methods
786 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
787 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000788 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000789 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000790
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000791 self.assertEqual(http.host, "example.com")
792 self.assertEqual(http.level, 0)
793 self.assertEqual(http.method, method)
794 self.assertEqual(http.selector, "/")
795 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000796 [("Connection", "close"),
797 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000798 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000799
800 # check socket.error converted to URLError
801 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000802 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000803
Senthil Kumaran29333122011-02-11 11:25:47 +0000804 # Check for TypeError on POST data which is str.
805 req = Request("http://example.com/","badpost")
806 self.assertRaises(TypeError, h.do_request_, req)
807
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000808 # check adding of standard headers
809 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000810 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000811 req = Request("http://example.com/", data)
812 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000813 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000814 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000815 self.assertNotIn("Content-length", req.unredirected_hdrs)
816 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000817 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000818 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
819 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000820 "application/x-www-form-urlencoded")
821 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000822 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
823 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000824
825 # don't clobber existing headers
826 req.add_unredirected_header("Content-length", "foo")
827 req.add_unredirected_header("Content-type", "bar")
828 req.add_unredirected_header("Host", "baz")
829 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000830 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000831 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
832 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000833 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
834 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000835
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000836 # Check iterable body support
837 def iterable_body():
838 yield b"one"
839 yield b"two"
840 yield b"three"
841
842 for headers in {}, {"Content-Length": 11}:
843 req = Request("http://example.com/", iterable_body(), headers)
844 if not headers:
845 # Having an iterable body without a Content-Length should
846 # raise an exception
847 self.assertRaises(ValueError, h.do_request_, req)
848 else:
849 newreq = h.do_request_(req)
850
Senthil Kumaran29333122011-02-11 11:25:47 +0000851 # A file object.
852 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000853
Senthil Kumaran29333122011-02-11 11:25:47 +0000854 file_obj = io.BytesIO()
855 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000856
857 for headers in {}, {"Content-Length": 30}:
858 req = Request("http://example.com/", file_obj, headers)
859 if not headers:
860 # Having an iterable body without a Content-Length should
861 # raise an exception
862 self.assertRaises(ValueError, h.do_request_, req)
863 else:
864 newreq = h.do_request_(req)
865 self.assertEqual(int(newreq.get_header('Content-length')),30)
866
867 file_obj.close()
868
869 # array.array Iterable - Content Length is calculated
870
871 iterable_array = array.array("I",[1,2,3,4])
872
873 for headers in {}, {"Content-Length": 16}:
874 req = Request("http://example.com/", iterable_array, headers)
875 newreq = h.do_request_(req)
876 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000877
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000878 def test_http_doubleslash(self):
879 # Checks the presence of any unnecessary double slash in url does not
880 # break anything. Previously, a double slash directly after the host
881 # could could cause incorrect parsing.
882 h = urllib.request.AbstractHTTPHandler()
883 o = h.parent = MockOpener()
884
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000885 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000886 ds_urls = [
887 "http://example.com/foo/bar/baz.html",
888 "http://example.com//foo/bar/baz.html",
889 "http://example.com/foo//bar/baz.html",
890 "http://example.com/foo/bar//baz.html"
891 ]
892
893 for ds_url in ds_urls:
894 ds_req = Request(ds_url, data)
895
896 # Check whether host is determined correctly if there is no proxy
897 np_ds_req = h.do_request_(ds_req)
898 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
899
900 # Check whether host is determined correctly if there is a proxy
901 ds_req.set_proxy("someproxy:3128",None)
902 p_ds_req = h.do_request_(ds_req)
903 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
904
Senthil Kumaranc2958622010-11-22 04:48:26 +0000905 def test_fixpath_in_weirdurls(self):
906 # Issue4493: urllib2 to supply '/' when to urls where path does not
907 # start with'/'
908
909 h = urllib.request.AbstractHTTPHandler()
910 o = h.parent = MockOpener()
911
912 weird_url = 'http://www.python.org?getspam'
913 req = Request(weird_url)
914 newreq = h.do_request_(req)
915 self.assertEqual(newreq.host,'www.python.org')
916 self.assertEqual(newreq.selector,'/?getspam')
917
918 url_without_path = 'http://www.python.org'
919 req = Request(url_without_path)
920 newreq = h.do_request_(req)
921 self.assertEqual(newreq.host,'www.python.org')
922 self.assertEqual(newreq.selector,'')
923
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000924
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000925 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000926 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000927 o = h.parent = MockOpener()
928
929 url = "http://example.com/"
930 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000931 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000932 r = MockResponse(200, "OK", {}, "", url)
933 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000934 self.assertIs(r, newr)
935 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000936 r = MockResponse(202, "Accepted", {}, "", url)
937 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000938 self.assertIs(r, newr)
939 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000940 r = MockResponse(206, "Partial content", {}, "", url)
941 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000942 self.assertIs(r, newr)
943 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000944 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000945 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000946 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000947 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000948 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000949
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000950 def test_cookies(self):
951 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000952 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000953 o = h.parent = MockOpener()
954
955 req = Request("http://example.com/")
956 r = MockResponse(200, "OK", {}, "")
957 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000958 self.assertIs(cj.ach_req, req)
959 self.assertIs(cj.ach_req, newreq)
960 self.assertEqual(req.get_origin_req_host(), "example.com")
961 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000962 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000963 self.assertIs(cj.ec_req, req)
964 self.assertIs(cj.ec_r, r)
965 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000966
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000967 def test_redirect(self):
968 from_url = "http://example.com/a.html"
969 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000970 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000971 o = h.parent = MockOpener()
972
973 # ordinary redirect behaviour
974 for code in 301, 302, 303, 307:
975 for data in None, "blah\nblah\n":
976 method = getattr(h, "http_error_%s" % code)
977 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000978 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000979 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000980 if data is not None:
981 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000982 req.add_unredirected_header("Spam", "spam")
983 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000984 method(req, MockFile(), code, "Blah",
985 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000986 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000987 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000988 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000989 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000990 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000991 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000992 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000993 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000994
995 # now it's a GET, there should not be headers regarding content
996 # (possibly dragged from before being a POST)
997 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000998 self.assertNotIn("content-length", headers)
999 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001000
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001001 self.assertEqual(o.req.headers["Nonsense"],
1002 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001003 self.assertNotIn("Spam", o.req.headers)
1004 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001005
1006 # loop detection
1007 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001008 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001009 def redirect(h, req, url=to_url):
1010 h.http_error_302(req, MockFile(), 302, "Blah",
1011 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001012 # Note that the *original* request shares the same record of
1013 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001014
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001015 # detect infinite loop redirect of a URL to itself
1016 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001017 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001018 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001019 try:
1020 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001021 redirect(h, req, "http://example.com/")
1022 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001023 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001024 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001025 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001026
1027 # detect endless non-repeating chain of redirects
1028 req = Request(from_url, origin_req_host="example.com")
1029 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001030 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001031 try:
1032 while 1:
1033 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001034 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001035 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001036 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001037 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001038
guido@google.coma119df92011-03-29 11:41:02 -07001039
1040 def test_invalid_redirect(self):
1041 from_url = "http://example.com/a.html"
1042 valid_schemes = ['http','https','ftp']
1043 invalid_schemes = ['file','imap','ldap']
1044 schemeless_url = "example.com/b.html"
1045 h = urllib.request.HTTPRedirectHandler()
1046 o = h.parent = MockOpener()
1047 req = Request(from_url)
1048 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1049
1050 for scheme in invalid_schemes:
1051 invalid_url = scheme + '://' + schemeless_url
1052 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1053 req, MockFile(), 302, "Security Loophole",
1054 MockHeaders({"location": invalid_url}))
1055
1056 for scheme in valid_schemes:
1057 valid_url = scheme + '://' + schemeless_url
1058 h.http_error_302(req, MockFile(), 302, "That's fine",
1059 MockHeaders({"location": valid_url}))
1060 self.assertEqual(o.req.get_full_url(), valid_url)
1061
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001062 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001063 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001064 from http.cookiejar import CookieJar
1065 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001066
1067 cj = CookieJar()
1068 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001069 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001070 hdeh = urllib.request.HTTPDefaultErrorHandler()
1071 hrh = urllib.request.HTTPRedirectHandler()
1072 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001073 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001074 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001075 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001076
Senthil Kumaran26430412011-04-13 07:01:19 +08001077 def test_redirect_fragment(self):
1078 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1079 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1080 hdeh = urllib.request.HTTPDefaultErrorHandler()
1081 hrh = urllib.request.HTTPRedirectHandler()
1082 o = build_test_opener(hh, hdeh, hrh)
1083 fp = o.open('http://www.example.com')
1084 self.assertEqual(fp.geturl(), redirected_url.strip())
1085
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001086 def test_proxy(self):
1087 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001088 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001089 o.add_handler(ph)
1090 meth_spec = [
1091 [("http_open", "return response")]
1092 ]
1093 handlers = add_ordered_mock_handlers(o, meth_spec)
1094
1095 req = Request("http://acme.example.com/")
1096 self.assertEqual(req.get_host(), "acme.example.com")
1097 r = o.open(req)
1098 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1099
1100 self.assertEqual([(handlers[0], "http_open")],
1101 [tup[0:2] for tup in o.calls])
1102
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001103 def test_proxy_no_proxy(self):
1104 os.environ['no_proxy'] = 'python.org'
1105 o = OpenerDirector()
1106 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1107 o.add_handler(ph)
1108 req = Request("http://www.perl.org/")
1109 self.assertEqual(req.get_host(), "www.perl.org")
1110 r = o.open(req)
1111 self.assertEqual(req.get_host(), "proxy.example.com")
1112 req = Request("http://www.python.org")
1113 self.assertEqual(req.get_host(), "www.python.org")
1114 r = o.open(req)
1115 self.assertEqual(req.get_host(), "www.python.org")
1116 del os.environ['no_proxy']
1117
Ronald Oussorene72e1612011-03-14 18:15:25 -04001118 def test_proxy_no_proxy_all(self):
1119 os.environ['no_proxy'] = '*'
1120 o = OpenerDirector()
1121 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1122 o.add_handler(ph)
1123 req = Request("http://www.python.org")
1124 self.assertEqual(req.get_host(), "www.python.org")
1125 r = o.open(req)
1126 self.assertEqual(req.get_host(), "www.python.org")
1127 del os.environ['no_proxy']
1128
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001129
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001130 def test_proxy_https(self):
1131 o = OpenerDirector()
1132 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1133 o.add_handler(ph)
1134 meth_spec = [
1135 [("https_open", "return response")]
1136 ]
1137 handlers = add_ordered_mock_handlers(o, meth_spec)
1138
1139 req = Request("https://www.example.com/")
1140 self.assertEqual(req.get_host(), "www.example.com")
1141 r = o.open(req)
1142 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1143 self.assertEqual([(handlers[0], "https_open")],
1144 [tup[0:2] for tup in o.calls])
1145
Senthil Kumaran47fff872009-12-20 07:10:31 +00001146 def test_proxy_https_proxy_authorization(self):
1147 o = OpenerDirector()
1148 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1149 o.add_handler(ph)
1150 https_handler = MockHTTPSHandler()
1151 o.add_handler(https_handler)
1152 req = Request("https://www.example.com/")
1153 req.add_header("Proxy-Authorization","FooBar")
1154 req.add_header("User-Agent","Grail")
1155 self.assertEqual(req.get_host(), "www.example.com")
1156 self.assertIsNone(req._tunnel_host)
1157 r = o.open(req)
1158 # Verify Proxy-Authorization gets tunneled to request.
1159 # httpsconn req_headers do not have the Proxy-Authorization header but
1160 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001161 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001162 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001163 self.assertIn(("User-Agent","Grail"),
1164 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001165 self.assertIsNotNone(req._tunnel_host)
1166 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1167 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001168
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001169 # TODO: This should be only for OSX
1170 @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001171 def test_osx_proxy_bypass(self):
1172 bypass = {
1173 'exclude_simple': False,
1174 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1175 '10.0/16']
1176 }
1177 # Check hosts that should trigger the proxy bypass
1178 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1179 '10.0.0.1'):
1180 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1181 'expected bypass of %s to be True' % host)
1182 # Check hosts that should not trigger the proxy bypass
1183 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1184 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1185 'expected bypass of %s to be False' % host)
1186
1187 # Check the exclude_simple flag
1188 bypass = {'exclude_simple': True, 'exceptions': []}
1189 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1190
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001191 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001192 opener = OpenerDirector()
1193 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001194 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001195 realm = "ACME Widget Store"
1196 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001197 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1198 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001199 opener.add_handler(auth_handler)
1200 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001201 self._test_basic_auth(opener, auth_handler, "Authorization",
1202 realm, http_handler, password_manager,
1203 "http://acme.example.com/protected",
1204 "http://acme.example.com/protected",
1205 )
1206
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001207 def test_basic_auth_with_single_quoted_realm(self):
1208 self.test_basic_auth(quote_char="'")
1209
Thomas Wouters477c8d52006-05-27 19:21:47 +00001210 def test_proxy_basic_auth(self):
1211 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001212 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001213 opener.add_handler(ph)
1214 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001215 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001216 realm = "ACME Networks"
1217 http_handler = MockHTTPHandler(
1218 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001219 opener.add_handler(auth_handler)
1220 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001221 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001222 realm, http_handler, password_manager,
1223 "http://acme.example.com:3128/protected",
1224 "proxy.example.com:3128",
1225 )
1226
1227 def test_basic_and_digest_auth_handlers(self):
1228 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1229 # response (http://python.org/sf/1479302), where it should instead
1230 # return None to allow another handler (especially
1231 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001232
1233 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1234 # try digest first (since it's the strongest auth scheme), so we record
1235 # order of calls here to check digest comes first:
1236 class RecordingOpenerDirector(OpenerDirector):
1237 def __init__(self):
1238 OpenerDirector.__init__(self)
1239 self.recorded = []
1240 def record(self, info):
1241 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001242 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001243 def http_error_401(self, *args, **kwds):
1244 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001245 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001246 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001247 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001248 def http_error_401(self, *args, **kwds):
1249 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001250 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001251 *args, **kwds)
1252
1253 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001254 password_manager = MockPasswordManager()
1255 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001256 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001257 realm = "ACME Networks"
1258 http_handler = MockHTTPHandler(
1259 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001260 opener.add_handler(basic_handler)
1261 opener.add_handler(digest_handler)
1262 opener.add_handler(http_handler)
1263
1264 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001265 self._test_basic_auth(opener, basic_handler, "Authorization",
1266 realm, http_handler, password_manager,
1267 "http://acme.example.com/protected",
1268 "http://acme.example.com/protected",
1269 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001270 # check digest was tried before basic (twice, because
1271 # _test_basic_auth called .open() twice)
1272 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001273
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001274 def test_unsupported_auth_digest_handler(self):
1275 opener = OpenerDirector()
1276 # While using DigestAuthHandler
1277 digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
1278 http_handler = MockHTTPHandler(
1279 401, 'WWW-Authenticate: Kerberos\r\n\r\n')
1280 opener.add_handler(digest_auth_handler)
1281 opener.add_handler(http_handler)
1282 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1283
1284 def test_unsupported_auth_basic_handler(self):
1285 # While using BasicAuthHandler
1286 opener = OpenerDirector()
1287 basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
1288 http_handler = MockHTTPHandler(
1289 401, 'WWW-Authenticate: NTLM\r\n\r\n')
1290 opener.add_handler(basic_auth_handler)
1291 opener.add_handler(http_handler)
1292 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1293
Thomas Wouters477c8d52006-05-27 19:21:47 +00001294 def _test_basic_auth(self, opener, auth_handler, auth_header,
1295 realm, http_handler, password_manager,
1296 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001297 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001298 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001299
1300 # .add_password() fed through to password manager
1301 auth_handler.add_password(realm, request_url, user, password)
1302 self.assertEqual(realm, password_manager.realm)
1303 self.assertEqual(request_url, password_manager.url)
1304 self.assertEqual(user, password_manager.user)
1305 self.assertEqual(password, password_manager.password)
1306
1307 r = opener.open(request_url)
1308
1309 # should have asked the password manager for the username/password
1310 self.assertEqual(password_manager.target_realm, realm)
1311 self.assertEqual(password_manager.target_url, protected_url)
1312
1313 # expect one request without authorization, then one with
1314 self.assertEqual(len(http_handler.requests), 2)
1315 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001316 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001317 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001318 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001319 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1320 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001321 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1322 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001323 # if the password manager can't find a password, the handler won't
1324 # handle the HTTP auth error
1325 password_manager.user = password_manager.password = None
1326 http_handler.reset()
1327 r = opener.open(request_url)
1328 self.assertEqual(len(http_handler.requests), 1)
1329 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1330
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001331
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001332class MiscTests(unittest.TestCase):
1333
1334 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001335 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1336 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001337 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001338 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001339 def bar_open(self): pass
1340
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001341 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001342
1343 o = build_opener(FooHandler, BarHandler)
1344 self.opener_has_handler(o, FooHandler)
1345 self.opener_has_handler(o, BarHandler)
1346
1347 # can take a mix of classes and instances
1348 o = build_opener(FooHandler, BarHandler())
1349 self.opener_has_handler(o, FooHandler)
1350 self.opener_has_handler(o, BarHandler)
1351
1352 # subclasses of default handlers override default handlers
1353 o = build_opener(MyHTTPHandler)
1354 self.opener_has_handler(o, MyHTTPHandler)
1355
1356 # a particular case of overriding: default handlers can be passed
1357 # in explicitly
1358 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001359 self.opener_has_handler(o, urllib.request.HTTPHandler)
1360 o = build_opener(urllib.request.HTTPHandler)
1361 self.opener_has_handler(o, urllib.request.HTTPHandler)
1362 o = build_opener(urllib.request.HTTPHandler())
1363 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001364
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001365 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001366 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001367 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1368 self.opener_has_handler(o, MyHTTPHandler)
1369 self.opener_has_handler(o, MyOtherHTTPHandler)
1370
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001371 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001372 self.assertTrue(any(h.__class__ == handler_class
1373 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001374
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001375class RequestTests(unittest.TestCase):
1376
1377 def setUp(self):
1378 self.get = Request("http://www.python.org/~jeremy/")
1379 self.post = Request("http://www.python.org/~jeremy/",
1380 "data",
1381 headers={"X-Test": "test"})
1382
1383 def test_method(self):
1384 self.assertEqual("POST", self.post.get_method())
1385 self.assertEqual("GET", self.get.get_method())
1386
1387 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001388 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001389 self.assertEqual("GET", self.get.get_method())
1390 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001391 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001392 self.assertEqual("POST", self.get.get_method())
1393
1394 def test_get_full_url(self):
1395 self.assertEqual("http://www.python.org/~jeremy/",
1396 self.get.get_full_url())
1397
1398 def test_selector(self):
1399 self.assertEqual("/~jeremy/", self.get.get_selector())
1400 req = Request("http://www.python.org/")
1401 self.assertEqual("/", req.get_selector())
1402
1403 def test_get_type(self):
1404 self.assertEqual("http", self.get.get_type())
1405
1406 def test_get_host(self):
1407 self.assertEqual("www.python.org", self.get.get_host())
1408
1409 def test_get_host_unquote(self):
1410 req = Request("http://www.%70ython.org/")
1411 self.assertEqual("www.python.org", req.get_host())
1412
1413 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001414 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001415 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001416 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001417 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1418 self.assertEqual("www.perl.org", self.get.get_host())
1419
Senthil Kumarand95cc752010-08-08 11:27:53 +00001420 def test_wrapped_url(self):
1421 req = Request("<URL:http://www.python.org>")
1422 self.assertEqual("www.python.org", req.get_host())
1423
Senthil Kumaran26430412011-04-13 07:01:19 +08001424 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001425 req = Request("http://www.python.org/?qs=query#fragment=true")
1426 self.assertEqual("/?qs=query", req.get_selector())
1427 req = Request("http://www.python.org/#fun=true")
1428 self.assertEqual("/", req.get_selector())
1429
Senthil Kumaran26430412011-04-13 07:01:19 +08001430 # Issue 11703: geturl() omits fragment in the original URL.
1431 url = 'http://docs.python.org/library/urllib2.html#OK'
1432 req = Request(url)
1433 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001434
1435def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001436 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001437 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001438 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001439 tests = (TrivialTests,
1440 OpenerDirectorTests,
1441 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001442 MiscTests,
1443 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001444 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001445
1446if __name__ == "__main__":
1447 test_main(verbose=True)