blob: 713a97f774f57b2fcff2a32e22397747327f0cea [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)
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200626 def close(self): pass
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000627
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000628 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000629 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000630 def connect_ftp(self, user, passwd, host, port, dirs,
631 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000632 self.user, self.passwd = user, passwd
633 self.host, self.port = host, port
634 self.dirs = dirs
635 self.ftpwrapper = MockFTPWrapper(self.data)
636 return self.ftpwrapper
637
Georg Brandlf78e02b2008-06-10 17:40:04 +0000638 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000639 data = "rheum rhaponicum"
640 h = NullFTPHandler(data)
641 o = h.parent = MockOpener()
642
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000643 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000644 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000645 "localhost", ftplib.FTP_PORT, "", "", "I",
646 ["foo", "bar"], "baz.html", "text/html"),
647 ("ftp://parrot@localhost/foo/bar/baz.html",
648 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
649 ["foo", "bar"], "baz.html", "text/html"),
650 ("ftp://%25parrot@localhost/foo/bar/baz.html",
651 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
652 ["foo", "bar"], "baz.html", "text/html"),
653 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
654 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000655 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000656 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000657 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000658 ["foo", "bar"], "", None),
659 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000660 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000661 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000662 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000663 req = Request(url)
664 req.timeout = None
665 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000666 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000667 self.assertEqual(h.user, user)
668 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000669 self.assertEqual(h.host, socket.gethostbyname(host))
670 self.assertEqual(h.port, port)
671 self.assertEqual(h.dirs, dirs)
672 self.assertEqual(h.ftpwrapper.filename, filename)
673 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000674 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000675 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000676 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000677
678 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000679 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000680 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000681 o = h.parent = MockOpener()
682
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000683 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000684 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000685 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000686 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000687 "file://localhost%s" % urlpath,
688 "file://%s" % urlpath,
689 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000690 ]
691 try:
692 localaddr = socket.gethostbyname(socket.gethostname())
693 except socket.gaierror:
694 localaddr = ''
695 if localaddr:
696 urls.append("file://%s%s" % (localaddr, urlpath))
697
698 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000699 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000700 try:
701 try:
702 f.write(towrite)
703 finally:
704 f.close()
705
706 r = h.file_open(Request(url))
707 try:
708 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000709 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000710 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000711 finally:
712 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000713 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000714 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000715 finally:
716 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000717 self.assertEqual(data, towrite)
718 self.assertEqual(headers["Content-type"], "text/plain")
719 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000720 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000721 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000722
723 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000724 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000725 "file:///file_does_not_exist.txt",
726 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
727 os.getcwd(), TESTFN),
728 "file://somerandomhost.ontheinternet.com%s/%s" %
729 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000730 ]:
731 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000732 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000733 try:
734 f.write(towrite)
735 finally:
736 f.close()
737
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000738 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000739 h.file_open, Request(url))
740 finally:
741 os.remove(TESTFN)
742
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000743 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000744 o = h.parent = MockOpener()
745 # XXXX why does // mean ftp (and /// mean not ftp!), and where
746 # is file: scheme specified? I think this is really a bug, and
747 # what was intended was to distinguish between URLs like:
748 # file:/blah.txt (a file)
749 # file://localhost/blah.txt (a file)
750 # file:///blah.txt (a file)
751 # file://ftp.example.com/blah.txt (an ftp URL)
752 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000753 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000754 ("file://ftp.example.com///foo.txt", False),
755# XXXX bug: fails with OSError, should be URLError
756 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000757 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000758 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000759 ]:
760 req = Request(url)
761 try:
762 h.file_open(req)
763 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000764 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000765 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000767 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000768 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000769 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000770
771 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000772
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000773 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000774 o = h.parent = MockOpener()
775
776 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000777 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000778 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000779 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000780 req.add_unredirected_header("Spam", "eggs")
781 http = MockHTTPClass()
782 r = h.do_open(http, req)
783
784 # result attributes
785 r.read; r.readline # wrapped MockFile methods
786 r.info; r.geturl # addinfourl methods
787 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
788 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000789 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000790 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000791
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000792 self.assertEqual(http.host, "example.com")
793 self.assertEqual(http.level, 0)
794 self.assertEqual(http.method, method)
795 self.assertEqual(http.selector, "/")
796 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000797 [("Connection", "close"),
798 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000799 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000800
801 # check socket.error converted to URLError
802 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000803 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000804
Senthil Kumaran29333122011-02-11 11:25:47 +0000805 # Check for TypeError on POST data which is str.
806 req = Request("http://example.com/","badpost")
807 self.assertRaises(TypeError, h.do_request_, req)
808
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000809 # check adding of standard headers
810 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000811 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000812 req = Request("http://example.com/", data)
813 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000814 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000815 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000816 self.assertNotIn("Content-length", req.unredirected_hdrs)
817 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000818 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000819 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
820 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000821 "application/x-www-form-urlencoded")
822 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000823 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
824 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000825
826 # don't clobber existing headers
827 req.add_unredirected_header("Content-length", "foo")
828 req.add_unredirected_header("Content-type", "bar")
829 req.add_unredirected_header("Host", "baz")
830 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000831 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000832 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
833 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000834 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
835 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000836
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000837 # Check iterable body support
838 def iterable_body():
839 yield b"one"
840 yield b"two"
841 yield b"three"
842
843 for headers in {}, {"Content-Length": 11}:
844 req = Request("http://example.com/", iterable_body(), headers)
845 if not headers:
846 # Having an iterable body without a Content-Length should
847 # raise an exception
848 self.assertRaises(ValueError, h.do_request_, req)
849 else:
850 newreq = h.do_request_(req)
851
Senthil Kumaran29333122011-02-11 11:25:47 +0000852 # A file object.
853 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000854
Senthil Kumaran29333122011-02-11 11:25:47 +0000855 file_obj = io.BytesIO()
856 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000857
858 for headers in {}, {"Content-Length": 30}:
859 req = Request("http://example.com/", file_obj, headers)
860 if not headers:
861 # Having an iterable body without a Content-Length should
862 # raise an exception
863 self.assertRaises(ValueError, h.do_request_, req)
864 else:
865 newreq = h.do_request_(req)
866 self.assertEqual(int(newreq.get_header('Content-length')),30)
867
868 file_obj.close()
869
870 # array.array Iterable - Content Length is calculated
871
872 iterable_array = array.array("I",[1,2,3,4])
873
874 for headers in {}, {"Content-Length": 16}:
875 req = Request("http://example.com/", iterable_array, headers)
876 newreq = h.do_request_(req)
877 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000878
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000879 def test_http_doubleslash(self):
880 # Checks the presence of any unnecessary double slash in url does not
881 # break anything. Previously, a double slash directly after the host
882 # could could cause incorrect parsing.
883 h = urllib.request.AbstractHTTPHandler()
884 o = h.parent = MockOpener()
885
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000886 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000887 ds_urls = [
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 "http://example.com/foo/bar//baz.html"
892 ]
893
894 for ds_url in ds_urls:
895 ds_req = Request(ds_url, data)
896
897 # Check whether host is determined correctly if there is no proxy
898 np_ds_req = h.do_request_(ds_req)
899 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
900
901 # Check whether host is determined correctly if there is a proxy
902 ds_req.set_proxy("someproxy:3128",None)
903 p_ds_req = h.do_request_(ds_req)
904 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
905
Senthil Kumaranc2958622010-11-22 04:48:26 +0000906 def test_fixpath_in_weirdurls(self):
907 # Issue4493: urllib2 to supply '/' when to urls where path does not
908 # start with'/'
909
910 h = urllib.request.AbstractHTTPHandler()
911 o = h.parent = MockOpener()
912
913 weird_url = 'http://www.python.org?getspam'
914 req = Request(weird_url)
915 newreq = h.do_request_(req)
916 self.assertEqual(newreq.host,'www.python.org')
917 self.assertEqual(newreq.selector,'/?getspam')
918
919 url_without_path = 'http://www.python.org'
920 req = Request(url_without_path)
921 newreq = h.do_request_(req)
922 self.assertEqual(newreq.host,'www.python.org')
923 self.assertEqual(newreq.selector,'')
924
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000925
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000926 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000927 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000928 o = h.parent = MockOpener()
929
930 url = "http://example.com/"
931 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000932 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000933 r = MockResponse(200, "OK", {}, "", url)
934 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000935 self.assertIs(r, newr)
936 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000937 r = MockResponse(202, "Accepted", {}, "", url)
938 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000939 self.assertIs(r, newr)
940 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941 r = MockResponse(206, "Partial content", {}, "", url)
942 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000943 self.assertIs(r, newr)
944 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000945 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000946 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000947 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000948 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000949 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000950
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000951 def test_cookies(self):
952 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000953 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000954 o = h.parent = MockOpener()
955
956 req = Request("http://example.com/")
957 r = MockResponse(200, "OK", {}, "")
958 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000959 self.assertIs(cj.ach_req, req)
960 self.assertIs(cj.ach_req, newreq)
961 self.assertEqual(req.get_origin_req_host(), "example.com")
962 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000963 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000964 self.assertIs(cj.ec_req, req)
965 self.assertIs(cj.ec_r, r)
966 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000967
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000968 def test_redirect(self):
969 from_url = "http://example.com/a.html"
970 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000971 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000972 o = h.parent = MockOpener()
973
974 # ordinary redirect behaviour
975 for code in 301, 302, 303, 307:
976 for data in None, "blah\nblah\n":
977 method = getattr(h, "http_error_%s" % code)
978 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000979 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000980 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000981 if data is not None:
982 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000983 req.add_unredirected_header("Spam", "spam")
984 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000985 method(req, MockFile(), code, "Blah",
986 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000987 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000988 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000989 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000990 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000991 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000992 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000993 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000994 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000995
996 # now it's a GET, there should not be headers regarding content
997 # (possibly dragged from before being a POST)
998 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000999 self.assertNotIn("content-length", headers)
1000 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001001
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001002 self.assertEqual(o.req.headers["Nonsense"],
1003 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001004 self.assertNotIn("Spam", o.req.headers)
1005 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001006
1007 # loop detection
1008 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001009 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001010 def redirect(h, req, url=to_url):
1011 h.http_error_302(req, MockFile(), 302, "Blah",
1012 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001013 # Note that the *original* request shares the same record of
1014 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001015
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001016 # detect infinite loop redirect of a URL to itself
1017 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001018 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001019 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001020 try:
1021 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001022 redirect(h, req, "http://example.com/")
1023 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001024 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001025 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001026 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001027
1028 # detect endless non-repeating chain of redirects
1029 req = Request(from_url, origin_req_host="example.com")
1030 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001031 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001032 try:
1033 while 1:
1034 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001035 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001036 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001037 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001038 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001039
guido@google.coma119df92011-03-29 11:41:02 -07001040
1041 def test_invalid_redirect(self):
1042 from_url = "http://example.com/a.html"
1043 valid_schemes = ['http','https','ftp']
1044 invalid_schemes = ['file','imap','ldap']
1045 schemeless_url = "example.com/b.html"
1046 h = urllib.request.HTTPRedirectHandler()
1047 o = h.parent = MockOpener()
1048 req = Request(from_url)
1049 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1050
1051 for scheme in invalid_schemes:
1052 invalid_url = scheme + '://' + schemeless_url
1053 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1054 req, MockFile(), 302, "Security Loophole",
1055 MockHeaders({"location": invalid_url}))
1056
1057 for scheme in valid_schemes:
1058 valid_url = scheme + '://' + schemeless_url
1059 h.http_error_302(req, MockFile(), 302, "That's fine",
1060 MockHeaders({"location": valid_url}))
1061 self.assertEqual(o.req.get_full_url(), valid_url)
1062
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001063 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001064 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001065 from http.cookiejar import CookieJar
1066 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001067
1068 cj = CookieJar()
1069 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001070 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001071 hdeh = urllib.request.HTTPDefaultErrorHandler()
1072 hrh = urllib.request.HTTPRedirectHandler()
1073 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001074 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001075 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001076 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001077
Senthil Kumaran26430412011-04-13 07:01:19 +08001078 def test_redirect_fragment(self):
1079 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1080 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1081 hdeh = urllib.request.HTTPDefaultErrorHandler()
1082 hrh = urllib.request.HTTPRedirectHandler()
1083 o = build_test_opener(hh, hdeh, hrh)
1084 fp = o.open('http://www.example.com')
1085 self.assertEqual(fp.geturl(), redirected_url.strip())
1086
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001087 def test_proxy(self):
1088 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001089 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001090 o.add_handler(ph)
1091 meth_spec = [
1092 [("http_open", "return response")]
1093 ]
1094 handlers = add_ordered_mock_handlers(o, meth_spec)
1095
1096 req = Request("http://acme.example.com/")
1097 self.assertEqual(req.get_host(), "acme.example.com")
1098 r = o.open(req)
1099 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1100
1101 self.assertEqual([(handlers[0], "http_open")],
1102 [tup[0:2] for tup in o.calls])
1103
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001104 def test_proxy_no_proxy(self):
1105 os.environ['no_proxy'] = 'python.org'
1106 o = OpenerDirector()
1107 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1108 o.add_handler(ph)
1109 req = Request("http://www.perl.org/")
1110 self.assertEqual(req.get_host(), "www.perl.org")
1111 r = o.open(req)
1112 self.assertEqual(req.get_host(), "proxy.example.com")
1113 req = Request("http://www.python.org")
1114 self.assertEqual(req.get_host(), "www.python.org")
1115 r = o.open(req)
1116 self.assertEqual(req.get_host(), "www.python.org")
1117 del os.environ['no_proxy']
1118
Ronald Oussorene72e1612011-03-14 18:15:25 -04001119 def test_proxy_no_proxy_all(self):
1120 os.environ['no_proxy'] = '*'
1121 o = OpenerDirector()
1122 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1123 o.add_handler(ph)
1124 req = Request("http://www.python.org")
1125 self.assertEqual(req.get_host(), "www.python.org")
1126 r = o.open(req)
1127 self.assertEqual(req.get_host(), "www.python.org")
1128 del os.environ['no_proxy']
1129
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001130
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001131 def test_proxy_https(self):
1132 o = OpenerDirector()
1133 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1134 o.add_handler(ph)
1135 meth_spec = [
1136 [("https_open", "return response")]
1137 ]
1138 handlers = add_ordered_mock_handlers(o, meth_spec)
1139
1140 req = Request("https://www.example.com/")
1141 self.assertEqual(req.get_host(), "www.example.com")
1142 r = o.open(req)
1143 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1144 self.assertEqual([(handlers[0], "https_open")],
1145 [tup[0:2] for tup in o.calls])
1146
Senthil Kumaran47fff872009-12-20 07:10:31 +00001147 def test_proxy_https_proxy_authorization(self):
1148 o = OpenerDirector()
1149 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1150 o.add_handler(ph)
1151 https_handler = MockHTTPSHandler()
1152 o.add_handler(https_handler)
1153 req = Request("https://www.example.com/")
1154 req.add_header("Proxy-Authorization","FooBar")
1155 req.add_header("User-Agent","Grail")
1156 self.assertEqual(req.get_host(), "www.example.com")
1157 self.assertIsNone(req._tunnel_host)
1158 r = o.open(req)
1159 # Verify Proxy-Authorization gets tunneled to request.
1160 # httpsconn req_headers do not have the Proxy-Authorization header but
1161 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001162 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001163 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001164 self.assertIn(("User-Agent","Grail"),
1165 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001166 self.assertIsNotNone(req._tunnel_host)
1167 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1168 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001169
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001170 # TODO: This should be only for OSX
1171 @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001172 def test_osx_proxy_bypass(self):
1173 bypass = {
1174 'exclude_simple': False,
1175 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1176 '10.0/16']
1177 }
1178 # Check hosts that should trigger the proxy bypass
1179 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1180 '10.0.0.1'):
1181 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1182 'expected bypass of %s to be True' % host)
1183 # Check hosts that should not trigger the proxy bypass
1184 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1185 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1186 'expected bypass of %s to be False' % host)
1187
1188 # Check the exclude_simple flag
1189 bypass = {'exclude_simple': True, 'exceptions': []}
1190 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1191
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001192 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001193 opener = OpenerDirector()
1194 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001195 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001196 realm = "ACME Widget Store"
1197 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001198 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1199 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001200 opener.add_handler(auth_handler)
1201 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001202 self._test_basic_auth(opener, auth_handler, "Authorization",
1203 realm, http_handler, password_manager,
1204 "http://acme.example.com/protected",
1205 "http://acme.example.com/protected",
1206 )
1207
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001208 def test_basic_auth_with_single_quoted_realm(self):
1209 self.test_basic_auth(quote_char="'")
1210
Thomas Wouters477c8d52006-05-27 19:21:47 +00001211 def test_proxy_basic_auth(self):
1212 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001213 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001214 opener.add_handler(ph)
1215 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001216 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001217 realm = "ACME Networks"
1218 http_handler = MockHTTPHandler(
1219 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001220 opener.add_handler(auth_handler)
1221 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001222 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001223 realm, http_handler, password_manager,
1224 "http://acme.example.com:3128/protected",
1225 "proxy.example.com:3128",
1226 )
1227
1228 def test_basic_and_digest_auth_handlers(self):
1229 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1230 # response (http://python.org/sf/1479302), where it should instead
1231 # return None to allow another handler (especially
1232 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001233
1234 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1235 # try digest first (since it's the strongest auth scheme), so we record
1236 # order of calls here to check digest comes first:
1237 class RecordingOpenerDirector(OpenerDirector):
1238 def __init__(self):
1239 OpenerDirector.__init__(self)
1240 self.recorded = []
1241 def record(self, info):
1242 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001243 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001244 def http_error_401(self, *args, **kwds):
1245 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001246 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001247 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001248 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001249 def http_error_401(self, *args, **kwds):
1250 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001251 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001252 *args, **kwds)
1253
1254 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001255 password_manager = MockPasswordManager()
1256 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001257 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001258 realm = "ACME Networks"
1259 http_handler = MockHTTPHandler(
1260 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001261 opener.add_handler(basic_handler)
1262 opener.add_handler(digest_handler)
1263 opener.add_handler(http_handler)
1264
1265 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001266 self._test_basic_auth(opener, basic_handler, "Authorization",
1267 realm, http_handler, password_manager,
1268 "http://acme.example.com/protected",
1269 "http://acme.example.com/protected",
1270 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001271 # check digest was tried before basic (twice, because
1272 # _test_basic_auth called .open() twice)
1273 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001274
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001275 def test_unsupported_auth_digest_handler(self):
1276 opener = OpenerDirector()
1277 # While using DigestAuthHandler
1278 digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
1279 http_handler = MockHTTPHandler(
1280 401, 'WWW-Authenticate: Kerberos\r\n\r\n')
1281 opener.add_handler(digest_auth_handler)
1282 opener.add_handler(http_handler)
1283 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1284
1285 def test_unsupported_auth_basic_handler(self):
1286 # While using BasicAuthHandler
1287 opener = OpenerDirector()
1288 basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
1289 http_handler = MockHTTPHandler(
1290 401, 'WWW-Authenticate: NTLM\r\n\r\n')
1291 opener.add_handler(basic_auth_handler)
1292 opener.add_handler(http_handler)
1293 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1294
Thomas Wouters477c8d52006-05-27 19:21:47 +00001295 def _test_basic_auth(self, opener, auth_handler, auth_header,
1296 realm, http_handler, password_manager,
1297 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001298 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001299 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001300
1301 # .add_password() fed through to password manager
1302 auth_handler.add_password(realm, request_url, user, password)
1303 self.assertEqual(realm, password_manager.realm)
1304 self.assertEqual(request_url, password_manager.url)
1305 self.assertEqual(user, password_manager.user)
1306 self.assertEqual(password, password_manager.password)
1307
1308 r = opener.open(request_url)
1309
1310 # should have asked the password manager for the username/password
1311 self.assertEqual(password_manager.target_realm, realm)
1312 self.assertEqual(password_manager.target_url, protected_url)
1313
1314 # expect one request without authorization, then one with
1315 self.assertEqual(len(http_handler.requests), 2)
1316 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001317 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001318 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001319 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001320 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1321 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001322 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1323 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001324 # if the password manager can't find a password, the handler won't
1325 # handle the HTTP auth error
1326 password_manager.user = password_manager.password = None
1327 http_handler.reset()
1328 r = opener.open(request_url)
1329 self.assertEqual(len(http_handler.requests), 1)
1330 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1331
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001332
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001333class MiscTests(unittest.TestCase):
1334
1335 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001336 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1337 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001338 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001339 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001340 def bar_open(self): pass
1341
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001342 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001343
1344 o = build_opener(FooHandler, BarHandler)
1345 self.opener_has_handler(o, FooHandler)
1346 self.opener_has_handler(o, BarHandler)
1347
1348 # can take a mix of classes and instances
1349 o = build_opener(FooHandler, BarHandler())
1350 self.opener_has_handler(o, FooHandler)
1351 self.opener_has_handler(o, BarHandler)
1352
1353 # subclasses of default handlers override default handlers
1354 o = build_opener(MyHTTPHandler)
1355 self.opener_has_handler(o, MyHTTPHandler)
1356
1357 # a particular case of overriding: default handlers can be passed
1358 # in explicitly
1359 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001360 self.opener_has_handler(o, urllib.request.HTTPHandler)
1361 o = build_opener(urllib.request.HTTPHandler)
1362 self.opener_has_handler(o, urllib.request.HTTPHandler)
1363 o = build_opener(urllib.request.HTTPHandler())
1364 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001365
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001366 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001367 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001368 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1369 self.opener_has_handler(o, MyHTTPHandler)
1370 self.opener_has_handler(o, MyOtherHTTPHandler)
1371
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001372 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001373 self.assertTrue(any(h.__class__ == handler_class
1374 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001375
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001376class RequestTests(unittest.TestCase):
1377
1378 def setUp(self):
1379 self.get = Request("http://www.python.org/~jeremy/")
1380 self.post = Request("http://www.python.org/~jeremy/",
1381 "data",
1382 headers={"X-Test": "test"})
1383
1384 def test_method(self):
1385 self.assertEqual("POST", self.post.get_method())
1386 self.assertEqual("GET", self.get.get_method())
1387
1388 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001389 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001390 self.assertEqual("GET", self.get.get_method())
1391 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001392 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001393 self.assertEqual("POST", self.get.get_method())
1394
1395 def test_get_full_url(self):
1396 self.assertEqual("http://www.python.org/~jeremy/",
1397 self.get.get_full_url())
1398
1399 def test_selector(self):
1400 self.assertEqual("/~jeremy/", self.get.get_selector())
1401 req = Request("http://www.python.org/")
1402 self.assertEqual("/", req.get_selector())
1403
1404 def test_get_type(self):
1405 self.assertEqual("http", self.get.get_type())
1406
1407 def test_get_host(self):
1408 self.assertEqual("www.python.org", self.get.get_host())
1409
1410 def test_get_host_unquote(self):
1411 req = Request("http://www.%70ython.org/")
1412 self.assertEqual("www.python.org", req.get_host())
1413
1414 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001415 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001416 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001417 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001418 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1419 self.assertEqual("www.perl.org", self.get.get_host())
1420
Senthil Kumarand95cc752010-08-08 11:27:53 +00001421 def test_wrapped_url(self):
1422 req = Request("<URL:http://www.python.org>")
1423 self.assertEqual("www.python.org", req.get_host())
1424
Senthil Kumaran26430412011-04-13 07:01:19 +08001425 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001426 req = Request("http://www.python.org/?qs=query#fragment=true")
1427 self.assertEqual("/?qs=query", req.get_selector())
1428 req = Request("http://www.python.org/#fun=true")
1429 self.assertEqual("/", req.get_selector())
1430
Senthil Kumaran26430412011-04-13 07:01:19 +08001431 # Issue 11703: geturl() omits fragment in the original URL.
1432 url = 'http://docs.python.org/library/urllib2.html#OK'
1433 req = Request(url)
1434 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001435
1436def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001437 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001438 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001439 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001440 tests = (TrivialTests,
1441 OpenerDirectorTests,
1442 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001443 MiscTests,
1444 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001445 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001446
1447if __name__ == "__main__":
1448 test_main(verbose=True)