blob: e55140e1d83142cd3dba0e09a32d2e2274471d73 [file] [log] [blame]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00003
Christian Heimes05e8be12008-02-23 18:30:17 +00004import os
Guido van Rossum34d19282007-08-09 01:03:29 +00005import io
Georg Brandlf78e02b2008-06-10 17:40:04 +00006import socket
Senthil Kumaran7bc0d872010-12-19 10:49:52 +00007import array
Senthil Kumaran4de00a22011-05-11 21:17:57 +08008import sys
Jeremy Hyltone3e61042001-05-09 15:50:25 +00009
Jeremy Hylton1afc1692008-06-18 20:49:58 +000010import urllib.request
Ronald Oussorene72e1612011-03-14 18:15:25 -040011# The proxy bypass method imported below has logic specific to the OSX
12# proxy config data structure but is testable on all platforms.
13from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
guido@google.coma119df92011-03-29 11:41:02 -070014import urllib.error
Jeremy Hyltone3e61042001-05-09 15:50:25 +000015
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000016# XXX
17# Request
18# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000019# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000020
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000021class TrivialTests(unittest.TestCase):
Senthil Kumaran6c5bd402011-11-01 23:20:31 +080022
23 def test___all__(self):
24 # Verify which names are exposed
25 for module in 'request', 'response', 'parse', 'error', 'robotparser':
26 context = {}
27 exec('from urllib.%s import *' % module, context)
28 del context['__builtins__']
29 for k, v in context.items():
30 self.assertEqual(v.__module__, 'urllib.%s' % module,
31 "%r is exposed in 'urllib.%s' but defined in %r" %
32 (k, module, v.__module__))
33
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000034 def test_trivial(self):
35 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000036
Jeremy Hylton1afc1692008-06-18 20:49:58 +000037 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000038
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000039 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000040 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000041
Senthil Kumarand587e302010-01-10 17:45:52 +000042 if os.name == 'nt':
43 file_url = "file:///%s" % fname
44 else:
45 file_url = "file://%s" % fname
46
Jeremy Hylton1afc1692008-06-18 20:49:58 +000047 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000048
49 buf = f.read()
50 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000051
Georg Brandle1b13d22005-08-24 22:20:32 +000052 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000053 tests = [
54 ('a,b,c', ['a', 'b', 'c']),
55 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
56 ('a, b, "c", "d", "e,f", g, h',
57 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
58 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
59 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000060 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000061 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000062
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000063
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000064def test_request_headers_dict():
65 """
66 The Request.headers dictionary is not a documented interface. It should
67 stay that way, because the complete set of headers are only accessible
68 through the .get_header(), .has_header(), .header_items() interface.
69 However, .headers pre-dates those methods, and so real code will be using
70 the dictionary.
71
72 The introduction in 2.4 of those methods was a mistake for the same reason:
73 code that previously saw all (urllib2 user)-provided headers in .headers
74 now sees only a subset (and the function interface is ugly and incomplete).
75 A better change would have been to replace .headers dict with a dict
76 subclass (or UserDict.DictMixin instance?) that preserved the .headers
77 interface and also provided access to the "unredirected" headers. It's
78 probably too late to fix that, though.
79
80
81 Check .capitalize() case normalization:
82
83 >>> url = "http://example.com"
84 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
85 'blah'
86 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
87 'blah'
88
89 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
90 but that could be changed in future.
91
92 """
93
94def test_request_headers_methods():
95 """
96 Note the case normalization of header names here, to .capitalize()-case.
97 This should be preserved for backwards-compatibility. (In the HTTP case,
98 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000099 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000100
101 >>> url = "http://example.com"
102 >>> r = Request(url, headers={"Spam-eggs": "blah"})
103 >>> r.has_header("Spam-eggs")
104 True
105 >>> r.header_items()
106 [('Spam-eggs', 'blah')]
107 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000108 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000109 >>> items
110 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
111
112 Note that e.g. r.has_header("spam-EggS") is currently False, and
113 r.get_header("spam-EggS") returns None, but that could be changed in
114 future.
115
116 >>> r.has_header("Not-there")
117 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000118 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000119 None
120 >>> r.get_header("Not-there", "default")
121 'default'
122
123 """
124
125
Thomas Wouters477c8d52006-05-27 19:21:47 +0000126def test_password_manager(self):
127 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000128 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000129 >>> add = mgr.add_password
130 >>> add("Some Realm", "http://example.com/", "joe", "password")
131 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
132 >>> add("c", "http://example.com/foo", "foo", "ni")
133 >>> add("c", "http://example.com/bar", "bar", "nini")
134 >>> add("b", "http://example.com/", "first", "blah")
135 >>> add("b", "http://example.com/", "second", "spam")
136 >>> add("a", "http://example.com", "1", "a")
137 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
138 >>> add("Some Realm", "d.example.com", "4", "d")
139 >>> add("Some Realm", "e.example.com:3128", "5", "e")
140
141 >>> mgr.find_user_password("Some Realm", "example.com")
142 ('joe', 'password')
143 >>> mgr.find_user_password("Some Realm", "http://example.com")
144 ('joe', 'password')
145 >>> mgr.find_user_password("Some Realm", "http://example.com/")
146 ('joe', 'password')
147 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
148 ('joe', 'password')
149 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
150 ('joe', 'password')
151 >>> mgr.find_user_password("c", "http://example.com/foo")
152 ('foo', 'ni')
153 >>> mgr.find_user_password("c", "http://example.com/bar")
154 ('bar', 'nini')
155
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000156 Actually, this is really undefined ATM
157## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000158
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000159## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
160## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000161
162 Use latest add_password() in case of conflict:
163
164 >>> mgr.find_user_password("b", "http://example.com/")
165 ('second', 'spam')
166
167 No special relationship between a.example.com and example.com:
168
169 >>> mgr.find_user_password("a", "http://example.com/")
170 ('1', 'a')
171 >>> mgr.find_user_password("a", "http://a.example.com/")
172 (None, None)
173
174 Ports:
175
176 >>> mgr.find_user_password("Some Realm", "c.example.com")
177 (None, None)
178 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
179 ('3', 'c')
180 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
181 ('3', 'c')
182 >>> mgr.find_user_password("Some Realm", "d.example.com")
183 ('4', 'd')
184 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
185 ('5', 'e')
186
187 """
188 pass
189
190
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000191def test_password_manager_default_port(self):
192 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000193 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000194 >>> add = mgr.add_password
195
196 The point to note here is that we can't guess the default port if there's
197 no scheme. This applies to both add_password and find_user_password.
198
199 >>> add("f", "http://g.example.com:80", "10", "j")
200 >>> add("g", "http://h.example.com", "11", "k")
201 >>> add("h", "i.example.com:80", "12", "l")
202 >>> add("i", "j.example.com", "13", "m")
203 >>> mgr.find_user_password("f", "g.example.com:100")
204 (None, None)
205 >>> mgr.find_user_password("f", "g.example.com:80")
206 ('10', 'j')
207 >>> mgr.find_user_password("f", "g.example.com")
208 (None, None)
209 >>> mgr.find_user_password("f", "http://g.example.com:100")
210 (None, None)
211 >>> mgr.find_user_password("f", "http://g.example.com:80")
212 ('10', 'j')
213 >>> mgr.find_user_password("f", "http://g.example.com")
214 ('10', 'j')
215 >>> mgr.find_user_password("g", "h.example.com")
216 ('11', 'k')
217 >>> mgr.find_user_password("g", "h.example.com:80")
218 ('11', 'k')
219 >>> mgr.find_user_password("g", "http://h.example.com:80")
220 ('11', 'k')
221 >>> mgr.find_user_password("h", "i.example.com")
222 (None, None)
223 >>> mgr.find_user_password("h", "i.example.com:80")
224 ('12', 'l')
225 >>> mgr.find_user_password("h", "http://i.example.com:80")
226 ('12', 'l')
227 >>> mgr.find_user_password("i", "j.example.com")
228 ('13', 'm')
229 >>> mgr.find_user_password("i", "j.example.com:80")
230 (None, None)
231 >>> mgr.find_user_password("i", "http://j.example.com")
232 ('13', 'm')
233 >>> mgr.find_user_password("i", "http://j.example.com:80")
234 (None, None)
235
236 """
237
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000238class MockOpener:
239 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000240 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
241 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000242 def error(self, proto, *args):
243 self.proto, self.args = proto, args
244
245class MockFile:
246 def read(self, count=None): pass
247 def readline(self, count=None): pass
248 def close(self): pass
249
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000250class MockHeaders(dict):
251 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000252 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000253
Guido van Rossum34d19282007-08-09 01:03:29 +0000254class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000255 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000256 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000257 self.code, self.msg, self.headers, self.url = code, msg, headers, url
258 def info(self):
259 return self.headers
260 def geturl(self):
261 return self.url
262
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000263class MockCookieJar:
264 def add_cookie_header(self, request):
265 self.ach_req = request
266 def extract_cookies(self, response, request):
267 self.ec_req, self.ec_r = request, response
268
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000269class FakeMethod:
270 def __init__(self, meth_name, action, handle):
271 self.meth_name = meth_name
272 self.handle = handle
273 self.action = action
274 def __call__(self, *args):
275 return self.handle(self.meth_name, self.action, *args)
276
Senthil Kumaran47fff872009-12-20 07:10:31 +0000277class MockHTTPResponse(io.IOBase):
278 def __init__(self, fp, msg, status, reason):
279 self.fp = fp
280 self.msg = msg
281 self.status = status
282 self.reason = reason
283 self.code = 200
284
285 def read(self):
286 return ''
287
288 def info(self):
289 return {}
290
291 def geturl(self):
292 return self.url
293
294
295class MockHTTPClass:
296 def __init__(self):
297 self.level = 0
298 self.req_headers = []
299 self.data = None
300 self.raise_on_endheaders = False
301 self._tunnel_headers = {}
302
303 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
304 self.host = host
305 self.timeout = timeout
306 return self
307
308 def set_debuglevel(self, level):
309 self.level = level
310
311 def set_tunnel(self, host, port=None, headers=None):
312 self._tunnel_host = host
313 self._tunnel_port = port
314 if headers:
315 self._tunnel_headers = headers
316 else:
317 self._tunnel_headers.clear()
318
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000319 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000320 self.method = method
321 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000322 if headers is not None:
323 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000324 self.req_headers.sort()
325 if body:
326 self.data = body
327 if self.raise_on_endheaders:
328 import socket
329 raise socket.error()
330 def getresponse(self):
331 return MockHTTPResponse(MockFile(), {}, 200, "OK")
332
Victor Stinnera4c45d72011-06-17 14:01:18 +0200333 def close(self):
334 pass
335
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000336class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000337 # useful for testing handler machinery
338 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000339 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000340 def __init__(self, methods):
341 self._define_methods(methods)
342 def _define_methods(self, methods):
343 for spec in methods:
344 if len(spec) == 2: name, action = spec
345 else: name, action = spec, None
346 meth = FakeMethod(name, action, self.handle)
347 setattr(self.__class__, name, meth)
348 def handle(self, fn_name, action, *args, **kwds):
349 self.parent.calls.append((self, fn_name, args, kwds))
350 if action is None:
351 return None
352 elif action == "return self":
353 return self
354 elif action == "return response":
355 res = MockResponse(200, "OK", {}, "")
356 return res
357 elif action == "return request":
358 return Request("http://blah/")
359 elif action.startswith("error"):
360 code = action[action.rfind(" ")+1:]
361 try:
362 code = int(code)
363 except ValueError:
364 pass
365 res = MockResponse(200, "OK", {}, "")
366 return self.parent.error("http", args[0], res, code, "", {})
367 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000368 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000369 assert False
370 def close(self): pass
371 def add_parent(self, parent):
372 self.parent = parent
373 self.parent.calls = []
374 def __lt__(self, other):
375 if not hasattr(other, "handler_order"):
376 # No handler_order, leave in original order. Yuck.
377 return True
378 return self.handler_order < other.handler_order
379
380def add_ordered_mock_handlers(opener, meth_spec):
381 """Create MockHandlers and add them to an OpenerDirector.
382
383 meth_spec: list of lists of tuples and strings defining methods to define
384 on handlers. eg:
385
386 [["http_error", "ftp_open"], ["http_open"]]
387
388 defines methods .http_error() and .ftp_open() on one handler, and
389 .http_open() on another. These methods just record their arguments and
390 return None. Using a tuple instead of a string causes the method to
391 perform some action (see MockHandler.handle()), eg:
392
393 [["http_error"], [("http_open", "return request")]]
394
395 defines .http_error() on one handler (which simply returns None), and
396 .http_open() on another handler, which returns a Request object.
397
398 """
399 handlers = []
400 count = 0
401 for meths in meth_spec:
402 class MockHandlerSubclass(MockHandler): pass
403 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000404 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000405 h.add_parent(opener)
406 count = count + 1
407 handlers.append(h)
408 opener.add_handler(h)
409 return handlers
410
Thomas Wouters477c8d52006-05-27 19:21:47 +0000411def build_test_opener(*handler_instances):
412 opener = OpenerDirector()
413 for h in handler_instances:
414 opener.add_handler(h)
415 return opener
416
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000417class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000418 # useful for testing redirections and auth
419 # sends supplied headers and code as first response
420 # sends 200 OK as second response
421 def __init__(self, code, headers):
422 self.code = code
423 self.headers = headers
424 self.reset()
425 def reset(self):
426 self._count = 0
427 self.requests = []
428 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000429 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000430 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000431 self.requests.append(copy.deepcopy(req))
432 if self._count == 0:
433 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000434 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000435 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000436 return self.parent.error(
437 "http", req, MockFile(), self.code, name, msg)
438 else:
439 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000440 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000441 return MockResponse(200, "OK", msg, "", req.get_full_url())
442
Senthil Kumaran47fff872009-12-20 07:10:31 +0000443class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
444 # Useful for testing the Proxy-Authorization request by verifying the
445 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000446
447 def __init__(self):
448 urllib.request.AbstractHTTPHandler.__init__(self)
449 self.httpconn = MockHTTPClass()
450
Senthil Kumaran47fff872009-12-20 07:10:31 +0000451 def https_open(self, req):
452 return self.do_open(self.httpconn, req)
453
Thomas Wouters477c8d52006-05-27 19:21:47 +0000454class MockPasswordManager:
455 def add_password(self, realm, uri, user, password):
456 self.realm = realm
457 self.url = uri
458 self.user = user
459 self.password = password
460 def find_user_password(self, realm, authuri):
461 self.target_realm = realm
462 self.target_url = authuri
463 return self.user, self.password
464
465
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000466class OpenerDirectorTests(unittest.TestCase):
467
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000468 def test_add_non_handler(self):
469 class NonHandler(object):
470 pass
471 self.assertRaises(TypeError,
472 OpenerDirector().add_handler, NonHandler())
473
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000474 def test_badly_named_methods(self):
475 # test work-around for three methods that accidentally follow the
476 # naming conventions for handler methods
477 # (*_open() / *_request() / *_response())
478
479 # These used to call the accidentally-named methods, causing a
480 # TypeError in real code; here, returning self from these mock
481 # methods would either cause no exception, or AttributeError.
482
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000483 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000484
485 o = OpenerDirector()
486 meth_spec = [
487 [("do_open", "return self"), ("proxy_open", "return self")],
488 [("redirect_request", "return self")],
489 ]
490 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000491 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000492 for scheme in "do", "proxy", "redirect":
493 self.assertRaises(URLError, o.open, scheme+"://example.com/")
494
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000495 def test_handled(self):
496 # handler returning non-None means no more handlers will be called
497 o = OpenerDirector()
498 meth_spec = [
499 ["http_open", "ftp_open", "http_error_302"],
500 ["ftp_open"],
501 [("http_open", "return self")],
502 [("http_open", "return self")],
503 ]
504 handlers = add_ordered_mock_handlers(o, meth_spec)
505
506 req = Request("http://example.com/")
507 r = o.open(req)
508 # Second .http_open() gets called, third doesn't, since second returned
509 # non-None. Handlers without .http_open() never get any methods called
510 # on them.
511 # In fact, second mock handler defining .http_open() returns self
512 # (instead of response), which becomes the OpenerDirector's return
513 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000514 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000515 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
516 for expected, got in zip(calls, o.calls):
517 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000518 self.assertEqual((handler, name), expected)
519 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000520
521 def test_handler_order(self):
522 o = OpenerDirector()
523 handlers = []
524 for meths, handler_order in [
525 ([("http_open", "return self")], 500),
526 (["http_open"], 0),
527 ]:
528 class MockHandlerSubclass(MockHandler): pass
529 h = MockHandlerSubclass(meths)
530 h.handler_order = handler_order
531 handlers.append(h)
532 o.add_handler(h)
533
534 r = o.open("http://example.com/")
535 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000536 self.assertEqual(o.calls[0][0], handlers[1])
537 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000538
539 def test_raise(self):
540 # raising URLError stops processing of request
541 o = OpenerDirector()
542 meth_spec = [
543 [("http_open", "raise")],
544 [("http_open", "return self")],
545 ]
546 handlers = add_ordered_mock_handlers(o, meth_spec)
547
548 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000549 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000550 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000551
552## def test_error(self):
553## # XXX this doesn't actually seem to be used in standard library,
554## # but should really be tested anyway...
555
556 def test_http_error(self):
557 # XXX http_error_default
558 # http errors are a special case
559 o = OpenerDirector()
560 meth_spec = [
561 [("http_open", "error 302")],
562 [("http_error_400", "raise"), "http_open"],
563 [("http_error_302", "return response"), "http_error_303",
564 "http_error"],
565 [("http_error_302")],
566 ]
567 handlers = add_ordered_mock_handlers(o, meth_spec)
568
569 class Unknown:
570 def __eq__(self, other): return True
571
572 req = Request("http://example.com/")
573 r = o.open(req)
574 assert len(o.calls) == 2
575 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000576 (handlers[2], "http_error_302",
577 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000578 for expected, got in zip(calls, o.calls):
579 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000580 self.assertEqual((handler, method_name), got[:2])
581 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000582
583 def test_processors(self):
584 # *_request / *_response methods get called appropriately
585 o = OpenerDirector()
586 meth_spec = [
587 [("http_request", "return request"),
588 ("http_response", "return response")],
589 [("http_request", "return request"),
590 ("http_response", "return response")],
591 ]
592 handlers = add_ordered_mock_handlers(o, meth_spec)
593
594 req = Request("http://example.com/")
595 r = o.open(req)
596 # processor methods are called on *all* handlers that define them,
597 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000598 calls = [
599 (handlers[0], "http_request"), (handlers[1], "http_request"),
600 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000601
602 for i, (handler, name, args, kwds) in enumerate(o.calls):
603 if i < 2:
604 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000605 self.assertEqual((handler, name), calls[i])
606 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000607 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000608 else:
609 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000610 self.assertEqual((handler, name), calls[i])
611 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000612 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000613 # response from opener.open is None, because there's no
614 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000615 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000616 isinstance(args[1], MockResponse))
617
618
Tim Peters58eb11c2004-01-18 20:29:55 +0000619def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000620 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000621 path.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000622 except UnicodeEncodeError:
623 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000624 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000625 if os.name == "nt" and urlpath.startswith("///"):
626 urlpath = urlpath[2:]
627 # XXX don't ask me about the mac...
628 return urlpath
629
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000630class HandlerTests(unittest.TestCase):
631
632 def test_ftp(self):
633 class MockFTPWrapper:
634 def __init__(self, data): self.data = data
635 def retrfile(self, filename, filetype):
636 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000637 return io.StringIO(self.data), len(self.data)
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200638 def close(self): pass
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000639
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000640 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000641 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000642 def connect_ftp(self, user, passwd, host, port, dirs,
643 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000644 self.user, self.passwd = user, passwd
645 self.host, self.port = host, port
646 self.dirs = dirs
647 self.ftpwrapper = MockFTPWrapper(self.data)
648 return self.ftpwrapper
649
Georg Brandlf78e02b2008-06-10 17:40:04 +0000650 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000651 data = "rheum rhaponicum"
652 h = NullFTPHandler(data)
653 o = h.parent = MockOpener()
654
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000655 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000656 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000657 "localhost", ftplib.FTP_PORT, "", "", "I",
658 ["foo", "bar"], "baz.html", "text/html"),
659 ("ftp://parrot@localhost/foo/bar/baz.html",
660 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
661 ["foo", "bar"], "baz.html", "text/html"),
662 ("ftp://%25parrot@localhost/foo/bar/baz.html",
663 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
664 ["foo", "bar"], "baz.html", "text/html"),
665 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
666 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000667 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000668 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000669 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000670 ["foo", "bar"], "", None),
671 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000672 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000673 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000674 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000675 req = Request(url)
676 req.timeout = None
677 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000678 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000679 self.assertEqual(h.user, user)
680 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000681 self.assertEqual(h.host, socket.gethostbyname(host))
682 self.assertEqual(h.port, port)
683 self.assertEqual(h.dirs, dirs)
684 self.assertEqual(h.ftpwrapper.filename, filename)
685 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000686 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000687 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000688 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000689
690 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000691 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000692 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000693 o = h.parent = MockOpener()
694
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000695 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000696 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000697 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000698 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000699 "file://localhost%s" % urlpath,
700 "file://%s" % urlpath,
701 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000702 ]
703 try:
704 localaddr = socket.gethostbyname(socket.gethostname())
705 except socket.gaierror:
706 localaddr = ''
707 if localaddr:
708 urls.append("file://%s%s" % (localaddr, urlpath))
709
710 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000711 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000712 try:
713 try:
714 f.write(towrite)
715 finally:
716 f.close()
717
718 r = h.file_open(Request(url))
719 try:
720 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000721 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000722 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000723 finally:
724 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000725 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000726 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000727 finally:
728 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000729 self.assertEqual(data, towrite)
730 self.assertEqual(headers["Content-type"], "text/plain")
731 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000732 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000733 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000734
735 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000736 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000737 "file:///file_does_not_exist.txt",
738 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
739 os.getcwd(), TESTFN),
740 "file://somerandomhost.ontheinternet.com%s/%s" %
741 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000742 ]:
743 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000744 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000745 try:
746 f.write(towrite)
747 finally:
748 f.close()
749
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000750 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000751 h.file_open, Request(url))
752 finally:
753 os.remove(TESTFN)
754
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000755 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000756 o = h.parent = MockOpener()
757 # XXXX why does // mean ftp (and /// mean not ftp!), and where
758 # is file: scheme specified? I think this is really a bug, and
759 # what was intended was to distinguish between URLs like:
760 # file:/blah.txt (a file)
761 # file://localhost/blah.txt (a file)
762 # file:///blah.txt (a file)
763 # file://ftp.example.com/blah.txt (an ftp URL)
764 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000765 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766 ("file://ftp.example.com///foo.txt", False),
767# XXXX bug: fails with OSError, should be URLError
768 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000769 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000770 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000771 ]:
772 req = Request(url)
773 try:
774 h.file_open(req)
775 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000776 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000777 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000778 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000779 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000780 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000781 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000782
783 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000784
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000785 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000786 o = h.parent = MockOpener()
787
788 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000789 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000790 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000791 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000792 req.add_unredirected_header("Spam", "eggs")
793 http = MockHTTPClass()
794 r = h.do_open(http, req)
795
796 # result attributes
797 r.read; r.readline # wrapped MockFile methods
798 r.info; r.geturl # addinfourl methods
799 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
800 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000801 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000802 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000803
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000804 self.assertEqual(http.host, "example.com")
805 self.assertEqual(http.level, 0)
806 self.assertEqual(http.method, method)
807 self.assertEqual(http.selector, "/")
808 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000809 [("Connection", "close"),
810 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000811 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000812
813 # check socket.error converted to URLError
814 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000815 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000816
Senthil Kumaran29333122011-02-11 11:25:47 +0000817 # Check for TypeError on POST data which is str.
818 req = Request("http://example.com/","badpost")
819 self.assertRaises(TypeError, h.do_request_, req)
820
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000821 # check adding of standard headers
822 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000823 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000824 req = Request("http://example.com/", data)
825 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000826 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000827 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000828 self.assertNotIn("Content-length", req.unredirected_hdrs)
829 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000830 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000831 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
832 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000833 "application/x-www-form-urlencoded")
834 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000835 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
836 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000837
838 # don't clobber existing headers
839 req.add_unredirected_header("Content-length", "foo")
840 req.add_unredirected_header("Content-type", "bar")
841 req.add_unredirected_header("Host", "baz")
842 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000843 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000844 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
845 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000846 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
847 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000848
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000849 # Check iterable body support
850 def iterable_body():
851 yield b"one"
852 yield b"two"
853 yield b"three"
854
855 for headers in {}, {"Content-Length": 11}:
856 req = Request("http://example.com/", iterable_body(), headers)
857 if not headers:
858 # Having an iterable body without a Content-Length should
859 # raise an exception
860 self.assertRaises(ValueError, h.do_request_, req)
861 else:
862 newreq = h.do_request_(req)
863
Senthil Kumaran29333122011-02-11 11:25:47 +0000864 # A file object.
865 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000866
Senthil Kumaran29333122011-02-11 11:25:47 +0000867 file_obj = io.BytesIO()
868 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000869
870 for headers in {}, {"Content-Length": 30}:
871 req = Request("http://example.com/", file_obj, headers)
872 if not headers:
873 # Having an iterable body without a Content-Length should
874 # raise an exception
875 self.assertRaises(ValueError, h.do_request_, req)
876 else:
877 newreq = h.do_request_(req)
878 self.assertEqual(int(newreq.get_header('Content-length')),30)
879
880 file_obj.close()
881
882 # array.array Iterable - Content Length is calculated
883
884 iterable_array = array.array("I",[1,2,3,4])
885
886 for headers in {}, {"Content-Length": 16}:
887 req = Request("http://example.com/", iterable_array, headers)
888 newreq = h.do_request_(req)
889 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000890
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000891 def test_http_doubleslash(self):
892 # Checks the presence of any unnecessary double slash in url does not
893 # break anything. Previously, a double slash directly after the host
Ezio Melottie130a522011-10-19 10:58:56 +0300894 # could cause incorrect parsing.
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000895 h = urllib.request.AbstractHTTPHandler()
896 o = h.parent = MockOpener()
897
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000898 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000899 ds_urls = [
900 "http://example.com/foo/bar/baz.html",
901 "http://example.com//foo/bar/baz.html",
902 "http://example.com/foo//bar/baz.html",
903 "http://example.com/foo/bar//baz.html"
904 ]
905
906 for ds_url in ds_urls:
907 ds_req = Request(ds_url, data)
908
909 # Check whether host is determined correctly if there is no proxy
910 np_ds_req = h.do_request_(ds_req)
911 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
912
913 # Check whether host is determined correctly if there is a proxy
914 ds_req.set_proxy("someproxy:3128",None)
915 p_ds_req = h.do_request_(ds_req)
916 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
917
Senthil Kumaranc2958622010-11-22 04:48:26 +0000918 def test_fixpath_in_weirdurls(self):
919 # Issue4493: urllib2 to supply '/' when to urls where path does not
920 # start with'/'
921
922 h = urllib.request.AbstractHTTPHandler()
923 o = h.parent = MockOpener()
924
925 weird_url = 'http://www.python.org?getspam'
926 req = Request(weird_url)
927 newreq = h.do_request_(req)
928 self.assertEqual(newreq.host,'www.python.org')
929 self.assertEqual(newreq.selector,'/?getspam')
930
931 url_without_path = 'http://www.python.org'
932 req = Request(url_without_path)
933 newreq = h.do_request_(req)
934 self.assertEqual(newreq.host,'www.python.org')
935 self.assertEqual(newreq.selector,'')
936
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000937
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000938 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000939 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000940 o = h.parent = MockOpener()
941
942 url = "http://example.com/"
943 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000944 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000945 r = MockResponse(200, "OK", {}, "", url)
946 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000947 self.assertIs(r, newr)
948 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000949 r = MockResponse(202, "Accepted", {}, "", url)
950 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000951 self.assertIs(r, newr)
952 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000953 r = MockResponse(206, "Partial content", {}, "", url)
954 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000955 self.assertIs(r, newr)
956 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000957 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000958 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000959 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000960 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000961 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000962
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000963 def test_cookies(self):
964 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000965 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000966 o = h.parent = MockOpener()
967
968 req = Request("http://example.com/")
969 r = MockResponse(200, "OK", {}, "")
970 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000971 self.assertIs(cj.ach_req, req)
972 self.assertIs(cj.ach_req, newreq)
973 self.assertEqual(req.get_origin_req_host(), "example.com")
974 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000975 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000976 self.assertIs(cj.ec_req, req)
977 self.assertIs(cj.ec_r, r)
978 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000979
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000980 def test_redirect(self):
981 from_url = "http://example.com/a.html"
982 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000983 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000984 o = h.parent = MockOpener()
985
986 # ordinary redirect behaviour
987 for code in 301, 302, 303, 307:
988 for data in None, "blah\nblah\n":
989 method = getattr(h, "http_error_%s" % code)
990 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000991 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000992 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000993 if data is not None:
994 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000995 req.add_unredirected_header("Spam", "spam")
996 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000997 method(req, MockFile(), code, "Blah",
998 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000999 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001000 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001001 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001002 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001003 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001004 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001005 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +00001006 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +00001007
1008 # now it's a GET, there should not be headers regarding content
1009 # (possibly dragged from before being a POST)
1010 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +00001011 self.assertNotIn("content-length", headers)
1012 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001013
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001014 self.assertEqual(o.req.headers["Nonsense"],
1015 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001016 self.assertNotIn("Spam", o.req.headers)
1017 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001018
1019 # loop detection
1020 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001021 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001022 def redirect(h, req, url=to_url):
1023 h.http_error_302(req, MockFile(), 302, "Blah",
1024 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001025 # Note that the *original* request shares the same record of
1026 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001027
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001028 # detect infinite loop redirect of a URL to itself
1029 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001030 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001031 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001032 try:
1033 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001034 redirect(h, req, "http://example.com/")
1035 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001036 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001037 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001038 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001039
1040 # detect endless non-repeating chain of redirects
1041 req = Request(from_url, origin_req_host="example.com")
1042 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001043 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001044 try:
1045 while 1:
1046 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001047 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001048 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001049 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001050 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001051
guido@google.coma119df92011-03-29 11:41:02 -07001052
1053 def test_invalid_redirect(self):
1054 from_url = "http://example.com/a.html"
1055 valid_schemes = ['http','https','ftp']
1056 invalid_schemes = ['file','imap','ldap']
1057 schemeless_url = "example.com/b.html"
1058 h = urllib.request.HTTPRedirectHandler()
1059 o = h.parent = MockOpener()
1060 req = Request(from_url)
1061 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1062
1063 for scheme in invalid_schemes:
1064 invalid_url = scheme + '://' + schemeless_url
1065 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1066 req, MockFile(), 302, "Security Loophole",
1067 MockHeaders({"location": invalid_url}))
1068
1069 for scheme in valid_schemes:
1070 valid_url = scheme + '://' + schemeless_url
1071 h.http_error_302(req, MockFile(), 302, "That's fine",
1072 MockHeaders({"location": valid_url}))
1073 self.assertEqual(o.req.get_full_url(), valid_url)
1074
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001075 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001076 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001077 from http.cookiejar import CookieJar
1078 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001079
1080 cj = CookieJar()
1081 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001082 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001083 hdeh = urllib.request.HTTPDefaultErrorHandler()
1084 hrh = urllib.request.HTTPRedirectHandler()
1085 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001086 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001087 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001088 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001089
Senthil Kumaran26430412011-04-13 07:01:19 +08001090 def test_redirect_fragment(self):
1091 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1092 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1093 hdeh = urllib.request.HTTPDefaultErrorHandler()
1094 hrh = urllib.request.HTTPRedirectHandler()
1095 o = build_test_opener(hh, hdeh, hrh)
1096 fp = o.open('http://www.example.com')
1097 self.assertEqual(fp.geturl(), redirected_url.strip())
1098
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001099 def test_proxy(self):
1100 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001101 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001102 o.add_handler(ph)
1103 meth_spec = [
1104 [("http_open", "return response")]
1105 ]
1106 handlers = add_ordered_mock_handlers(o, meth_spec)
1107
1108 req = Request("http://acme.example.com/")
1109 self.assertEqual(req.get_host(), "acme.example.com")
1110 r = o.open(req)
1111 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1112
1113 self.assertEqual([(handlers[0], "http_open")],
1114 [tup[0:2] for tup in o.calls])
1115
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001116 def test_proxy_no_proxy(self):
1117 os.environ['no_proxy'] = 'python.org'
1118 o = OpenerDirector()
1119 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1120 o.add_handler(ph)
1121 req = Request("http://www.perl.org/")
1122 self.assertEqual(req.get_host(), "www.perl.org")
1123 r = o.open(req)
1124 self.assertEqual(req.get_host(), "proxy.example.com")
1125 req = Request("http://www.python.org")
1126 self.assertEqual(req.get_host(), "www.python.org")
1127 r = o.open(req)
1128 self.assertEqual(req.get_host(), "www.python.org")
1129 del os.environ['no_proxy']
1130
Ronald Oussorene72e1612011-03-14 18:15:25 -04001131 def test_proxy_no_proxy_all(self):
1132 os.environ['no_proxy'] = '*'
1133 o = OpenerDirector()
1134 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1135 o.add_handler(ph)
1136 req = Request("http://www.python.org")
1137 self.assertEqual(req.get_host(), "www.python.org")
1138 r = o.open(req)
1139 self.assertEqual(req.get_host(), "www.python.org")
1140 del os.environ['no_proxy']
1141
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001142
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001143 def test_proxy_https(self):
1144 o = OpenerDirector()
1145 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1146 o.add_handler(ph)
1147 meth_spec = [
1148 [("https_open", "return response")]
1149 ]
1150 handlers = add_ordered_mock_handlers(o, meth_spec)
1151
1152 req = Request("https://www.example.com/")
1153 self.assertEqual(req.get_host(), "www.example.com")
1154 r = o.open(req)
1155 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1156 self.assertEqual([(handlers[0], "https_open")],
1157 [tup[0:2] for tup in o.calls])
1158
Senthil Kumaran47fff872009-12-20 07:10:31 +00001159 def test_proxy_https_proxy_authorization(self):
1160 o = OpenerDirector()
1161 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1162 o.add_handler(ph)
1163 https_handler = MockHTTPSHandler()
1164 o.add_handler(https_handler)
1165 req = Request("https://www.example.com/")
1166 req.add_header("Proxy-Authorization","FooBar")
1167 req.add_header("User-Agent","Grail")
1168 self.assertEqual(req.get_host(), "www.example.com")
1169 self.assertIsNone(req._tunnel_host)
1170 r = o.open(req)
1171 # Verify Proxy-Authorization gets tunneled to request.
1172 # httpsconn req_headers do not have the Proxy-Authorization header but
1173 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001174 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001175 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001176 self.assertIn(("User-Agent","Grail"),
1177 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001178 self.assertIsNotNone(req._tunnel_host)
1179 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1180 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001181
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001182 # TODO: This should be only for OSX
1183 @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001184 def test_osx_proxy_bypass(self):
1185 bypass = {
1186 'exclude_simple': False,
1187 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1188 '10.0/16']
1189 }
1190 # Check hosts that should trigger the proxy bypass
1191 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1192 '10.0.0.1'):
1193 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1194 'expected bypass of %s to be True' % host)
1195 # Check hosts that should not trigger the proxy bypass
1196 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1197 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1198 'expected bypass of %s to be False' % host)
1199
1200 # Check the exclude_simple flag
1201 bypass = {'exclude_simple': True, 'exceptions': []}
1202 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1203
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001204 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001205 opener = OpenerDirector()
1206 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001207 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001208 realm = "ACME Widget Store"
1209 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001210 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1211 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001212 opener.add_handler(auth_handler)
1213 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001214 self._test_basic_auth(opener, auth_handler, "Authorization",
1215 realm, http_handler, password_manager,
1216 "http://acme.example.com/protected",
1217 "http://acme.example.com/protected",
1218 )
1219
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001220 def test_basic_auth_with_single_quoted_realm(self):
1221 self.test_basic_auth(quote_char="'")
1222
Thomas Wouters477c8d52006-05-27 19:21:47 +00001223 def test_proxy_basic_auth(self):
1224 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001225 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001226 opener.add_handler(ph)
1227 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001228 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001229 realm = "ACME Networks"
1230 http_handler = MockHTTPHandler(
1231 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001232 opener.add_handler(auth_handler)
1233 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001234 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001235 realm, http_handler, password_manager,
1236 "http://acme.example.com:3128/protected",
1237 "proxy.example.com:3128",
1238 )
1239
1240 def test_basic_and_digest_auth_handlers(self):
1241 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1242 # response (http://python.org/sf/1479302), where it should instead
1243 # return None to allow another handler (especially
1244 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001245
1246 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1247 # try digest first (since it's the strongest auth scheme), so we record
1248 # order of calls here to check digest comes first:
1249 class RecordingOpenerDirector(OpenerDirector):
1250 def __init__(self):
1251 OpenerDirector.__init__(self)
1252 self.recorded = []
1253 def record(self, info):
1254 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001255 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001256 def http_error_401(self, *args, **kwds):
1257 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001258 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001259 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001260 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001261 def http_error_401(self, *args, **kwds):
1262 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001263 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001264 *args, **kwds)
1265
1266 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001267 password_manager = MockPasswordManager()
1268 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001269 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001270 realm = "ACME Networks"
1271 http_handler = MockHTTPHandler(
1272 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001273 opener.add_handler(basic_handler)
1274 opener.add_handler(digest_handler)
1275 opener.add_handler(http_handler)
1276
1277 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001278 self._test_basic_auth(opener, basic_handler, "Authorization",
1279 realm, http_handler, password_manager,
1280 "http://acme.example.com/protected",
1281 "http://acme.example.com/protected",
1282 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001283 # check digest was tried before basic (twice, because
1284 # _test_basic_auth called .open() twice)
1285 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001286
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001287 def test_unsupported_auth_digest_handler(self):
1288 opener = OpenerDirector()
1289 # While using DigestAuthHandler
1290 digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
1291 http_handler = MockHTTPHandler(
1292 401, 'WWW-Authenticate: Kerberos\r\n\r\n')
1293 opener.add_handler(digest_auth_handler)
1294 opener.add_handler(http_handler)
1295 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1296
1297 def test_unsupported_auth_basic_handler(self):
1298 # While using BasicAuthHandler
1299 opener = OpenerDirector()
1300 basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
1301 http_handler = MockHTTPHandler(
1302 401, 'WWW-Authenticate: NTLM\r\n\r\n')
1303 opener.add_handler(basic_auth_handler)
1304 opener.add_handler(http_handler)
1305 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1306
Thomas Wouters477c8d52006-05-27 19:21:47 +00001307 def _test_basic_auth(self, opener, auth_handler, auth_header,
1308 realm, http_handler, password_manager,
1309 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001310 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001311 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001312
1313 # .add_password() fed through to password manager
1314 auth_handler.add_password(realm, request_url, user, password)
1315 self.assertEqual(realm, password_manager.realm)
1316 self.assertEqual(request_url, password_manager.url)
1317 self.assertEqual(user, password_manager.user)
1318 self.assertEqual(password, password_manager.password)
1319
1320 r = opener.open(request_url)
1321
1322 # should have asked the password manager for the username/password
1323 self.assertEqual(password_manager.target_realm, realm)
1324 self.assertEqual(password_manager.target_url, protected_url)
1325
1326 # expect one request without authorization, then one with
1327 self.assertEqual(len(http_handler.requests), 2)
1328 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001329 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001330 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001331 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001332 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1333 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001334 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1335 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001336 # if the password manager can't find a password, the handler won't
1337 # handle the HTTP auth error
1338 password_manager.user = password_manager.password = None
1339 http_handler.reset()
1340 r = opener.open(request_url)
1341 self.assertEqual(len(http_handler.requests), 1)
1342 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1343
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001344
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001345class MiscTests(unittest.TestCase):
1346
1347 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001348 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1349 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001350 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001351 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001352 def bar_open(self): pass
1353
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001354 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001355
1356 o = build_opener(FooHandler, BarHandler)
1357 self.opener_has_handler(o, FooHandler)
1358 self.opener_has_handler(o, BarHandler)
1359
1360 # can take a mix of classes and instances
1361 o = build_opener(FooHandler, BarHandler())
1362 self.opener_has_handler(o, FooHandler)
1363 self.opener_has_handler(o, BarHandler)
1364
1365 # subclasses of default handlers override default handlers
1366 o = build_opener(MyHTTPHandler)
1367 self.opener_has_handler(o, MyHTTPHandler)
1368
1369 # a particular case of overriding: default handlers can be passed
1370 # in explicitly
1371 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001372 self.opener_has_handler(o, urllib.request.HTTPHandler)
1373 o = build_opener(urllib.request.HTTPHandler)
1374 self.opener_has_handler(o, urllib.request.HTTPHandler)
1375 o = build_opener(urllib.request.HTTPHandler())
1376 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001377
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001378 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001379 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001380 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1381 self.opener_has_handler(o, MyHTTPHandler)
1382 self.opener_has_handler(o, MyOtherHTTPHandler)
1383
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001384 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001385 self.assertTrue(any(h.__class__ == handler_class
1386 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001387
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001388class RequestTests(unittest.TestCase):
1389
1390 def setUp(self):
1391 self.get = Request("http://www.python.org/~jeremy/")
1392 self.post = Request("http://www.python.org/~jeremy/",
1393 "data",
1394 headers={"X-Test": "test"})
1395
1396 def test_method(self):
1397 self.assertEqual("POST", self.post.get_method())
1398 self.assertEqual("GET", self.get.get_method())
1399
1400 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001401 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001402 self.assertEqual("GET", self.get.get_method())
1403 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001404 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001405 self.assertEqual("POST", self.get.get_method())
1406
1407 def test_get_full_url(self):
1408 self.assertEqual("http://www.python.org/~jeremy/",
1409 self.get.get_full_url())
1410
1411 def test_selector(self):
1412 self.assertEqual("/~jeremy/", self.get.get_selector())
1413 req = Request("http://www.python.org/")
1414 self.assertEqual("/", req.get_selector())
1415
1416 def test_get_type(self):
1417 self.assertEqual("http", self.get.get_type())
1418
1419 def test_get_host(self):
1420 self.assertEqual("www.python.org", self.get.get_host())
1421
1422 def test_get_host_unquote(self):
1423 req = Request("http://www.%70ython.org/")
1424 self.assertEqual("www.python.org", req.get_host())
1425
1426 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001427 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001428 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001429 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001430 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1431 self.assertEqual("www.perl.org", self.get.get_host())
1432
Senthil Kumarand95cc752010-08-08 11:27:53 +00001433 def test_wrapped_url(self):
1434 req = Request("<URL:http://www.python.org>")
1435 self.assertEqual("www.python.org", req.get_host())
1436
Senthil Kumaran26430412011-04-13 07:01:19 +08001437 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001438 req = Request("http://www.python.org/?qs=query#fragment=true")
1439 self.assertEqual("/?qs=query", req.get_selector())
1440 req = Request("http://www.python.org/#fun=true")
1441 self.assertEqual("/", req.get_selector())
1442
Senthil Kumaran26430412011-04-13 07:01:19 +08001443 # Issue 11703: geturl() omits fragment in the original URL.
1444 url = 'http://docs.python.org/library/urllib2.html#OK'
1445 req = Request(url)
1446 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001447
1448def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001449 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001450 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001451 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001452 tests = (TrivialTests,
1453 OpenerDirectorTests,
1454 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001455 MiscTests,
1456 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001457 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001458
1459if __name__ == "__main__":
1460 test_main(verbose=True)