blob: b6e4e919e4cb21b384ed7d8a1dce6830c4969c8f [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
Jeremy Hyltone3e61042001-05-09 15:50:25 +00008
Jeremy Hylton1afc1692008-06-18 20:49:58 +00009import urllib.request
Ronald Oussorene72e1612011-03-14 18:15:25 -040010# The proxy bypass method imported below has logic specific to the OSX
11# proxy config data structure but is testable on all platforms.
12from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
guido@google.coma119df92011-03-29 11:41:02 -070013import urllib.error
Jeremy Hyltone3e61042001-05-09 15:50:25 +000014
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000015# XXX
16# Request
17# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000018# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000019
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000020class TrivialTests(unittest.TestCase):
21 def test_trivial(self):
22 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000023
Jeremy Hylton1afc1692008-06-18 20:49:58 +000024 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000025
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000026 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000027 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000028
Senthil Kumarand587e302010-01-10 17:45:52 +000029 if os.name == 'nt':
30 file_url = "file:///%s" % fname
31 else:
32 file_url = "file://%s" % fname
33
Jeremy Hylton1afc1692008-06-18 20:49:58 +000034 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000035
36 buf = f.read()
37 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000038
Georg Brandle1b13d22005-08-24 22:20:32 +000039 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000040 tests = [
41 ('a,b,c', ['a', 'b', 'c']),
42 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
43 ('a, b, "c", "d", "e,f", g, h',
44 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
45 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
46 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000047 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000048 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000049
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000050
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000051def test_request_headers_dict():
52 """
53 The Request.headers dictionary is not a documented interface. It should
54 stay that way, because the complete set of headers are only accessible
55 through the .get_header(), .has_header(), .header_items() interface.
56 However, .headers pre-dates those methods, and so real code will be using
57 the dictionary.
58
59 The introduction in 2.4 of those methods was a mistake for the same reason:
60 code that previously saw all (urllib2 user)-provided headers in .headers
61 now sees only a subset (and the function interface is ugly and incomplete).
62 A better change would have been to replace .headers dict with a dict
63 subclass (or UserDict.DictMixin instance?) that preserved the .headers
64 interface and also provided access to the "unredirected" headers. It's
65 probably too late to fix that, though.
66
67
68 Check .capitalize() case normalization:
69
70 >>> url = "http://example.com"
71 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
72 'blah'
73 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
74 'blah'
75
76 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
77 but that could be changed in future.
78
79 """
80
81def test_request_headers_methods():
82 """
83 Note the case normalization of header names here, to .capitalize()-case.
84 This should be preserved for backwards-compatibility. (In the HTTP case,
85 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000086 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000087
88 >>> url = "http://example.com"
89 >>> r = Request(url, headers={"Spam-eggs": "blah"})
90 >>> r.has_header("Spam-eggs")
91 True
92 >>> r.header_items()
93 [('Spam-eggs', 'blah')]
94 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000095 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000096 >>> items
97 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
98
99 Note that e.g. r.has_header("spam-EggS") is currently False, and
100 r.get_header("spam-EggS") returns None, but that could be changed in
101 future.
102
103 >>> r.has_header("Not-there")
104 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000105 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000106 None
107 >>> r.get_header("Not-there", "default")
108 'default'
109
110 """
111
112
Thomas Wouters477c8d52006-05-27 19:21:47 +0000113def test_password_manager(self):
114 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000115 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000116 >>> add = mgr.add_password
117 >>> add("Some Realm", "http://example.com/", "joe", "password")
118 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
119 >>> add("c", "http://example.com/foo", "foo", "ni")
120 >>> add("c", "http://example.com/bar", "bar", "nini")
121 >>> add("b", "http://example.com/", "first", "blah")
122 >>> add("b", "http://example.com/", "second", "spam")
123 >>> add("a", "http://example.com", "1", "a")
124 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
125 >>> add("Some Realm", "d.example.com", "4", "d")
126 >>> add("Some Realm", "e.example.com:3128", "5", "e")
127
128 >>> mgr.find_user_password("Some Realm", "example.com")
129 ('joe', 'password')
130 >>> mgr.find_user_password("Some Realm", "http://example.com")
131 ('joe', 'password')
132 >>> mgr.find_user_password("Some Realm", "http://example.com/")
133 ('joe', 'password')
134 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
135 ('joe', 'password')
136 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
137 ('joe', 'password')
138 >>> mgr.find_user_password("c", "http://example.com/foo")
139 ('foo', 'ni')
140 >>> mgr.find_user_password("c", "http://example.com/bar")
141 ('bar', 'nini')
142
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000143 Actually, this is really undefined ATM
144## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000145
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000146## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
147## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000148
149 Use latest add_password() in case of conflict:
150
151 >>> mgr.find_user_password("b", "http://example.com/")
152 ('second', 'spam')
153
154 No special relationship between a.example.com and example.com:
155
156 >>> mgr.find_user_password("a", "http://example.com/")
157 ('1', 'a')
158 >>> mgr.find_user_password("a", "http://a.example.com/")
159 (None, None)
160
161 Ports:
162
163 >>> mgr.find_user_password("Some Realm", "c.example.com")
164 (None, None)
165 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
166 ('3', 'c')
167 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
168 ('3', 'c')
169 >>> mgr.find_user_password("Some Realm", "d.example.com")
170 ('4', 'd')
171 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
172 ('5', 'e')
173
174 """
175 pass
176
177
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000178def test_password_manager_default_port(self):
179 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000180 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000181 >>> add = mgr.add_password
182
183 The point to note here is that we can't guess the default port if there's
184 no scheme. This applies to both add_password and find_user_password.
185
186 >>> add("f", "http://g.example.com:80", "10", "j")
187 >>> add("g", "http://h.example.com", "11", "k")
188 >>> add("h", "i.example.com:80", "12", "l")
189 >>> add("i", "j.example.com", "13", "m")
190 >>> mgr.find_user_password("f", "g.example.com:100")
191 (None, None)
192 >>> mgr.find_user_password("f", "g.example.com:80")
193 ('10', 'j')
194 >>> mgr.find_user_password("f", "g.example.com")
195 (None, None)
196 >>> mgr.find_user_password("f", "http://g.example.com:100")
197 (None, None)
198 >>> mgr.find_user_password("f", "http://g.example.com:80")
199 ('10', 'j')
200 >>> mgr.find_user_password("f", "http://g.example.com")
201 ('10', 'j')
202 >>> mgr.find_user_password("g", "h.example.com")
203 ('11', 'k')
204 >>> mgr.find_user_password("g", "h.example.com:80")
205 ('11', 'k')
206 >>> mgr.find_user_password("g", "http://h.example.com:80")
207 ('11', 'k')
208 >>> mgr.find_user_password("h", "i.example.com")
209 (None, None)
210 >>> mgr.find_user_password("h", "i.example.com:80")
211 ('12', 'l')
212 >>> mgr.find_user_password("h", "http://i.example.com:80")
213 ('12', 'l')
214 >>> mgr.find_user_password("i", "j.example.com")
215 ('13', 'm')
216 >>> mgr.find_user_password("i", "j.example.com:80")
217 (None, None)
218 >>> mgr.find_user_password("i", "http://j.example.com")
219 ('13', 'm')
220 >>> mgr.find_user_password("i", "http://j.example.com:80")
221 (None, None)
222
223 """
224
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000225class MockOpener:
226 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000227 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
228 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000229 def error(self, proto, *args):
230 self.proto, self.args = proto, args
231
232class MockFile:
233 def read(self, count=None): pass
234 def readline(self, count=None): pass
235 def close(self): pass
236
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000237class MockHeaders(dict):
238 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000239 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000240
Guido van Rossum34d19282007-08-09 01:03:29 +0000241class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000242 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000243 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000244 self.code, self.msg, self.headers, self.url = code, msg, headers, url
245 def info(self):
246 return self.headers
247 def geturl(self):
248 return self.url
249
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000250class MockCookieJar:
251 def add_cookie_header(self, request):
252 self.ach_req = request
253 def extract_cookies(self, response, request):
254 self.ec_req, self.ec_r = request, response
255
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000256class FakeMethod:
257 def __init__(self, meth_name, action, handle):
258 self.meth_name = meth_name
259 self.handle = handle
260 self.action = action
261 def __call__(self, *args):
262 return self.handle(self.meth_name, self.action, *args)
263
Senthil Kumaran47fff872009-12-20 07:10:31 +0000264class MockHTTPResponse(io.IOBase):
265 def __init__(self, fp, msg, status, reason):
266 self.fp = fp
267 self.msg = msg
268 self.status = status
269 self.reason = reason
270 self.code = 200
271
272 def read(self):
273 return ''
274
275 def info(self):
276 return {}
277
278 def geturl(self):
279 return self.url
280
281
282class MockHTTPClass:
283 def __init__(self):
284 self.level = 0
285 self.req_headers = []
286 self.data = None
287 self.raise_on_endheaders = False
288 self._tunnel_headers = {}
289
290 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
291 self.host = host
292 self.timeout = timeout
293 return self
294
295 def set_debuglevel(self, level):
296 self.level = level
297
298 def set_tunnel(self, host, port=None, headers=None):
299 self._tunnel_host = host
300 self._tunnel_port = port
301 if headers:
302 self._tunnel_headers = headers
303 else:
304 self._tunnel_headers.clear()
305
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000306 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000307 self.method = method
308 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000309 if headers is not None:
310 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000311 self.req_headers.sort()
312 if body:
313 self.data = body
314 if self.raise_on_endheaders:
315 import socket
316 raise socket.error()
317 def getresponse(self):
318 return MockHTTPResponse(MockFile(), {}, 200, "OK")
319
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000320class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000321 # useful for testing handler machinery
322 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000323 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000324 def __init__(self, methods):
325 self._define_methods(methods)
326 def _define_methods(self, methods):
327 for spec in methods:
328 if len(spec) == 2: name, action = spec
329 else: name, action = spec, None
330 meth = FakeMethod(name, action, self.handle)
331 setattr(self.__class__, name, meth)
332 def handle(self, fn_name, action, *args, **kwds):
333 self.parent.calls.append((self, fn_name, args, kwds))
334 if action is None:
335 return None
336 elif action == "return self":
337 return self
338 elif action == "return response":
339 res = MockResponse(200, "OK", {}, "")
340 return res
341 elif action == "return request":
342 return Request("http://blah/")
343 elif action.startswith("error"):
344 code = action[action.rfind(" ")+1:]
345 try:
346 code = int(code)
347 except ValueError:
348 pass
349 res = MockResponse(200, "OK", {}, "")
350 return self.parent.error("http", args[0], res, code, "", {})
351 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000352 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000353 assert False
354 def close(self): pass
355 def add_parent(self, parent):
356 self.parent = parent
357 self.parent.calls = []
358 def __lt__(self, other):
359 if not hasattr(other, "handler_order"):
360 # No handler_order, leave in original order. Yuck.
361 return True
362 return self.handler_order < other.handler_order
363
364def add_ordered_mock_handlers(opener, meth_spec):
365 """Create MockHandlers and add them to an OpenerDirector.
366
367 meth_spec: list of lists of tuples and strings defining methods to define
368 on handlers. eg:
369
370 [["http_error", "ftp_open"], ["http_open"]]
371
372 defines methods .http_error() and .ftp_open() on one handler, and
373 .http_open() on another. These methods just record their arguments and
374 return None. Using a tuple instead of a string causes the method to
375 perform some action (see MockHandler.handle()), eg:
376
377 [["http_error"], [("http_open", "return request")]]
378
379 defines .http_error() on one handler (which simply returns None), and
380 .http_open() on another handler, which returns a Request object.
381
382 """
383 handlers = []
384 count = 0
385 for meths in meth_spec:
386 class MockHandlerSubclass(MockHandler): pass
387 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000388 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000389 h.add_parent(opener)
390 count = count + 1
391 handlers.append(h)
392 opener.add_handler(h)
393 return handlers
394
Thomas Wouters477c8d52006-05-27 19:21:47 +0000395def build_test_opener(*handler_instances):
396 opener = OpenerDirector()
397 for h in handler_instances:
398 opener.add_handler(h)
399 return opener
400
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000401class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000402 # useful for testing redirections and auth
403 # sends supplied headers and code as first response
404 # sends 200 OK as second response
405 def __init__(self, code, headers):
406 self.code = code
407 self.headers = headers
408 self.reset()
409 def reset(self):
410 self._count = 0
411 self.requests = []
412 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000413 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000414 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000415 self.requests.append(copy.deepcopy(req))
416 if self._count == 0:
417 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000418 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000419 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000420 return self.parent.error(
421 "http", req, MockFile(), self.code, name, msg)
422 else:
423 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000424 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000425 return MockResponse(200, "OK", msg, "", req.get_full_url())
426
Senthil Kumaran47fff872009-12-20 07:10:31 +0000427class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
428 # Useful for testing the Proxy-Authorization request by verifying the
429 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000430
431 def __init__(self):
432 urllib.request.AbstractHTTPHandler.__init__(self)
433 self.httpconn = MockHTTPClass()
434
Senthil Kumaran47fff872009-12-20 07:10:31 +0000435 def https_open(self, req):
436 return self.do_open(self.httpconn, req)
437
Thomas Wouters477c8d52006-05-27 19:21:47 +0000438class MockPasswordManager:
439 def add_password(self, realm, uri, user, password):
440 self.realm = realm
441 self.url = uri
442 self.user = user
443 self.password = password
444 def find_user_password(self, realm, authuri):
445 self.target_realm = realm
446 self.target_url = authuri
447 return self.user, self.password
448
449
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000450class OpenerDirectorTests(unittest.TestCase):
451
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000452 def test_add_non_handler(self):
453 class NonHandler(object):
454 pass
455 self.assertRaises(TypeError,
456 OpenerDirector().add_handler, NonHandler())
457
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000458 def test_badly_named_methods(self):
459 # test work-around for three methods that accidentally follow the
460 # naming conventions for handler methods
461 # (*_open() / *_request() / *_response())
462
463 # These used to call the accidentally-named methods, causing a
464 # TypeError in real code; here, returning self from these mock
465 # methods would either cause no exception, or AttributeError.
466
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000467 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000468
469 o = OpenerDirector()
470 meth_spec = [
471 [("do_open", "return self"), ("proxy_open", "return self")],
472 [("redirect_request", "return self")],
473 ]
474 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000475 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000476 for scheme in "do", "proxy", "redirect":
477 self.assertRaises(URLError, o.open, scheme+"://example.com/")
478
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000479 def test_handled(self):
480 # handler returning non-None means no more handlers will be called
481 o = OpenerDirector()
482 meth_spec = [
483 ["http_open", "ftp_open", "http_error_302"],
484 ["ftp_open"],
485 [("http_open", "return self")],
486 [("http_open", "return self")],
487 ]
488 handlers = add_ordered_mock_handlers(o, meth_spec)
489
490 req = Request("http://example.com/")
491 r = o.open(req)
492 # Second .http_open() gets called, third doesn't, since second returned
493 # non-None. Handlers without .http_open() never get any methods called
494 # on them.
495 # In fact, second mock handler defining .http_open() returns self
496 # (instead of response), which becomes the OpenerDirector's return
497 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000498 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000499 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
500 for expected, got in zip(calls, o.calls):
501 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000502 self.assertEqual((handler, name), expected)
503 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000504
505 def test_handler_order(self):
506 o = OpenerDirector()
507 handlers = []
508 for meths, handler_order in [
509 ([("http_open", "return self")], 500),
510 (["http_open"], 0),
511 ]:
512 class MockHandlerSubclass(MockHandler): pass
513 h = MockHandlerSubclass(meths)
514 h.handler_order = handler_order
515 handlers.append(h)
516 o.add_handler(h)
517
518 r = o.open("http://example.com/")
519 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000520 self.assertEqual(o.calls[0][0], handlers[1])
521 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000522
523 def test_raise(self):
524 # raising URLError stops processing of request
525 o = OpenerDirector()
526 meth_spec = [
527 [("http_open", "raise")],
528 [("http_open", "return self")],
529 ]
530 handlers = add_ordered_mock_handlers(o, meth_spec)
531
532 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000533 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000534 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000535
536## def test_error(self):
537## # XXX this doesn't actually seem to be used in standard library,
538## # but should really be tested anyway...
539
540 def test_http_error(self):
541 # XXX http_error_default
542 # http errors are a special case
543 o = OpenerDirector()
544 meth_spec = [
545 [("http_open", "error 302")],
546 [("http_error_400", "raise"), "http_open"],
547 [("http_error_302", "return response"), "http_error_303",
548 "http_error"],
549 [("http_error_302")],
550 ]
551 handlers = add_ordered_mock_handlers(o, meth_spec)
552
553 class Unknown:
554 def __eq__(self, other): return True
555
556 req = Request("http://example.com/")
557 r = o.open(req)
558 assert len(o.calls) == 2
559 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000560 (handlers[2], "http_error_302",
561 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000562 for expected, got in zip(calls, o.calls):
563 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000564 self.assertEqual((handler, method_name), got[:2])
565 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000566
567 def test_processors(self):
568 # *_request / *_response methods get called appropriately
569 o = OpenerDirector()
570 meth_spec = [
571 [("http_request", "return request"),
572 ("http_response", "return response")],
573 [("http_request", "return request"),
574 ("http_response", "return response")],
575 ]
576 handlers = add_ordered_mock_handlers(o, meth_spec)
577
578 req = Request("http://example.com/")
579 r = o.open(req)
580 # processor methods are called on *all* handlers that define them,
581 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000582 calls = [
583 (handlers[0], "http_request"), (handlers[1], "http_request"),
584 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000585
586 for i, (handler, name, args, kwds) in enumerate(o.calls):
587 if i < 2:
588 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000589 self.assertEqual((handler, name), calls[i])
590 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000591 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000592 else:
593 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000594 self.assertEqual((handler, name), calls[i])
595 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000596 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000597 # response from opener.open is None, because there's no
598 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000599 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000600 isinstance(args[1], MockResponse))
601
602
Tim Peters58eb11c2004-01-18 20:29:55 +0000603def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000604 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000605 path.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000606 except UnicodeEncodeError:
607 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000608 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000609 if os.name == "nt" and urlpath.startswith("///"):
610 urlpath = urlpath[2:]
611 # XXX don't ask me about the mac...
612 return urlpath
613
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000614class HandlerTests(unittest.TestCase):
615
616 def test_ftp(self):
617 class MockFTPWrapper:
618 def __init__(self, data): self.data = data
619 def retrfile(self, filename, filetype):
620 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000621 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000622
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000623 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000624 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000625 def connect_ftp(self, user, passwd, host, port, dirs,
626 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000627 self.user, self.passwd = user, passwd
628 self.host, self.port = host, port
629 self.dirs = dirs
630 self.ftpwrapper = MockFTPWrapper(self.data)
631 return self.ftpwrapper
632
Georg Brandlf78e02b2008-06-10 17:40:04 +0000633 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000634 data = "rheum rhaponicum"
635 h = NullFTPHandler(data)
636 o = h.parent = MockOpener()
637
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000638 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000639 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000640 "localhost", ftplib.FTP_PORT, "", "", "I",
641 ["foo", "bar"], "baz.html", "text/html"),
642 ("ftp://parrot@localhost/foo/bar/baz.html",
643 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
644 ["foo", "bar"], "baz.html", "text/html"),
645 ("ftp://%25parrot@localhost/foo/bar/baz.html",
646 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
647 ["foo", "bar"], "baz.html", "text/html"),
648 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
649 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000650 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000651 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000652 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000653 ["foo", "bar"], "", None),
654 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000655 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000656 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000657 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000658 req = Request(url)
659 req.timeout = None
660 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000661 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000662 self.assertEqual(h.user, user)
663 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000664 self.assertEqual(h.host, socket.gethostbyname(host))
665 self.assertEqual(h.port, port)
666 self.assertEqual(h.dirs, dirs)
667 self.assertEqual(h.ftpwrapper.filename, filename)
668 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000669 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000670 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000671 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000672
673 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000674 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000675 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000676 o = h.parent = MockOpener()
677
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000678 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000679 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000680 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000681 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000682 "file://localhost%s" % urlpath,
683 "file://%s" % urlpath,
684 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000685 ]
686 try:
687 localaddr = socket.gethostbyname(socket.gethostname())
688 except socket.gaierror:
689 localaddr = ''
690 if localaddr:
691 urls.append("file://%s%s" % (localaddr, urlpath))
692
693 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000694 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000695 try:
696 try:
697 f.write(towrite)
698 finally:
699 f.close()
700
701 r = h.file_open(Request(url))
702 try:
703 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000704 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000705 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000706 finally:
707 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000708 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000709 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000710 finally:
711 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000712 self.assertEqual(data, towrite)
713 self.assertEqual(headers["Content-type"], "text/plain")
714 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000715 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000716 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000717
718 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000719 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000720 "file:///file_does_not_exist.txt",
721 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
722 os.getcwd(), TESTFN),
723 "file://somerandomhost.ontheinternet.com%s/%s" %
724 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000725 ]:
726 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000727 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000728 try:
729 f.write(towrite)
730 finally:
731 f.close()
732
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000733 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000734 h.file_open, Request(url))
735 finally:
736 os.remove(TESTFN)
737
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000738 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000739 o = h.parent = MockOpener()
740 # XXXX why does // mean ftp (and /// mean not ftp!), and where
741 # is file: scheme specified? I think this is really a bug, and
742 # what was intended was to distinguish between URLs like:
743 # file:/blah.txt (a file)
744 # file://localhost/blah.txt (a file)
745 # file:///blah.txt (a file)
746 # file://ftp.example.com/blah.txt (an ftp URL)
747 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000748 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000749 ("file://ftp.example.com///foo.txt", False),
750# XXXX bug: fails with OSError, should be URLError
751 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000752 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000753 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000754 ]:
755 req = Request(url)
756 try:
757 h.file_open(req)
758 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000759 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000760 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000761 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000762 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000763 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000764 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000765
766 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000767
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000768 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000769 o = h.parent = MockOpener()
770
771 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000772 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000773 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000774 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000775 req.add_unredirected_header("Spam", "eggs")
776 http = MockHTTPClass()
777 r = h.do_open(http, req)
778
779 # result attributes
780 r.read; r.readline # wrapped MockFile methods
781 r.info; r.geturl # addinfourl methods
782 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
783 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000784 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000785 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000786
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000787 self.assertEqual(http.host, "example.com")
788 self.assertEqual(http.level, 0)
789 self.assertEqual(http.method, method)
790 self.assertEqual(http.selector, "/")
791 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000792 [("Connection", "close"),
793 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000794 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000795
796 # check socket.error converted to URLError
797 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000798 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000799
Senthil Kumaran29333122011-02-11 11:25:47 +0000800 # Check for TypeError on POST data which is str.
801 req = Request("http://example.com/","badpost")
802 self.assertRaises(TypeError, h.do_request_, req)
803
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000804 # check adding of standard headers
805 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000806 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000807 req = Request("http://example.com/", data)
808 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000809 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000810 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000811 self.assertNotIn("Content-length", req.unredirected_hdrs)
812 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000813 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000814 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
815 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000816 "application/x-www-form-urlencoded")
817 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000818 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
819 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000820
821 # don't clobber existing headers
822 req.add_unredirected_header("Content-length", "foo")
823 req.add_unredirected_header("Content-type", "bar")
824 req.add_unredirected_header("Host", "baz")
825 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000826 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000827 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
828 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000829 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
830 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000831
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000832 # Check iterable body support
833 def iterable_body():
834 yield b"one"
835 yield b"two"
836 yield b"three"
837
838 for headers in {}, {"Content-Length": 11}:
839 req = Request("http://example.com/", iterable_body(), headers)
840 if not headers:
841 # Having an iterable body without a Content-Length should
842 # raise an exception
843 self.assertRaises(ValueError, h.do_request_, req)
844 else:
845 newreq = h.do_request_(req)
846
Senthil Kumaran29333122011-02-11 11:25:47 +0000847 # A file object.
848 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000849
Senthil Kumaran29333122011-02-11 11:25:47 +0000850 file_obj = io.BytesIO()
851 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000852
853 for headers in {}, {"Content-Length": 30}:
854 req = Request("http://example.com/", file_obj, headers)
855 if not headers:
856 # Having an iterable body without a Content-Length should
857 # raise an exception
858 self.assertRaises(ValueError, h.do_request_, req)
859 else:
860 newreq = h.do_request_(req)
861 self.assertEqual(int(newreq.get_header('Content-length')),30)
862
863 file_obj.close()
864
865 # array.array Iterable - Content Length is calculated
866
867 iterable_array = array.array("I",[1,2,3,4])
868
869 for headers in {}, {"Content-Length": 16}:
870 req = Request("http://example.com/", iterable_array, headers)
871 newreq = h.do_request_(req)
872 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000873
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000874 def test_http_doubleslash(self):
875 # Checks the presence of any unnecessary double slash in url does not
876 # break anything. Previously, a double slash directly after the host
877 # could could cause incorrect parsing.
878 h = urllib.request.AbstractHTTPHandler()
879 o = h.parent = MockOpener()
880
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000881 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000882 ds_urls = [
883 "http://example.com/foo/bar/baz.html",
884 "http://example.com//foo/bar/baz.html",
885 "http://example.com/foo//bar/baz.html",
886 "http://example.com/foo/bar//baz.html"
887 ]
888
889 for ds_url in ds_urls:
890 ds_req = Request(ds_url, data)
891
892 # Check whether host is determined correctly if there is no proxy
893 np_ds_req = h.do_request_(ds_req)
894 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
895
896 # Check whether host is determined correctly if there is a proxy
897 ds_req.set_proxy("someproxy:3128",None)
898 p_ds_req = h.do_request_(ds_req)
899 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
900
Senthil Kumaranc2958622010-11-22 04:48:26 +0000901 def test_fixpath_in_weirdurls(self):
902 # Issue4493: urllib2 to supply '/' when to urls where path does not
903 # start with'/'
904
905 h = urllib.request.AbstractHTTPHandler()
906 o = h.parent = MockOpener()
907
908 weird_url = 'http://www.python.org?getspam'
909 req = Request(weird_url)
910 newreq = h.do_request_(req)
911 self.assertEqual(newreq.host,'www.python.org')
912 self.assertEqual(newreq.selector,'/?getspam')
913
914 url_without_path = 'http://www.python.org'
915 req = Request(url_without_path)
916 newreq = h.do_request_(req)
917 self.assertEqual(newreq.host,'www.python.org')
918 self.assertEqual(newreq.selector,'')
919
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000920
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000921 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000922 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000923 o = h.parent = MockOpener()
924
925 url = "http://example.com/"
926 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000927 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000928 r = MockResponse(200, "OK", {}, "", url)
929 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000930 self.assertIs(r, newr)
931 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000932 r = MockResponse(202, "Accepted", {}, "", 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(206, "Partial content", {}, "", 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
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000940 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000942 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000943 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000944 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000945
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000946 def test_cookies(self):
947 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000948 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000949 o = h.parent = MockOpener()
950
951 req = Request("http://example.com/")
952 r = MockResponse(200, "OK", {}, "")
953 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000954 self.assertIs(cj.ach_req, req)
955 self.assertIs(cj.ach_req, newreq)
956 self.assertEqual(req.get_origin_req_host(), "example.com")
957 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000958 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000959 self.assertIs(cj.ec_req, req)
960 self.assertIs(cj.ec_r, r)
961 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000962
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000963 def test_redirect(self):
964 from_url = "http://example.com/a.html"
965 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000966 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000967 o = h.parent = MockOpener()
968
969 # ordinary redirect behaviour
970 for code in 301, 302, 303, 307:
971 for data in None, "blah\nblah\n":
972 method = getattr(h, "http_error_%s" % code)
973 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000974 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000975 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000976 if data is not None:
977 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000978 req.add_unredirected_header("Spam", "spam")
979 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000980 method(req, MockFile(), code, "Blah",
981 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000982 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000983 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000984 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000985 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000986 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000987 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000988 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000989 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000990
991 # now it's a GET, there should not be headers regarding content
992 # (possibly dragged from before being a POST)
993 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000994 self.assertNotIn("content-length", headers)
995 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +0000996
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000997 self.assertEqual(o.req.headers["Nonsense"],
998 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +0000999 self.assertNotIn("Spam", o.req.headers)
1000 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001001
1002 # loop detection
1003 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001004 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001005 def redirect(h, req, url=to_url):
1006 h.http_error_302(req, MockFile(), 302, "Blah",
1007 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001008 # Note that the *original* request shares the same record of
1009 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001010
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001011 # detect infinite loop redirect of a URL to itself
1012 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001013 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001014 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001015 try:
1016 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001017 redirect(h, req, "http://example.com/")
1018 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001019 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001020 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001021 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001022
1023 # detect endless non-repeating chain of redirects
1024 req = Request(from_url, origin_req_host="example.com")
1025 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001026 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001027 try:
1028 while 1:
1029 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001030 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001031 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001032 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001033 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001034
guido@google.coma119df92011-03-29 11:41:02 -07001035
1036 def test_invalid_redirect(self):
1037 from_url = "http://example.com/a.html"
1038 valid_schemes = ['http','https','ftp']
1039 invalid_schemes = ['file','imap','ldap']
1040 schemeless_url = "example.com/b.html"
1041 h = urllib.request.HTTPRedirectHandler()
1042 o = h.parent = MockOpener()
1043 req = Request(from_url)
1044 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1045
1046 for scheme in invalid_schemes:
1047 invalid_url = scheme + '://' + schemeless_url
1048 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1049 req, MockFile(), 302, "Security Loophole",
1050 MockHeaders({"location": invalid_url}))
1051
1052 for scheme in valid_schemes:
1053 valid_url = scheme + '://' + schemeless_url
1054 h.http_error_302(req, MockFile(), 302, "That's fine",
1055 MockHeaders({"location": valid_url}))
1056 self.assertEqual(o.req.get_full_url(), valid_url)
1057
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001058 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001059 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001060 from http.cookiejar import CookieJar
1061 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001062
1063 cj = CookieJar()
1064 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001065 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001066 hdeh = urllib.request.HTTPDefaultErrorHandler()
1067 hrh = urllib.request.HTTPRedirectHandler()
1068 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001069 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001070 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001071 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001072
Senthil Kumaran26430412011-04-13 07:01:19 +08001073 def test_redirect_fragment(self):
1074 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1075 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1076 hdeh = urllib.request.HTTPDefaultErrorHandler()
1077 hrh = urllib.request.HTTPRedirectHandler()
1078 o = build_test_opener(hh, hdeh, hrh)
1079 fp = o.open('http://www.example.com')
1080 self.assertEqual(fp.geturl(), redirected_url.strip())
1081
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001082 def test_proxy(self):
1083 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001084 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001085 o.add_handler(ph)
1086 meth_spec = [
1087 [("http_open", "return response")]
1088 ]
1089 handlers = add_ordered_mock_handlers(o, meth_spec)
1090
1091 req = Request("http://acme.example.com/")
1092 self.assertEqual(req.get_host(), "acme.example.com")
1093 r = o.open(req)
1094 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1095
1096 self.assertEqual([(handlers[0], "http_open")],
1097 [tup[0:2] for tup in o.calls])
1098
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001099 def test_proxy_no_proxy(self):
1100 os.environ['no_proxy'] = 'python.org'
1101 o = OpenerDirector()
1102 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1103 o.add_handler(ph)
1104 req = Request("http://www.perl.org/")
1105 self.assertEqual(req.get_host(), "www.perl.org")
1106 r = o.open(req)
1107 self.assertEqual(req.get_host(), "proxy.example.com")
1108 req = Request("http://www.python.org")
1109 self.assertEqual(req.get_host(), "www.python.org")
1110 r = o.open(req)
1111 self.assertEqual(req.get_host(), "www.python.org")
1112 del os.environ['no_proxy']
1113
Ronald Oussorene72e1612011-03-14 18:15:25 -04001114 def test_proxy_no_proxy_all(self):
1115 os.environ['no_proxy'] = '*'
1116 o = OpenerDirector()
1117 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1118 o.add_handler(ph)
1119 req = Request("http://www.python.org")
1120 self.assertEqual(req.get_host(), "www.python.org")
1121 r = o.open(req)
1122 self.assertEqual(req.get_host(), "www.python.org")
1123 del os.environ['no_proxy']
1124
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001125
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001126 def test_proxy_https(self):
1127 o = OpenerDirector()
1128 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1129 o.add_handler(ph)
1130 meth_spec = [
1131 [("https_open", "return response")]
1132 ]
1133 handlers = add_ordered_mock_handlers(o, meth_spec)
1134
1135 req = Request("https://www.example.com/")
1136 self.assertEqual(req.get_host(), "www.example.com")
1137 r = o.open(req)
1138 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1139 self.assertEqual([(handlers[0], "https_open")],
1140 [tup[0:2] for tup in o.calls])
1141
Senthil Kumaran47fff872009-12-20 07:10:31 +00001142 def test_proxy_https_proxy_authorization(self):
1143 o = OpenerDirector()
1144 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1145 o.add_handler(ph)
1146 https_handler = MockHTTPSHandler()
1147 o.add_handler(https_handler)
1148 req = Request("https://www.example.com/")
1149 req.add_header("Proxy-Authorization","FooBar")
1150 req.add_header("User-Agent","Grail")
1151 self.assertEqual(req.get_host(), "www.example.com")
1152 self.assertIsNone(req._tunnel_host)
1153 r = o.open(req)
1154 # Verify Proxy-Authorization gets tunneled to request.
1155 # httpsconn req_headers do not have the Proxy-Authorization header but
1156 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001157 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001158 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001159 self.assertIn(("User-Agent","Grail"),
1160 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001161 self.assertIsNotNone(req._tunnel_host)
1162 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1163 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001164
Ronald Oussorene72e1612011-03-14 18:15:25 -04001165 def test_osx_proxy_bypass(self):
1166 bypass = {
1167 'exclude_simple': False,
1168 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1169 '10.0/16']
1170 }
1171 # Check hosts that should trigger the proxy bypass
1172 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1173 '10.0.0.1'):
1174 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1175 'expected bypass of %s to be True' % host)
1176 # Check hosts that should not trigger the proxy bypass
1177 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1178 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1179 'expected bypass of %s to be False' % host)
1180
1181 # Check the exclude_simple flag
1182 bypass = {'exclude_simple': True, 'exceptions': []}
1183 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1184
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001185 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001186 opener = OpenerDirector()
1187 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001188 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001189 realm = "ACME Widget Store"
1190 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001191 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1192 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001193 opener.add_handler(auth_handler)
1194 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001195 self._test_basic_auth(opener, auth_handler, "Authorization",
1196 realm, http_handler, password_manager,
1197 "http://acme.example.com/protected",
1198 "http://acme.example.com/protected",
1199 )
1200
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001201 def test_basic_auth_with_single_quoted_realm(self):
1202 self.test_basic_auth(quote_char="'")
1203
Thomas Wouters477c8d52006-05-27 19:21:47 +00001204 def test_proxy_basic_auth(self):
1205 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001206 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001207 opener.add_handler(ph)
1208 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001209 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001210 realm = "ACME Networks"
1211 http_handler = MockHTTPHandler(
1212 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001213 opener.add_handler(auth_handler)
1214 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001215 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001216 realm, http_handler, password_manager,
1217 "http://acme.example.com:3128/protected",
1218 "proxy.example.com:3128",
1219 )
1220
1221 def test_basic_and_digest_auth_handlers(self):
1222 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1223 # response (http://python.org/sf/1479302), where it should instead
1224 # return None to allow another handler (especially
1225 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001226
1227 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1228 # try digest first (since it's the strongest auth scheme), so we record
1229 # order of calls here to check digest comes first:
1230 class RecordingOpenerDirector(OpenerDirector):
1231 def __init__(self):
1232 OpenerDirector.__init__(self)
1233 self.recorded = []
1234 def record(self, info):
1235 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001236 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001237 def http_error_401(self, *args, **kwds):
1238 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001239 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001240 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001241 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001242 def http_error_401(self, *args, **kwds):
1243 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001244 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001245 *args, **kwds)
1246
1247 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001248 password_manager = MockPasswordManager()
1249 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001250 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001251 realm = "ACME Networks"
1252 http_handler = MockHTTPHandler(
1253 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001254 opener.add_handler(basic_handler)
1255 opener.add_handler(digest_handler)
1256 opener.add_handler(http_handler)
1257
1258 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001259 self._test_basic_auth(opener, basic_handler, "Authorization",
1260 realm, http_handler, password_manager,
1261 "http://acme.example.com/protected",
1262 "http://acme.example.com/protected",
1263 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001264 # check digest was tried before basic (twice, because
1265 # _test_basic_auth called .open() twice)
1266 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001267
1268 def _test_basic_auth(self, opener, auth_handler, auth_header,
1269 realm, http_handler, password_manager,
1270 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001271 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001272 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001273
1274 # .add_password() fed through to password manager
1275 auth_handler.add_password(realm, request_url, user, password)
1276 self.assertEqual(realm, password_manager.realm)
1277 self.assertEqual(request_url, password_manager.url)
1278 self.assertEqual(user, password_manager.user)
1279 self.assertEqual(password, password_manager.password)
1280
1281 r = opener.open(request_url)
1282
1283 # should have asked the password manager for the username/password
1284 self.assertEqual(password_manager.target_realm, realm)
1285 self.assertEqual(password_manager.target_url, protected_url)
1286
1287 # expect one request without authorization, then one with
1288 self.assertEqual(len(http_handler.requests), 2)
1289 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001290 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001291 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001292 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001293 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1294 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001295 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1296 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001297 # if the password manager can't find a password, the handler won't
1298 # handle the HTTP auth error
1299 password_manager.user = password_manager.password = None
1300 http_handler.reset()
1301 r = opener.open(request_url)
1302 self.assertEqual(len(http_handler.requests), 1)
1303 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1304
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001305class MiscTests(unittest.TestCase):
1306
1307 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001308 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1309 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001310 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001311 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001312 def bar_open(self): pass
1313
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001314 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001315
1316 o = build_opener(FooHandler, BarHandler)
1317 self.opener_has_handler(o, FooHandler)
1318 self.opener_has_handler(o, BarHandler)
1319
1320 # can take a mix of classes and instances
1321 o = build_opener(FooHandler, BarHandler())
1322 self.opener_has_handler(o, FooHandler)
1323 self.opener_has_handler(o, BarHandler)
1324
1325 # subclasses of default handlers override default handlers
1326 o = build_opener(MyHTTPHandler)
1327 self.opener_has_handler(o, MyHTTPHandler)
1328
1329 # a particular case of overriding: default handlers can be passed
1330 # in explicitly
1331 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001332 self.opener_has_handler(o, urllib.request.HTTPHandler)
1333 o = build_opener(urllib.request.HTTPHandler)
1334 self.opener_has_handler(o, urllib.request.HTTPHandler)
1335 o = build_opener(urllib.request.HTTPHandler())
1336 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001337
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001338 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001339 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001340 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1341 self.opener_has_handler(o, MyHTTPHandler)
1342 self.opener_has_handler(o, MyOtherHTTPHandler)
1343
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001344 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001345 self.assertTrue(any(h.__class__ == handler_class
1346 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001347
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001348class RequestTests(unittest.TestCase):
1349
1350 def setUp(self):
1351 self.get = Request("http://www.python.org/~jeremy/")
1352 self.post = Request("http://www.python.org/~jeremy/",
1353 "data",
1354 headers={"X-Test": "test"})
1355
1356 def test_method(self):
1357 self.assertEqual("POST", self.post.get_method())
1358 self.assertEqual("GET", self.get.get_method())
1359
1360 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001361 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001362 self.assertEqual("GET", self.get.get_method())
1363 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001364 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001365 self.assertEqual("POST", self.get.get_method())
1366
1367 def test_get_full_url(self):
1368 self.assertEqual("http://www.python.org/~jeremy/",
1369 self.get.get_full_url())
1370
1371 def test_selector(self):
1372 self.assertEqual("/~jeremy/", self.get.get_selector())
1373 req = Request("http://www.python.org/")
1374 self.assertEqual("/", req.get_selector())
1375
1376 def test_get_type(self):
1377 self.assertEqual("http", self.get.get_type())
1378
1379 def test_get_host(self):
1380 self.assertEqual("www.python.org", self.get.get_host())
1381
1382 def test_get_host_unquote(self):
1383 req = Request("http://www.%70ython.org/")
1384 self.assertEqual("www.python.org", req.get_host())
1385
1386 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001387 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001388 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001389 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001390 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1391 self.assertEqual("www.perl.org", self.get.get_host())
1392
Senthil Kumarand95cc752010-08-08 11:27:53 +00001393 def test_wrapped_url(self):
1394 req = Request("<URL:http://www.python.org>")
1395 self.assertEqual("www.python.org", req.get_host())
1396
Senthil Kumaran26430412011-04-13 07:01:19 +08001397 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001398 req = Request("http://www.python.org/?qs=query#fragment=true")
1399 self.assertEqual("/?qs=query", req.get_selector())
1400 req = Request("http://www.python.org/#fun=true")
1401 self.assertEqual("/", req.get_selector())
1402
Senthil Kumaran26430412011-04-13 07:01:19 +08001403 # Issue 11703: geturl() omits fragment in the original URL.
1404 url = 'http://docs.python.org/library/urllib2.html#OK'
1405 req = Request(url)
1406 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001407
1408def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001409 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001410 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001411 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001412 tests = (TrivialTests,
1413 OpenerDirectorTests,
1414 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001415 MiscTests,
1416 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001417 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001418
1419if __name__ == "__main__":
1420 test_main(verbose=True)